diff --git a/.gitignore b/.gitignore index cf34ac8aadac498e894176d70c9a9c87d494f982..5c9f0e4f34b396f43ff39d408b38efd2704e17af 100644 --- a/.gitignore +++ b/.gitignore @@ -1,55 +1,57 @@ -*.swp -*.nfs -CMakeFiles -*Makefile* -tags -build*/ -Info.plist -obj -.DS_Store -*.log -*~ -*~.skp -bin/*.exe -bin/*.txt -bin/mac -*pro.user* -qrc_*.cpp -*.Debug -*.Release -tmp -debug -release -qgroundcontrol -mavlinkgen-build-desktop -qgroundcontrol.xcodeproj/** -doc/html -doc/doxy.log -deploy/mac -deploy/linux -deploy/qgroundcontrol* -controller_log* -user_config.pri -*.app -*.ncb -*.vcproj -*.vcxproj* -*.sdf -*.ipch -*.pdb -*.sln -*.sln -*.vcproj -*.user -*.ncb -*.idb -*.project -*.cproject -*.sln -*.suo -*.uhf.txt -*.opensdf - -thirdParty/qserialport-build-desktop/ -thirdParty/qserialport/bin/ -thirdParty/qserialport/lib/ +*.swp +*.nfs +CMakeFiles +*Makefile* +tags +build*/ +Info.plist +obj +.DS_Store +*.log +*~ +*~.skp +bin/*.exe +bin/*.txt +bin/mac +*pro.user* +qrc_*.cpp +*.Debug +*.Release +tmp +debug +release +/qgroundcontrol +mavlinkgen-build-desktop +qgroundcontrol.xcodeproj/** +doc/html +doc/doxy.log +deploy/mac +deploy/linux +deploy/qgroundcontrol* +controller_log* +user_config.pri +*.app +*.ncb +*.vcproj +*.vcxproj* +*.sdf +*.ipch +*.pdb +*.sln +*.sln +*.vcproj +*.user +*.ncb +*.idb +*.project +*.cproject +*.sln +*.suo +*.uhf.txt +*.opensdf +thirdParty/qserialport-build-desktop/ +thirdParty/qserialport/bin/ +thirdParty/qserialport/lib/ +GeneratedFiles/ + +*.autosave diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000000000000000000000000000000000..3f0d4baa875cd82c4931d3c36aa90a71cfa91612 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "qupgrade"] + path = qupgrade + url = https://github.com/LorenzMeier/qupgrade.git diff --git a/Custom-Info.plist b/Custom-Info.plist new file mode 100644 index 0000000000000000000000000000000000000000..89cae30f60338c389286383ed5651b31748681a0 --- /dev/null +++ b/Custom-Info.plist @@ -0,0 +1,24 @@ + + + + + NSPrincipalClass + NSApplication + CFBundleIconFile + macx.icns + CFBundlePackageType + APPL + CFBundleVersion + 227 + CFBundleShortVersionString + 2.0.0 + CFBundleSignature + ???? + CFBundleExecutable + @EXECUTABLE@ + CFBundleIdentifier + org.qgroundcontrol.qgroundcontrol + NOTE + Open source ground control app provided by QGroundControl dev team + + diff --git a/README b/README deleted file mode 100644 index 1d08b8244e01e58d383ec5959c5a6b5f85cddd2b..0000000000000000000000000000000000000000 --- a/README +++ /dev/null @@ -1,173 +0,0 @@ -maah -QGroundControl Open Source Micro Air Vehicle Ground Control Station - -Project: -http://qgroundcontrol.org - -Files: -http://github.com/mavlink/qgroundcontrol - -Credits: -http://qgroundcontrol.org/credits - - -Documentation -============= -For generating documentation, refer to README in the doc directory. - - -Mac OS X -======== - -To build on Mac OS X (10.6 or later): - -Install SDL ------------ -1) Download SDL from: - -2) From the SDL disk image, copy the `sdl.framework` bundle to `/Library/Frameworks` directory (if you are not an admin copy to `~/Library/Framewroks`) - -Install QT ------------ -1) Download Qt 4.8+ - -2) Double click the package installer - -Build QGroundControl --------------------- -1) From the terminal go to the `groundcontrol` directory - -2) Run `qmake -spec macx-g++` - -3) Run `make -j8` - - -Linux -===== - - -To build on Linux: - -sudo apt-get install phonon libqt4-dev \ - libphonon-dev libphonon4 phonon-backend-gstreamer \ - qtcreator libsdl1.2-dev libflite1 flite1-dev build-essential \ - libopenscenegraph-dev - -cd directory - -git clone https://github.com/mavlink/qgroundcontrol.git - -go to libs/thirdParty -> libxbee - -Create Library -> Readme file in folder - -Ubuntu Application Menu -> Development -> Qt Creator - -QtCreator Menu File -> Open File or Project.. - -Open directory/qgroundcontrol/qgroundcontrol.pro - -Hit the green play button to compile and launch it - -Done. - - -Windows -======= - -GNU GCC / MINGW IS UNTESTED, COULD WORK -VISUAL STUDIO 2008 / 2010 EXPRESS EDITION IS FREE! - -Steps for Visual Studio 2008 / 2010: - -Windows XP/7: - -1) Download and install the Qt libraries for Windows from https://qt.nokia.com/downloads/ (the Visual Studio 2008 or 2010 version as appropriate) - -2) Download and install Visual Studio 2008 or 2010 Express Edition (free) from https://www.microsoft.com/visualstudio. If using Visual Studio 2010, make sure you are running at least SP1. There is a linking error you'll encounter otherwise that will prevent compilation. - -3) Go to the QGroundControl folder and then to thirdParty/libxbee and build it following the instructions in win32.README - -4) Open the Qt Command Prompt program (should be in the Start Menu), navigate to the source folder of QGroundControl and create the Visual Studio project by typing: - -`qmake -tp vc qgroundcontrol.pro` - -5) Now start Visual Studio and load the qgroundcontrol.vcproj if using Visual Studio 2008 or qgroundcontrol.vcxproj if using Visual Studio 2010 - -6) Compile and edit in Visual Studio. If you need to add new files, add them to qgroundcontrol.pro and re-run `qmake -tp vc qgroundcontrol.pro - - -Repository Layout -================= - -qgroundcontrol: - demo-log.txt - license.txt - qgcunittest.pro - For the unit tests. - qgcunittest.pro.user - qgcvideo.pro - qgroundcontrol.pri - Used by qgroundcontrol.pro - qgroundcontrol.pro - Project opened in QT to run qgc. - qgroundcontrol.pro.user - qgroundcontrol.qrc - Holds many images. - qgroundcontrol.rc - line of code to point toward the images - qserialport.pri - generated by qmake. - testlog.txt - testlog2.txt - user_config.pri.dist - Custom message specs to be added here. -data: - Maps from yahoo and kinect and earth. -deploy: - Install and uninstall for win32. - Create a debian packet. - Create .DMG file for publishing for mac. - Audio test on mac. -doc: - Doxyfile is in this directory and information for creating html documentation for qgc. -files: - Has the audio for the vehicle and data output. - ardupilotmega: - widgets and tool tips for pilot heading for the fixed wing. - tooltips for quadrotor - flightgear: - Aircraft: - Different types of planes and one jeep. - Protocol: - The protocol for the fixed_wings and quadrotor and quadhil.holds info about the fixed wing yaw, roll etc. Quadrotor. Agian holds info about yaw, roll etc. - Pixhawk: - Widgets for hexarotor. Widgets and tooltips for quadrotor. - vehicles: - different vehicles. Seems to hold the different kinds of aircrafts as well as files for audio and the hexarotor and quadrotor. - widgets: - Has a lot of widgets defined for buttons and sliders. - -images: - For the UI. Has a bunch of different images such as images for applications or actions or buttons. -lib: - SDL is located in this direcotry. - Msinttypes: - Defines intteger types for microsoft visual studio. - sdl: - Information about the library and to run the library on different platforms. -mavlink: - The files for the library mavlink. -qgcunittest: - Has the unittests for qgc -settings: - Parameter lists for alpha, bravo and charlie. - Data for stereo, waypoints and radio calibrartion. -src: - Code for QGCCore, audio output, configuration, waypoints, main and log compressor. - apps - Code for mavlink generation and for a video application. - comm - Code for linking to simulation, mavlink, udp, xbee, opal, flight gear and interface. - Has other libraries. Qwt is in directory named lib. The other libraries are in libs. - lib - qwt library - libs - eigen, opmapcontrol, qestserialport, qtconcurrent, utils. - input - joystick and freenect code. - plugins - Qt project for PIXHAWK plugins. - uas - Ardu pilot, UAS, mavlink factory, uas manager, interface, waypoint manager and slugs. - ui - Has code for data plots, waypoint lists and window congfiguration. All of the ui code. -thirdParty: - Library called lxbee. - Library called QSerialPort. - diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..412be38c17989da774c5bcaa055a26172b080ce9 --- /dev/null +++ b/README.md @@ -0,0 +1,179 @@ +# QGroundControl +## Open Source Micro Air Vehicle Ground Control Station + + +* Project: + + +* Files: + + +* Credits: + + + +## Documentation +For generating documentation, refer to /doc/README. + +## Notes +Please make sure to delete your build folder before re-building. Independent of which +build system you use (this is not related to Qt or your OS) the dependency checking and +cleaning is based on the current project revision. So if you change the project and don't remove the build folder before your next build, incremental building can leave you with stale object files. + +## QGC2.0 Tech Preview +Developers: In order to build the tech preview branch you need to: + + git clone https://github.com/mavlink/qgroundcontrol -b config qgc2 + git submodule init + git submodule update + +This procedure: + +* Clones the config branch (which contains QGC2) from github into your qgc2 directory +* initializes all the submodules required for QGC, such as qupdate, the firmware installer +* gets the latest code for all submodules + + +# Build on Mac OSX + +To build on Mac OSX (10.6 or later): +- - - +### Install SDL + +1. Download SDL from: +2. From the SDL disk image, copy the `sdl.framework` bundle to `/Library/Frameworks` directory (if you are not an admin copy to `~/Library/Frameworks`) + +### Install QT +- - - +1. Download Qt 4.8+ from +2. Double click the package installer and follow instructions: + +### Build QGroundControl +- - - + (use clang compiler - not gcc) + +1. From the terminal go to the `groundcontrol` directory +2. Run `qmake qgroundcontrol.pro -r -spec unsupported/macx-clang CONFIG+=x86_64` +3. Run `make -j4` + + +# Build on Linux + + +To build on Linux: +- - - + sudo apt-get install phonon libqt4-dev libphonon-dev libphonon4 phonon-backend-gstreamer qtcreator libsdl1.2-dev libflite1 flite1-dev build-essential libopenscenegraph-dev + cd directory + git clone https://github.com/mavlink/qgroundcontrol.git + +* go to `libs/thirdParty -> libxbee` +* Create Library -> Readme file in folder +* Ubuntu Application Menu -> Development -> Qt Creator +* QtCreator Menu File -> Open File or Project.. +* Open `directory/qgroundcontrol/qgroundcontrol.pro` +* Hit the green play button to compile and launch it + + +# Build on Windows +- - - + +__GNU GCC / MINGW IS UNTESTED, COULD WORK WITH +VISUAL STUDIO 2008 / 2010 EXPRESS EDITION (FREE!)__ + +Steps for Visual Studio 2008 / 2010: + +Windows XP/7: + +1. Download and install the Qt libraries for Windows from https://qt.nokia.com/downloads/ (the Visual Studio 2008 or 2010 version as appropriate) + +2. Download and install Visual Studio 2008 or 2010 Express Edition (free) from https://www.microsoft.com/visualstudio. If using Visual Studio 2010, make sure you are running at least SP1. There is a linking error you'll encounter otherwise that will prevent compilation. + +3. Go to the QGroundControl folder and then to thirdParty/libxbee and build it following the instructions in win32.README + +4. Open the Qt Command Prompt program (should be in the Start Menu), navigate to the source folder of QGroundControl and create the Visual Studio project by typing `qmake -tp vc qgroundcontrol.pro` + +5. Now start Visual Studio and load the qgroundcontrol.vcproj if using Visual Studio 2008 or qgroundcontrol.vcxproj if using Visual Studio 2010 + +6. Compile and edit in Visual Studio. If you need to add new files, add them to qgroundcontrol.pro and re-run `qmake -tp vc qgroundcontrol.pro` + + +## Repository Layout + qgroundcontrol: + demo-log.txt + license.txt + qgcunittest.pro - For the unit tests. + qgcunittest.pro.user + qgcvideo.pro + qgroundcontrol.pri - Used by qgroundcontrol.pro + qgroundcontrol.pro - Project opened in QT to run qgc. + qgroundcontrol.pro.user + qgroundcontrol.qrc - Holds many images. + qgroundcontrol.rc - line of code to point toward the images + qserialport.pri - generated by qmake. + testlog.txt - sample log file + testlog2.txt - sample log file + user_config.pri.dist - Custom message specs to be added here. + data: + Maps from yahoo and kinect and earth. + deploy: + Install and uninstall for win32. + Create a debian packet. + Create .DMG file for publishing for mac. + Audio test on mac. + doc: + Doxyfile is in this directory and information for creating html documentation for qgc. + files: + Has the audio for the vehicle and data output. + ardupilotmega: + widgets and tool tips for pilot heading for the fixed wing. + tooltips for quadrotor + flightgear: + Aircraft: + Different types of planes and one jeep. + Protocol: + The protocol for the fixed_wings and quadrotor and quadhil.holds info about the fixed wing yaw, roll etc. + Quadrotor: + Again holds info about yaw, roll etc. + Pixhawk: + Widgets for hexarotor. Widgets and tooltips for quadrotor. + vehicles: + different vehicles. Seems to hold the different kinds of aircrafts as well as files for audio and the hexarotor and quadrotor. + widgets: + Has a lot of widgets defined for buttons and sliders. + + images: + For the UI. Has a bunch of different images such as images for applications or actions or buttons. + lib: + SDL is located in this direcotry. + Msinttypes: + Defines intteger types for microsoft visual studio. + sdl: + Information about the library and to run the library on different platforms. + mavlink: + The files for the library mavlink. + qgcunittest: + Has the unittests for qgc + settings: + Parameter lists for alpha, bravo and charlie. Data for stereo, waypoints and radio calibration. + src: + Code for QGCCore, audio output, configuration, waypoints, main and log compressor. + apps + Code for mavlink generation and for a video application. + comm + Code for linking to simulation, mavlink, udp, xbee, opal, flight gear and interface. + Has other libraries. Qwt is in directory named lib. The other libraries are in libs. + lib + qwt library + libs + eigen, opmapcontrol, qestserialport, qtconcurrent, utils. + input + joystick and freenect code. + plugins + Qt project for PIXHAWK plugins. + uas + Ardu pilot, UAS, mavlink factory, uas manager, interface, waypoint manager and slugs. + ui + Has code for data plots, waypoint lists and window congfiguration. All of the ui code. +thirdParty: + Library called lxbee. + Library called QSerialPort. diff --git a/avrdude/avrdude.conf b/avrdude/avrdude.conf new file mode 100644 index 0000000000000000000000000000000000000000..8883bd12e8a200611b54a8328580a84119085907 --- /dev/null +++ b/avrdude/avrdude.conf @@ -0,0 +1,15478 @@ +# $Id: avrdude.conf.in 916 2010-01-15 16:36:13Z joerg_wunsch $ +# +# AVRDUDE Configuration File +# +# This file contains configuration data used by AVRDUDE which describes +# the programming hardware pinouts and also provides part definitions. +# AVRDUDE's "-C" command line option specifies the location of the +# configuration file. The "-c" option names the programmer configuration +# which must match one of the entry's "id" parameter. The "-p" option +# identifies which part AVRDUDE is going to be programming and must match +# one of the parts' "id" parameter. +# +# Possible entry formats are: +# +# programmer +# id = [, [, ] ...] ; # are quoted strings +# desc = ; # quoted string +# type = par | stk500 | stk500v2 | stk500pp | stk500hvsp | stk500generic | +# stk600 | stk600pp | stk600hvsp | +# avr910 | butterfly | usbasp | +# jtagmki | jtagmkii | jtagmkii_isp | jtagmkii_dw | +# jtagmkII_avr32 | jtagmkii_pdi | +# dragon_dw | dragon_jtag | dragon_isp | dragon_pp | +# dragon_hvsp | dragon_pdi | arduino; # programmer type +# baudrate = ; # baudrate for avr910-programmer +# vcc = [, ... ] ; # pin number(s) +# reset = ; # pin number +# sck = ; # pin number +# mosi = ; # pin number +# miso = ; # pin number +# errled = ; # pin number +# rdyled = ; # pin number +# pgmled = ; # pin number +# vfyled = ; # pin number +# ; +# +# part +# id = ; # quoted string +# desc = ; # quoted string +# has_jtag = ; # part has JTAG i/f +# has_debugwire = ; # part has debugWire i/f +# has_pdi = ; # part has PDI i/f +# has_tpi = ; # part has TPI i/f +# devicecode = ; # deprecated, use stk500_devcode +# stk500_devcode = ; # numeric +# avr910_devcode = ; # numeric +# signature = ; # signature bytes +# chip_erase_delay = ; # micro-seconds +# reset = dedicated | io; +# retry_pulse = reset | sck; +# pgm_enable = ; +# chip_erase = ; +# chip_erase_delay = ; # chip erase delay (us) +# # STK500 parameters (parallel programming IO lines) +# pagel = ; # pin name in hex, i.e., 0xD7 +# bs2 = ; # pin name in hex, i.e., 0xA0 +# serial = ; # can use serial downloading +# parallel = ; # can use par. programming +# # STK500v2 parameters, to be taken from Atmel's XML files +# timeout = ; +# stabdelay = ; +# cmdexedelay = ; +# synchloops = ; +# bytedelay = ; +# pollvalue = ; +# pollindex = ; +# predelay = ; +# postdelay = ; +# pollmethod = ; +# mode = ; +# delay = ; +# blocksize = ; +# readsize = ; +# hvspcmdexedelay = ; +# # STK500v2 HV programming parameters, from XML +# pp_controlstack = , , ...; # PP only +# hvsp_controlstack = , , ...; # HVSP only +# hventerstabdelay = ; +# progmodedelay = ; # PP only +# latchcycles = ; +# togglevtg = ; +# poweroffdelay = ; +# resetdelayms = ; +# resetdelayus = ; +# hvleavestabdelay = ; +# resetdelay = ; +# synchcycles = ; # HVSP only +# chiperasepulsewidth = ; # PP only +# chiperasepolltimeout = ; +# chiperasetime = ; # HVSP only +# programfusepulsewidth = ; # PP only +# programfusepolltimeout = ; +# programlockpulsewidth = ; # PP only +# programlockpolltimeout = ; +# # JTAG ICE mkII parameters, also from XML files +# allowfullpagebitstream = ; +# enablepageprogramming = ; +# idr = ; # IO addr of IDR (OCD) reg. +# rampz = ; # IO addr of RAMPZ reg. +# spmcr = ; # mem addr of SPMC[S]R reg. +# eecr = ; # mem addr of EECR reg. +# # (only when != 0x3c) +# is_avr32 = ; # AVR32 part +# +# memory +# paged = ; # yes / no +# size = ; # bytes +# page_size = ; # bytes +# num_pages = ; # numeric +# min_write_delay = ; # micro-seconds +# max_write_delay = ; # micro-seconds +# readback_p1 = ; # byte value +# readback_p2 = ; # byte value +# pwroff_after_write = ; # yes / no +# read = ; +# write = ; +# read_lo = ; +# read_hi = ; +# write_lo = ; +# write_hi = ; +# loadpage_lo = ; +# loadpage_hi = ; +# writepage = ; +# ; +# ; +# +# If any of the above parameters are not specified, the default value +# of 0 is used for numerics or the empty string ("") for string +# values. If a required parameter is left empty, AVRDUDE will +# complain. +# +# NOTES: +# * 'devicecode' is the device code used by the STK500 (see codes +# listed below) +# * Not all memory types will implement all instructions. +# * AVR Fuse bits and Lock bits are implemented as a type of memory. +# * Example memory types are: +# "flash", "eeprom", "fuse", "lfuse" (low fuse), "hfuse" (high +# fuse), "signature", "calibration", "lock" +# * The memory type specified on the avrdude command line must match +# one of the memory types defined for the specified chip. +# * The pwroff_after_write flag causes avrdude to attempt to +# power the device off and back on after an unsuccessful write to +# the affected memory area if VCC programmer pins are defined. If +# VCC pins are not defined for the programmer, a message +# indicating that the device needs a power-cycle is printed out. +# This flag was added to work around a problem with the +# at90s4433/2333's; see the at90s4433 errata at: +# +# http://www.atmel.com/atmel/acrobat/doc1280.pdf +# +# INSTRUCTION FORMATS +# +# Instruction formats are specified as a comma seperated list of +# string values containing information (bit specifiers) about each +# of the 32 bits of the instruction. Bit specifiers may be one of +# the following formats: +# +# '1' = the bit is always set on input as well as output +# +# '0' = the bit is always clear on input as well as output +# +# 'x' = the bit is ignored on input and output +# +# 'a' = the bit is an address bit, the bit-number matches this bit +# specifier's position within the current instruction byte +# +# 'aN' = the bit is the Nth address bit, bit-number = N, i.e., a12 +# is address bit 12 on input, a0 is address bit 0. +# +# 'i' = the bit is an input data bit +# +# 'o' = the bit is an output data bit +# +# Each instruction must be composed of 32 bit specifiers. The +# instruction specification closely follows the instruction data +# provided in Atmel's data sheets for their parts. +# +# See below for some examples. +# +# +# The following are STK500 part device codes to use for the +# "devicecode" field of the part. These came from Atmel's software +# section avr061.zip which accompanies the application note +# AVR061 available from: +# +# http://www.atmel.com/atmel/acrobat/doc2525.pdf +# + +#define ATTINY10 0x10 /* the _old_ one that never existed! */ +#define ATTINY11 0x11 +#define ATTINY12 0x12 +#define ATTINY15 0x13 +#define ATTINY13 0x14 + +#define ATTINY22 0x20 +#define ATTINY26 0x21 +#define ATTINY28 0x22 +#define ATTINY2313 0x23 + +#define AT90S1200 0x33 + +#define AT90S2313 0x40 +#define AT90S2323 0x41 +#define AT90S2333 0x42 +#define AT90S2343 0x43 + +#define AT90S4414 0x50 +#define AT90S4433 0x51 +#define AT90S4434 0x52 +#define ATMEGA48 0x59 + +#define AT90S8515 0x60 +#define AT90S8535 0x61 +#define AT90C8534 0x62 +#define ATMEGA8515 0x63 +#define ATMEGA8535 0x64 + +#define ATMEGA8 0x70 +#define ATMEGA88 0x73 +#define ATMEGA168 0x86 + +#define ATMEGA161 0x80 +#define ATMEGA163 0x81 +#define ATMEGA16 0x82 +#define ATMEGA162 0x83 +#define ATMEGA169 0x84 + +#define ATMEGA323 0x90 +#define ATMEGA32 0x91 + +#define ATMEGA64 0xA0 + +#define ATMEGA103 0xB1 +#define ATMEGA128 0xB2 +#define AT90CAN128 0xB3 +#define AT90CAN64 0xB3 +#define AT90CAN32 0xB3 + +#define AT86RF401 0xD0 + +#define AT89START 0xE0 +#define AT89S51 0xE0 +#define AT89S52 0xE1 + +# The following table lists the devices in the original AVR910 +# appnote: +# |Device |Signature | Code | +# +-------+----------+------+ +# |tiny12 | 1E 90 05 | 0x55 | +# |tiny15 | 1E 90 06 | 0x56 | +# | | | | +# | S1200 | 1E 90 01 | 0x13 | +# | | | | +# | S2313 | 1E 91 01 | 0x20 | +# | S2323 | 1E 91 02 | 0x48 | +# | S2333 | 1E 91 05 | 0x34 | +# | S2343 | 1E 91 03 | 0x4C | +# | | | | +# | S4414 | 1E 92 01 | 0x28 | +# | S4433 | 1E 92 03 | 0x30 | +# | S4434 | 1E 92 02 | 0x6C | +# | | | | +# | S8515 | 1E 93 01 | 0x38 | +# | S8535 | 1E 93 03 | 0x68 | +# | | | | +# |mega32 | 1E 95 01 | 0x72 | +# |mega83 | 1E 93 05 | 0x65 | +# |mega103| 1E 97 01 | 0x41 | +# |mega161| 1E 94 01 | 0x60 | +# |mega163| 1E 94 02 | 0x64 | + +# Appnote AVR109 also has a table of AVR910 device codes, which +# lists: +# dev avr910 signature +# ATmega8 0x77 0x1E 0x93 0x07 +# ATmega8515 0x3B 0x1E 0x93 0x06 +# ATmega8535 0x6A 0x1E 0x93 0x08 +# ATmega16 0x75 0x1E 0x94 0x03 +# ATmega162 0x63 0x1E 0x94 0x04 +# ATmega163 0x66 0x1E 0x94 0x02 +# ATmega169 0x79 0x1E 0x94 0x05 +# ATmega32 0x7F 0x1E 0x95 0x02 +# ATmega323 0x73 0x1E 0x95 0x01 +# ATmega64 0x46 0x1E 0x96 0x02 +# ATmega128 0x44 0x1E 0x97 0x02 +# +# These codes refer to "BOOT" device codes which are apparently +# different than standard device codes, for whatever reasons +# (often one above the standard code). + +# There are several extended versions of AVR910 implementations around +# in the Internet. These add the following codes (only devices that +# actually exist are listed): + +# ATmega8515 0x3A +# ATmega128 0x43 +# ATmega64 0x45 +# ATtiny26 0x5E +# ATmega8535 0x69 +# ATmega32 0x72 +# ATmega16 0x74 +# ATmega8 0x76 +# ATmega169 0x78 + +# +# Overall avrdude defaults +# +default_parallel = "lpt1"; +default_serial = "com1"; + + +# +# PROGRAMMER DEFINITIONS +# + +programmer + id = "arduino"; + desc = "Arduino"; + type = arduino; +; + +programmer + id = "avrisp"; + desc = "Atmel AVR ISP"; + type = stk500; +; + +programmer + id = "avrispv2"; + desc = "Atmel AVR ISP V2"; + type = stk500v2; +; + +programmer + id = "avrispmkII"; + desc = "Atmel AVR ISP mkII"; + type = stk500v2; +; + +programmer + id = "avrisp2"; + desc = "Atmel AVR ISP mkII"; + type = stk500v2; +; + +programmer + id = "buspirate"; + desc = "The Bus Pirate"; + type = buspirate; +; + +# This is supposed to be the "default" STK500 entry. +# Attempts to select the correct firmware version +# by probing for it. Better use one of the entries +# below instead. +programmer + id = "stk500"; + desc = "Atmel STK500"; + type = stk500generic; +; + +programmer + id = "stk500v1"; + desc = "Atmel STK500 Version 1.x firmware"; + type = stk500; +; + +programmer + id = "mib510"; + desc = "Crossbow MIB510 programming board"; + type = stk500; +; + +programmer + id = "stk500v2"; + desc = "Atmel STK500 Version 2.x firmware"; + type = stk500v2; +; + +programmer + id = "stk500pp"; + desc = "Atmel STK500 V2 in parallel programming mode"; + type = stk500pp; +; + +programmer + id = "stk500hvsp"; + desc = "Atmel STK500 V2 in high-voltage serial programming mode"; + type = stk500hvsp; +; + +programmer + id = "stk600"; + desc = "Atmel STK600"; + type = stk600; +; + +programmer + id = "stk600pp"; + desc = "Atmel STK600 in parallel programming mode"; + type = stk600pp; +; + +programmer + id = "stk600hvsp"; + desc = "Atmel STK600 in high-voltage serial programming mode"; + type = stk600hvsp; +; + +programmer + id = "avr910"; + desc = "Atmel Low Cost Serial Programmer"; + type = avr910; +; + +programmer + id = "usbasp"; + desc = "USBasp, http://www.fischl.de/usbasp/"; + type = usbasp; +; + +programmer + id = "usbtiny"; + desc = "USBtiny simple USB programmer, http://www.ladyada.net/make/usbtinyisp/"; + type = usbtiny; +; + +programmer + id = "butterfly"; + desc = "Atmel Butterfly Development Board"; + type = butterfly; +; + +programmer + id = "avr109"; + desc = "Atmel AppNote AVR109 Boot Loader"; + type = butterfly; +; + +programmer + id = "avr911"; + desc = "Atmel AppNote AVR911 AVROSP"; + type = butterfly; +; + +programmer + id = "jtagmkI"; + desc = "Atmel JTAG ICE (mkI)"; + baudrate = 115200; # default is 115200 + type = jtagmki; +; + +# easier to type +programmer + id = "jtag1"; + desc = "Atmel JTAG ICE (mkI)"; + baudrate = 115200; # default is 115200 + type = jtagmki; +; + +# easier to type +programmer + id = "jtag1slow"; + desc = "Atmel JTAG ICE (mkI)"; + baudrate = 19200; + type = jtagmki; +; + +programmer + id = "jtagmkII"; + desc = "Atmel JTAG ICE mkII"; + baudrate = 19200; # default is 19200 + type = jtagmkii; +; + +# easier to type +programmer + id = "jtag2slow"; + desc = "Atmel JTAG ICE mkII"; + baudrate = 19200; # default is 19200 + type = jtagmkii; +; + +# JTAG ICE mkII @ 115200 Bd +programmer + id = "jtag2fast"; + desc = "Atmel JTAG ICE mkII"; + baudrate = 115200; + type = jtagmkii; +; + +# make the fast one the default, people will love that +programmer + id = "jtag2"; + desc = "Atmel JTAG ICE mkII"; + baudrate = 115200; + type = jtagmkii; +; + +# JTAG ICE mkII in ISP mode +programmer + id = "jtag2isp"; + desc = "Atmel JTAG ICE mkII in ISP mode"; + baudrate = 115200; + type = jtagmkii_isp; +; + +# JTAG ICE mkII in debugWire mode +programmer + id = "jtag2dw"; + desc = "Atmel JTAG ICE mkII in debugWire mode"; + baudrate = 115200; + type = jtagmkii_dw; +; + +# JTAG ICE mkII in AVR32 mode +programmer + id = "jtagmkII_avr32"; + desc = "Atmel JTAG ICE mkII im AVR32 mode"; + baudrate = 115200; + type = jtagmkii_avr32; +; + +# JTAG ICE mkII in AVR32 mode +programmer + id = "jtag2avr32"; + desc = "Atmel JTAG ICE mkII im AVR32 mode"; + baudrate = 115200; + type = jtagmkii_avr32; +; + +# JTAG ICE mkII in PDI mode +programmer + id = "jtag2pdi"; + desc = "Atmel JTAG ICE mkII PDI mode"; + baudrate = 115200; + type = jtagmkii_pdi; +; + +# AVR Dragon in JTAG mode +programmer + id = "dragon_jtag"; + desc = "Atmel AVR Dragon in JTAG mode"; + baudrate = 115200; + type = dragon_jtag; +; + +# AVR Dragon in ISP mode +programmer + id = "dragon_isp"; + desc = "Atmel AVR Dragon in ISP mode"; + baudrate = 115200; + type = dragon_isp; +; + +# AVR Dragon in PP mode +programmer + id = "dragon_pp"; + desc = "Atmel AVR Dragon in PP mode"; + baudrate = 115200; + type = dragon_pp; +; + +# AVR Dragon in HVSP mode +programmer + id = "dragon_hvsp"; + desc = "Atmel AVR Dragon in HVSP mode"; + baudrate = 115200; + type = dragon_hvsp; +; + +# AVR Dragon in debugWire mode +programmer + id = "dragon_dw"; + desc = "Atmel AVR Dragon in debugWire mode"; + baudrate = 115200; + type = dragon_dw; +; + +# AVR Dragon in PDI mode +programmer + id = "dragon_pdi"; + desc = "Atmel AVR Dragon in PDI mode"; + baudrate = 115200; + type = dragon_pdi; +; + +programmer + id = "pavr"; + desc = "Jason Kyle's pAVR Serial Programmer"; + type = avr910; +; + +# Parallel port programmers. + +programmer + id = "bsd"; + desc = "Brian Dean's Programmer, http://www.bsdhome.com/avrdude/"; + type = par; + vcc = 2, 3, 4, 5; + reset = 7; + sck = 8; + mosi = 9; + miso = 10; +; + +programmer + id = "stk200"; + desc = "STK200"; + type = par; + buff = 4, 5; + sck = 6; + mosi = 7; + reset = 9; + miso = 10; +; + +# The programming dongle used by the popular Ponyprog +# utility. It is almost similar to the STK200 one, +# except that there is a LED indicating that the +# programming is currently in progress. + +programmer + id = "pony-stk200"; + desc = "Pony Prog STK200"; + type = par; + buff = 4, 5; + sck = 6; + mosi = 7; + reset = 9; + miso = 10; + pgmled = 8; +; + +programmer + id = "dt006"; + desc = "Dontronics DT006"; + type = par; + reset = 4; + sck = 5; + mosi = 2; + miso = 11; +; + +programmer + id = "bascom"; + desc = "Bascom SAMPLE programming cable"; + type = par; + reset = 4; + sck = 5; + mosi = 2; + miso = 11; +; + +programmer + id = "alf"; + desc = "Nightshade ALF-PgmAVR, http://nightshade.homeip.net/"; + type = par; + vcc = 2, 3, 4, 5; + buff = 6; + reset = 7; + sck = 8; + mosi = 9; + miso = 10; + errled = 1; + rdyled = 14; + pgmled = 16; + vfyled = 17; +; + +programmer + id = "sp12"; + desc = "Steve Bolt's Programmer"; + type = par; + vcc = 4,5,6,7,8; + reset = 3; + sck = 2; + mosi = 9; + miso = 11; +; + +programmer + id = "picoweb"; + desc = "Picoweb Programming Cable, http://www.picoweb.net/"; + type = par; + reset = 2; + sck = 3; + mosi = 4; + miso = 13; +; + +programmer + id = "abcmini"; + desc = "ABCmini Board, aka Dick Smith HOTCHIP"; + type = par; + reset = 4; + sck = 3; + mosi = 2; + miso = 10; +; + +programmer + id = "futurlec"; + desc = "Futurlec.com programming cable."; + type = par; + reset = 3; + sck = 2; + mosi = 1; + miso = 10; +; + + +# From the contributor of the "xil" jtag cable: +# The "vcc" definition isn't really vcc (the cable gets its power from +# the programming circuit) but is necessary to switch one of the +# buffer lines (trying to add it to the "buff" lines doesn't work). +# With this, TMS connects to RESET, TDI to MOSI, TDO to MISO and TCK +# to SCK (plus vcc/gnd of course) +programmer + id = "xil"; + desc = "Xilinx JTAG cable"; + type = par; + mosi = 2; + sck = 3; + reset = 4; + buff = 5; + miso = 13; + vcc = 6; +; + + +programmer + id = "dapa"; + desc = "Direct AVR Parallel Access cable"; + type = par; + vcc = 3; + reset = 16; + sck = 1; + mosi = 2; + miso = 11; +; + +programmer + id = "atisp"; + desc = "AT-ISP V1.1 programming cable for AVR-SDK1 from micro-research.co.th"; + type = par; + reset = ~6; + sck = ~8; + mosi = ~7; + miso = ~10; +; + +programmer + id = "ere-isp-avr"; + desc = "ERE ISP-AVR "; + type = par; + reset = ~4; + sck = 3; + mosi = 2; + miso = 10; +; + +programmer + id = "blaster"; + desc = "Altera ByteBlaster"; + type = par; + sck = 2; + miso = 11; + reset = 3; + mosi = 8; + buff = 14; +; + +# It is almost same as pony-stk200, except vcc on pin 5 to auto +# disconnect port (download on http://electropol.free.fr) +programmer + id = "frank-stk200"; + desc = "Frank STK200"; + type = par; + vcc = 5; + sck = 6; + mosi = 7; + reset = 9; + miso = 10; + pgmled = 8; +; + +# The AT98ISP Cable is a simple parallel dongle for AT89 family. +# http://www.atmel.com/dyn/products/tools_card.asp?tool_id=2877 +programmer +id = "89isp"; +desc = "Atmel at89isp cable"; +type = par; +reset = 17; +sck = 1; +mosi = 2; +miso = 10; +; + + +# +# some ultra cheap programmers use bitbanging on the +# serialport. +# +# PC - DB9 - Pins for RS232: +# +# GND 5 -- |O +# | O| <- 9 RI +# DTR 4 <- |O | +# | O| <- 8 CTS +# TXD 3 <- |O | +# | O| -> 7 RTS +# RXD 2 -> |O | +# | O| <- 6 DSR +# DCD 1 -> |O +# +# Using RXD is currently not supported. +# Using RI is not supported under Win32 but is supported under Posix. + +# serial ponyprog design (dasa2 in uisp) +# reset=!txd sck=rts mosi=dtr miso=cts + +programmer + id = "ponyser"; + desc = "design ponyprog serial, reset=!txd sck=rts mosi=dtr miso=cts"; + type = serbb; + reset = ~3; + sck = 7; + mosi = 4; + miso = 8; +; + +# Same as above, different name +# reset=!txd sck=rts mosi=dtr miso=cts + +programmer + id = "siprog"; + desc = "Lancos SI-Prog "; + type = serbb; + reset = ~3; + sck = 7; + mosi = 4; + miso = 8; +; + +# unknown (dasa in uisp) +# reset=rts sck=dtr mosi=txd miso=cts + +programmer + id = "dasa"; + desc = "serial port banging, reset=rts sck=dtr mosi=txd miso=cts"; + type = serbb; + reset = 7; + sck = 4; + mosi = 3; + miso = 8; +; + +# unknown (dasa3 in uisp) +# reset=!dtr sck=rts mosi=txd miso=cts + +programmer + id = "dasa3"; + desc = "serial port banging, reset=!dtr sck=rts mosi=txd miso=cts"; + type = serbb; + reset = ~4; + sck = 7; + mosi = 3; + miso = 8; +; + +# C2N232i (jumper configuration "auto") +# reset=dtr sck=!rts mosi=!txd miso=!cts + +programmer + id = "c2n232i"; + desc = "serial port banging, reset=dtr sck=!rts mosi=!txd miso=!cts"; + type = serbb; + reset = 4; + sck = ~7; + mosi = ~3; + miso = ~8; +; + +# +# PART DEFINITIONS +# + +#------------------------------------------------------------ +# ATtiny11 +#------------------------------------------------------------ + +# This is an HVSP-only device. + +part + id = "t11"; + desc = "ATtiny11"; + stk500_devcode = 0x11; + signature = 0x1e 0x90 0x04; + chip_erase_delay = 20000; + + timeout = 200; + hvsp_controlstack = + 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, + 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, + 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, + 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + hvspcmdexedelay = 0; + synchcycles = 6; + latchcycles = 1; + togglevtg = 1; + poweroffdelay = 25; + resetdelayms = 0; + resetdelayus = 50; + hvleavestabdelay = 100; + resetdelay = 25; + chiperasepolltimeout = 40; + chiperasetime = 0; + programfusepolltimeout = 25; + programlockpolltimeout = 25; + + memory "eeprom" + size = 64; + blocksize = 64; + readsize = 256; + delay = 5; + ; + + memory "flash" + size = 1024; + blocksize = 128; + readsize = 256; + delay = 3; + ; + + memory "signature" + size = 3; + ; + + memory "lock" + size = 1; + ; + + memory "calibration" + size = 1; + ; + + memory "fuse" + size = 1; + ; +; + +#------------------------------------------------------------ +# ATtiny12 +#------------------------------------------------------------ + +part + id = "t12"; + desc = "ATtiny12"; + stk500_devcode = 0x12; + avr910_devcode = 0x55; + signature = 0x1e 0x90 0x05; + chip_erase_delay = 20000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + hvsp_controlstack = + 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, + 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, + 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, + 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; + hventerstabdelay = 100; + hvspcmdexedelay = 0; + synchcycles = 6; + latchcycles = 1; + togglevtg = 1; + poweroffdelay = 25; + resetdelayms = 0; + resetdelayus = 50; + hvleavestabdelay = 100; + resetdelay = 25; + chiperasepolltimeout = 40; + chiperasetime = 0; + programfusepolltimeout = 25; + programlockpolltimeout = 25; + + memory "eeprom" + size = 64; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 x x x x x x x x", + "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 x x x x x x x x", + "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + mode = 0x04; + delay = 8; + blocksize = 64; + readsize = 256; + ; + + memory "flash" + size = 1024; + min_write_delay = 4500; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + mode = 0x04; + delay = 5; + blocksize = 128; + readsize = 256; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x o o x"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "fuse" + size = 1; + read = "0 1 0 1 0 0 0 0 x x x x x x x x", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 x x x x x", + "x x x x x x x x i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; +; + +#------------------------------------------------------------ +# ATtiny13 +#------------------------------------------------------------ + +part + id = "t13"; + desc = "ATtiny13"; + has_debugwire = yes; + flash_instr = 0xB4, 0x0E, 0x1E; + eeprom_instr = 0xBB, 0xFE, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, + 0xBC, 0x0E, 0xB4, 0x0E, 0xBA, 0x0D, 0xBB, 0xBC, + 0x99, 0xE1, 0xBB, 0xAC; + stk500_devcode = 0x14; + signature = 0x1e 0x90 0x07; + chip_erase_delay = 4000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + hvsp_controlstack = + 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, + 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, + 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, + 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + hvspcmdexedelay = 0; + synchcycles = 6; + latchcycles = 1; + togglevtg = 1; + poweroffdelay = 25; + resetdelayms = 0; + resetdelayus = 90; + hvleavestabdelay = 100; + resetdelay = 25; + chiperasepolltimeout = 40; + chiperasetime = 0; + programfusepolltimeout = 25; + programlockpolltimeout = 25; + + memory "eeprom" + size = 64; + page_size = 4; + min_write_delay = 4000; + max_write_delay = 4000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", + "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", + "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x x", + " x x a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 5; + blocksize = 4; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 1024; + page_size = 32; + num_pages = 32; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 0 0 0 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 0 0 0 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x x a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x x a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 0 0 0 a8", + " a7 a6 a5 a4 x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 32; + readsize = 256; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "lock" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "calibration" + size = 2; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 a0 o o o o o o o o"; + ; + + memory "lfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; + +; + + +#------------------------------------------------------------ +# ATtiny15 +#------------------------------------------------------------ + +part + id = "t15"; + desc = "ATtiny15"; + stk500_devcode = 0x13; + avr910_devcode = 0x56; + signature = 0x1e 0x90 0x06; + chip_erase_delay = 8200; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + hvsp_controlstack = + 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, + 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, + 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, + 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; + hventerstabdelay = 100; + hvspcmdexedelay = 5; + synchcycles = 6; + latchcycles = 16; + togglevtg = 1; + poweroffdelay = 25; + resetdelayms = 0; + resetdelayus = 50; + hvleavestabdelay = 100; + resetdelay = 25; + chiperasepolltimeout = 40; + chiperasetime = 0; + programfusepolltimeout = 25; + programlockpolltimeout = 25; + + memory "eeprom" + size = 64; + min_write_delay = 8200; + max_write_delay = 8200; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 x x x x x x x x", + "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 x x x x x x x x", + "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + mode = 0x04; + delay = 10; + blocksize = 64; + readsize = 256; + ; + + memory "flash" + size = 1024; + min_write_delay = 4100; + max_write_delay = 4100; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + mode = 0x04; + delay = 5; + blocksize = 128; + readsize = 256; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x o o x"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "fuse" + size = 1; + read = "0 1 0 1 0 0 0 0 x x x x x x x x", + "x x x x x x x x o o o o x x o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 x x x x x", + "x x x x x x x x i i i i 1 1 i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; +; + +#------------------------------------------------------------ +# AT90s1200 +#------------------------------------------------------------ + +part + id = "1200"; + desc = "AT90S1200"; + stk500_devcode = 0x33; + avr910_devcode = 0x13; + signature = 0x1e 0x90 0x01; + pagel = 0xd7; + bs2 = 0xa0; + chip_erase_delay = 20000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 1; + bytedelay = 0; + pollindex = 0; + pollvalue = 0xFF; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 0; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 15; + chiperasepolltimeout = 0; + programfusepulsewidth = 2; + programfusepolltimeout = 0; + programlockpulsewidth = 0; + programlockpolltimeout = 1; + + memory "eeprom" + size = 64; + min_write_delay = 4000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 x x x x x x x x", + "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 x x x x x x x x", + "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + mode = 0x04; + delay = 20; + blocksize = 32; + readsize = 256; + ; + memory "flash" + size = 1024; + min_write_delay = 4000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + mode = 0x02; + delay = 15; + blocksize = 128; + readsize = 256; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "fuse" + size = 1; + ; + memory "lock" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + ; + ; + +#------------------------------------------------------------ +# AT90s4414 +#------------------------------------------------------------ + +part + id = "4414"; + desc = "AT90S4414"; + stk500_devcode = 0x50; + avr910_devcode = 0x28; + signature = 0x1e 0x92 0x01; + chip_erase_delay = 20000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 0; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 15; + chiperasepolltimeout = 0; + programfusepulsewidth = 2; + programfusepolltimeout = 0; + programlockpulsewidth = 0; + programlockpolltimeout = 1; + + memory "eeprom" + size = 256; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x80; + readback_p2 = 0x7f; + read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + mode = 0x04; + delay = 12; + blocksize = 64; + readsize = 256; + ; + memory "flash" + size = 4096; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x7f; + readback_p2 = 0x7f; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + mode = 0x04; + delay = 12; + blocksize = 64; + readsize = 256; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "fuse" + size = 1; + ; + memory "lock" + size = 1; + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + ; + +#------------------------------------------------------------ +# AT90s2313 +#------------------------------------------------------------ + +part + id = "2313"; + desc = "AT90S2313"; + stk500_devcode = 0x40; + avr910_devcode = 0x20; + signature = 0x1e 0x91 0x01; + chip_erase_delay = 20000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 0; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 15; + chiperasepolltimeout = 0; + programfusepulsewidth = 2; + programfusepolltimeout = 0; + programlockpulsewidth = 0; + programlockpolltimeout = 1; + + memory "eeprom" + size = 128; + min_write_delay = 4000; + max_write_delay = 9000; + readback_p1 = 0x80; + readback_p2 = 0x7f; + read = "1 0 1 0 0 0 0 0 x x x x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 x x x x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + mode = 0x04; + delay = 12; + blocksize = 64; + readsize = 256; + ; + memory "flash" + size = 2048; + min_write_delay = 4000; + max_write_delay = 9000; + readback_p1 = 0x7f; + readback_p2 = 0x7f; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + mode = 0x04; + delay = 12; + blocksize = 128; + readsize = 256; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "fuse" + size = 1; + ; + memory "lock" + size = 1; + write = "1 0 1 0 1 1 0 0 1 1 1 x x i i x", + "x x x x x x x x x x x x x x x x"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + ; + +#------------------------------------------------------------ +# AT90s2333 +#------------------------------------------------------------ + +part + id = "2333"; +##### WARNING: No XML file for device 'AT90S2333'! ##### + desc = "AT90S2333"; + stk500_devcode = 0x42; + avr910_devcode = 0x34; + signature = 0x1e 0x91 0x05; + chip_erase_delay = 20000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 0; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 15; + chiperasepolltimeout = 0; + programfusepulsewidth = 2; + programfusepolltimeout = 0; + programlockpulsewidth = 0; + programlockpolltimeout = 1; + + memory "eeprom" + size = 128; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x00; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 x x x x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 x x x x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + mode = 0x04; + delay = 12; + blocksize = 128; + readsize = 256; + ; + + memory "flash" + size = 2048; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + mode = 0x04; + delay = 12; + blocksize = 128; + readsize = 256; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "fuse" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + pwroff_after_write = yes; + read = "0 1 0 1 0 0 0 0 x x x x x x x x", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", + "x x x x x x x x x x x x x x x x"; + ; + memory "lock" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x o o x"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + ; + ; + + +#------------------------------------------------------------ +# AT90s2343 (also AT90s2323 and ATtiny22) +#------------------------------------------------------------ + +part + id = "2343"; + desc = "AT90S2343"; + stk500_devcode = 0x43; + avr910_devcode = 0x4c; + signature = 0x1e 0x91 0x03; + chip_erase_delay = 18000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + hvsp_controlstack = + 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00, + 0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78, + 0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, + 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; + hventerstabdelay = 100; + hvspcmdexedelay = 0; + synchcycles = 6; + latchcycles = 1; + togglevtg = 0; + poweroffdelay = 25; + resetdelayms = 0; + resetdelayus = 50; + hvleavestabdelay = 100; + resetdelay = 25; + chiperasepolltimeout = 40; + chiperasetime = 0; + programfusepolltimeout = 25; + programlockpolltimeout = 25; + + memory "eeprom" + size = 128; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x00; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0", + "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0", + "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + mode = 0x04; + delay = 12; + blocksize = 64; + readsize = 256; + ; + memory "flash" + size = 2048; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + mode = 0x04; + delay = 12; + blocksize = 128; + readsize = 128; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "fuse" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x o o o x x x x o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 1 1 1 1 i", + "x x x x x x x x x x x x x x x x"; + ; + memory "lock" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x o o o x x x x o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + ; + ; + + +#------------------------------------------------------------ +# AT90s4433 +#------------------------------------------------------------ + +part + id = "4433"; + desc = "AT90S4433"; + stk500_devcode = 0x51; + avr910_devcode = 0x30; + signature = 0x1e 0x92 0x03; + chip_erase_delay = 20000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 0; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 15; + chiperasepolltimeout = 0; + programfusepulsewidth = 2; + programfusepolltimeout = 0; + programlockpulsewidth = 0; + programlockpolltimeout = 1; + + memory "eeprom" + size = 256; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x00; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0 x x x x x x x x", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0 x x x x x x x x", + "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + mode = 0x04; + delay = 12; + blocksize = 128; + readsize = 256; + ; + memory "flash" + size = 4096; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + mode = 0x04; + delay = 12; + blocksize = 128; + readsize = 256; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "fuse" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + pwroff_after_write = yes; + read = "0 1 0 1 0 0 0 0 x x x x x x x x", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", + "x x x x x x x x x x x x x x x x"; + ; + memory "lock" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x o o x"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + ; + ; + +#------------------------------------------------------------ +# AT90s4434 +#------------------------------------------------------------ + +part + id = "4434"; +##### WARNING: No XML file for device 'AT90S4434'! ##### + desc = "AT90S4434"; + stk500_devcode = 0x52; + avr910_devcode = 0x6c; + signature = 0x1e 0x92 0x02; + chip_erase_delay = 20000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 256; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x00; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0 x x x x x x x x", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0 x x x x x x x x", + "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + ; + memory "flash" + size = 4096; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "fuse" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + read = "0 1 0 1 0 0 0 0 x x x x x x x x", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", + "x x x x x x x x x x x x x x x x"; + ; + memory "lock" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x o o x"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + ; + ; + +#------------------------------------------------------------ +# AT90s8515 +#------------------------------------------------------------ + +part + id = "8515"; + desc = "AT90S8515"; + stk500_devcode = 0x60; + avr910_devcode = 0x38; + signature = 0x1e 0x93 0x01; + chip_erase_delay = 20000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 0; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + resetdelay = 15; + chiperasepulsewidth = 15; + chiperasepolltimeout = 0; + programfusepulsewidth = 2; + programfusepolltimeout = 0; + programlockpulsewidth = 0; + programlockpolltimeout = 1; + + memory "eeprom" + size = 512; + min_write_delay = 4000; + max_write_delay = 9000; + readback_p1 = 0x80; + readback_p2 = 0x7f; + read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + mode = 0x04; + delay = 12; + blocksize = 128; + readsize = 256; + ; + memory "flash" + size = 8192; + min_write_delay = 4000; + max_write_delay = 9000; + readback_p1 = 0x7f; + readback_p2 = 0x7f; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + mode = 0x04; + delay = 12; + blocksize = 128; + readsize = 256; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "fuse" + size = 1; + ; + memory "lock" + size = 1; + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + ; + +#------------------------------------------------------------ +# AT90s8535 +#------------------------------------------------------------ + +part + id = "8535"; + desc = "AT90S8535"; + stk500_devcode = 0x61; + avr910_devcode = 0x68; + signature = 0x1e 0x93 0x03; + chip_erase_delay = 20000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 0; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 15; + chiperasepolltimeout = 0; + programfusepulsewidth = 2; + programfusepolltimeout = 0; + programlockpulsewidth = 0; + programlockpolltimeout = 1; + + memory "eeprom" + size = 512; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x00; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + mode = 0x04; + delay = 12; + blocksize = 128; + readsize = 256; + ; + memory "flash" + size = 8192; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + mode = 0x04; + delay = 12; + blocksize = 128; + readsize = 256; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "fuse" + size = 1; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x x x o"; + write = "1 0 1 0 1 1 0 0 1 0 1 1 1 1 1 i", + "x x x x x x x x x x x x x x x x"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x o o x x x x x x"; + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + ; + +#------------------------------------------------------------ +# ATmega103 +#------------------------------------------------------------ + +part + id = "m103"; + desc = "ATMEGA103"; + stk500_devcode = 0xB1; + avr910_devcode = 0x41; + signature = 0x1e 0x97 0x01; + chip_erase_delay = 112000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x8E, 0x9E, 0x2E, 0x3E, 0xAE, 0xBE, + 0x4E, 0x5E, 0xCE, 0xDE, 0x6E, 0x7E, 0xEE, 0xDE, + 0x66, 0x76, 0xE6, 0xF6, 0x6A, 0x7A, 0xEA, 0x7A, + 0x7F, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 0; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 15; + chiperasepolltimeout = 0; + programfusepulsewidth = 2; + programfusepolltimeout = 0; + programlockpulsewidth = 0; + programlockpolltimeout = 10; + + memory "eeprom" + size = 4096; + min_write_delay = 4000; + max_write_delay = 9000; + readback_p1 = 0x80; + readback_p2 = 0x7f; + read = " 1 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + mode = 0x04; + delay = 12; + blocksize = 64; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 131072; + page_size = 256; + num_pages = 512; + min_write_delay = 22000; + max_write_delay = 56000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x11; + delay = 70; + blocksize = 256; + readsize = 256; + ; + + memory "fuse" + size = 1; + read = "0 1 0 1 0 0 0 0 x x x x x x x x", + "x x x x x x x x x x o x o 1 o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 1 i 1 i i", + "x x x x x x x x x x x x x x x x"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x o o x"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + +#------------------------------------------------------------ +# ATmega64 +#------------------------------------------------------------ + +part + id = "m64"; + desc = "ATMEGA64"; + has_jtag = yes; + stk500_devcode = 0xA0; + avr910_devcode = 0x45; + signature = 0x1e 0x96 0x02; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 6; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x22; + spmcr = 0x68; + allowfullpagebitstream = yes; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 2048; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + mode = 0x04; + delay = 20; + blocksize = 64; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 65536; + page_size = 256; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x21; + delay = 6; + blocksize = 128; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 4; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + + + +#------------------------------------------------------------ +# ATmega128 +#------------------------------------------------------------ + +part + id = "m128"; + desc = "ATMEGA128"; + has_jtag = yes; + stk500_devcode = 0xB2; + avr910_devcode = 0x43; + signature = 0x1e 0x97 0x02; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 6; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x22; + spmcr = 0x68; + rampz = 0x3b; + allowfullpagebitstream = yes; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 4096; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + mode = 0x04; + delay = 12; + blocksize = 64; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 131072; + page_size = 256; + num_pages = 512; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x21; + delay = 6; + blocksize = 128; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 4; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# AT90CAN128 +#------------------------------------------------------------ + +part + id = "c128"; + desc = "AT90CAN128"; + has_jtag = yes; + stk500_devcode = 0xB3; +# avr910_devcode = 0x43; + signature = 0x1e 0x97 0x81; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 6; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + rampz = 0x3b; + eecr = 0x3f; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 4096; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 0 x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 0 x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + + mode = 0x41; + delay = 20; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 131072; + page_size = 256; + num_pages = 512; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# AT90CAN64 +#------------------------------------------------------------ + +part + id = "c64"; + desc = "AT90CAN64"; + has_jtag = yes; + stk500_devcode = 0xB3; +# avr910_devcode = 0x43; + signature = 0x1e 0x96 0x81; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 6; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + rampz = 0x3b; + eecr = 0x3f; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 2048; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 0 x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 0 x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + + mode = 0x41; + delay = 20; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 65536; + page_size = 256; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# AT90CAN32 +#------------------------------------------------------------ + +part + id = "c32"; + desc = "AT90CAN32"; + has_jtag = yes; + stk500_devcode = 0xB3; +# avr910_devcode = 0x43; + signature = 0x1e 0x95 0x81; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 6; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + rampz = 0x3b; + eecr = 0x3f; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 1024; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 0 x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 0 x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + + mode = 0x41; + delay = 20; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 32768; + page_size = 256; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + +#------------------------------------------------------------ +# ATmega16 +#------------------------------------------------------------ + +part + id = "m16"; + desc = "ATMEGA16"; + has_jtag = yes; + stk500_devcode = 0x82; + avr910_devcode = 0x74; + signature = 0x1e 0x94 0x03; + pagel = 0xd7; + bs2 = 0xa0; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 100; + latchcycles = 6; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + resetdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + allowfullpagebitstream = yes; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 4; /* for parallel programming */ + size = 512; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x04; + delay = 10; + blocksize = 128; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 16384; + page_size = 128; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + + mode = 0x21; + delay = 6; + blocksize = 128; + readsize = 256; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "calibration" + size = 4; + + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + ; + + +#------------------------------------------------------------ +# ATmega164P +#------------------------------------------------------------ + +# close to ATmega16 + +part + id = "m164p"; + desc = "ATMEGA164P"; + has_jtag = yes; + stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one + avr910_devcode = 0x74; + signature = 0x1e 0x94 0x0a; + pagel = 0xd7; + bs2 = 0xa0; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 4; /* for parallel programming */ + size = 512; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 128; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 16384; + page_size = 128; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + + mode = 0x21; + delay = 6; + blocksize = 128; + readsize = 256; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x 1 1 1 1 1 i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + + +#------------------------------------------------------------ +# ATmega324P +#------------------------------------------------------------ + +# similar to ATmega164P + +part + id = "m324p"; + desc = "ATMEGA324P"; + has_jtag = yes; + stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one + avr910_devcode = 0x74; + signature = 0x1e 0x95 0x08; + pagel = 0xd7; + bs2 = 0xa0; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 4; /* for parallel programming */ + size = 1024; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 128; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 32768; + page_size = 128; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + + mode = 0x21; + delay = 6; + blocksize = 256; + readsize = 256; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x 1 1 1 1 1 i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + + +#------------------------------------------------------------ +# ATmega644 +#------------------------------------------------------------ + +# similar to ATmega164 + +part + id = "m644"; + desc = "ATMEGA644"; + has_jtag = yes; + stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one + avr910_devcode = 0x74; + signature = 0x1e 0x96 0x09; + pagel = 0xd7; + bs2 = 0xa0; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 6; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 2048; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 128; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 65536; + page_size = 256; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x21; + delay = 6; + blocksize = 256; + readsize = 256; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x 1 1 1 1 1 i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega644P +#------------------------------------------------------------ + +# similar to ATmega164p + +part + id = "m644p"; + desc = "ATMEGA644P"; + has_jtag = yes; + stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one + avr910_devcode = 0x74; + signature = 0x1e 0x96 0x0a; + pagel = 0xd7; + bs2 = 0xa0; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 6; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 2048; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 128; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 65536; + page_size = 256; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x21; + delay = 6; + blocksize = 256; + readsize = 256; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x 1 1 1 1 1 i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + + + +#------------------------------------------------------------ +# ATmega1284P +#------------------------------------------------------------ + +# similar to ATmega164p + +part + id = "m1284p"; + desc = "ATMEGA1284P"; + has_jtag = yes; + stk500_devcode = 0x82; # no STK500v1 support, use the ATmega16 one + avr910_devcode = 0x74; + signature = 0x1e 0x97 0x05; + pagel = 0xd7; + bs2 = 0xa0; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 6; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 4096; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 128; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 131072; + page_size = 256; + num_pages = 512; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 256; + readsize = 256; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x 1 1 1 1 1 i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + + + +#------------------------------------------------------------ +# ATmega162 +#------------------------------------------------------------ + +part + id = "m162"; + desc = "ATMEGA162"; + has_jtag = yes; + stk500_devcode = 0x83; + avr910_devcode = 0x63; + signature = 0x1e 0x94 0x04; + chip_erase_delay = 9000; + pagel = 0xd7; + bs2 = 0xa0; + + idr = 0x04; + spmcr = 0x57; + allowfullpagebitstream = yes; + + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + memory "flash" + paged = yes; + size = 16384; + page_size = 128; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + mode = 0x41; + delay = 10; + blocksize = 128; + readsize = 256; + + ; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 6; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 4; /* for parallel programming */ + size = 512; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + + read = " 1 0 1 0 0 0 0 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 20; + blocksize = 4; + readsize = 256; + ; + + memory "lfuse" + size = 1; + min_write_delay = 16000; + max_write_delay = 16000; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 16000; + max_write_delay = 16000; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "efuse" + size = 1; + min_write_delay = 16000; + max_write_delay = 16000; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x 1 1 1 1 1 i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 16000; + max_write_delay = 16000; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "signature" + size = 3; + + read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + + read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; +; + + + +#------------------------------------------------------------ +# ATmega163 +#------------------------------------------------------------ + +part + id = "m163"; + desc = "ATMEGA163"; + stk500_devcode = 0x81; + avr910_devcode = 0x64; + signature = 0x1e 0x94 0x02; + chip_erase_delay = 32000; + pagel = 0xd7; + bs2 = 0xa0; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 0; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 30; + programfusepulsewidth = 0; + programfusepolltimeout = 2; + programlockpulsewidth = 0; + programlockpolltimeout = 2; + + + memory "eeprom" + size = 512; + min_write_delay = 4000; + max_write_delay = 4000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + mode = 0x41; + delay = 20; + blocksize = 4; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 16384; + page_size = 128; + num_pages = 128; + min_write_delay = 16000; + max_write_delay = 16000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + + mode = 0x11; + delay = 20; + blocksize = 128; + readsize = 256; + ; + + memory "lfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o x x o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i 1 1 i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x x x x x 1 o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x 1 1 1 1 1 i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x 0 x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega169 +#------------------------------------------------------------ + +part + id = "m169"; + desc = "ATMEGA169"; + has_jtag = yes; + stk500_devcode = 0x85; + avr910_devcode = 0x78; + signature = 0x1e 0x94 0x05; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 4; /* for parallel programming */ + size = 512; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x a8", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 20; + blocksize = 4; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 16384; + page_size = 128; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 128; + readsize = 256; + ; + + memory "lfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; + + memory "lock" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega329 +#------------------------------------------------------------ + +part + id = "m329"; + desc = "ATMEGA329"; + has_jtag = yes; +# stk500_devcode = 0x85; # no STK500 support, only STK500v2 +# avr910_devcode = 0x?; # try the ATmega169 one: + avr910_devcode = 0x75; + signature = 0x1e 0x95 0x03; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 4; /* for parallel programming */ + size = 1024; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 20; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 32768; + page_size = 128; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "efuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega329P +#------------------------------------------------------------ +# Identical to ATmega329 except of the signature + +part + id = "m329p"; + desc = "ATMEGA329P"; + has_jtag = yes; +# stk500_devcode = 0x85; # no STK500 support, only STK500v2 +# avr910_devcode = 0x?; # try the ATmega169 one: + avr910_devcode = 0x75; + signature = 0x1e 0x95 0x0b; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 4; /* for parallel programming */ + size = 1024; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 20; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 32768; + page_size = 128; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "efuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega3290 +#------------------------------------------------------------ + +# identical to ATmega329 + +part + id = "m3290"; + desc = "ATMEGA3290"; + has_jtag = yes; +# stk500_devcode = 0x85; # no STK500 support, only STK500v2 +# avr910_devcode = 0x?; # try the ATmega169 one: + avr910_devcode = 0x75; + signature = 0x1e 0x95 0x04; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 4; /* for parallel programming */ + size = 1024; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a3 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 20; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 32768; + page_size = 128; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "efuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega3290P +#------------------------------------------------------------ + +# identical to ATmega3290 except of the signature + +part + id = "m3290p"; + desc = "ATMEGA3290P"; + has_jtag = yes; +# stk500_devcode = 0x85; # no STK500 support, only STK500v2 +# avr910_devcode = 0x?; # try the ATmega169 one: + avr910_devcode = 0x75; + signature = 0x1e 0x95 0x0c; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 4; /* for parallel programming */ + size = 1024; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a3 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 20; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 32768; + page_size = 128; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "efuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega649 +#------------------------------------------------------------ + +part + id = "m649"; + desc = "ATMEGA649"; + has_jtag = yes; +# stk500_devcode = 0x85; # no STK500 support, only STK500v2 +# avr910_devcode = 0x?; # try the ATmega169 one: + avr910_devcode = 0x75; + signature = 0x1e 0x96 0x03; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 2048; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 20; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 65536; + page_size = 256; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "efuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega6490 +#------------------------------------------------------------ + +# identical to ATmega649 + +part + id = "m6490"; + desc = "ATMEGA6490"; + has_jtag = yes; +# stk500_devcode = 0x85; # no STK500 support, only STK500v2 +# avr910_devcode = 0x?; # try the ATmega169 one: + avr910_devcode = 0x75; + signature = 0x1e 0x96 0x04; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 2048; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 20; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 65536; + page_size = 256; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "efuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega32 +#------------------------------------------------------------ + +part + id = "m32"; + desc = "ATMEGA32"; + has_jtag = yes; + stk500_devcode = 0x91; + avr910_devcode = 0x72; + signature = 0x1e 0x95 0x02; + chip_erase_delay = 9000; + pagel = 0xd7; + bs2 = 0xa0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 6; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + allowfullpagebitstream = yes; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 4; /* for parallel programming */ + size = 1024; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x04; + delay = 10; + blocksize = 64; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 32768; + page_size = 128; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + + mode = 0x21; + delay = 6; + blocksize = 64; + readsize = 256; + ; + + memory "lfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 4; + read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega161 +#------------------------------------------------------------ + +part + id = "m161"; + desc = "ATMEGA161"; + stk500_devcode = 0x80; + avr910_devcode = 0x60; + signature = 0x1e 0x94 0x01; + chip_erase_delay = 28000; + pagel = 0xd7; + bs2 = 0xa0; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 0; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 30; + programfusepulsewidth = 0; + programfusepolltimeout = 2; + programlockpulsewidth = 0; + programlockpolltimeout = 2; + + memory "eeprom" + size = 512; + min_write_delay = 3400; + max_write_delay = 3400; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + mode = 0x04; + delay = 5; + blocksize = 128; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 16384; + page_size = 128; + num_pages = 128; + min_write_delay = 14000; + max_write_delay = 14000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + + mode = 0x21; + delay = 16; + blocksize = 128; + readsize = 256; + ; + + memory "fuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 0 0 0 0 x x x x x x x x", + "x x x x x x x x x o x o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 x x x x x", + "x x x x x x x x 1 i 1 i i i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + +#------------------------------------------------------------ +# ATmega8 +#------------------------------------------------------------ + +part + id = "m8"; + desc = "ATMEGA8"; + stk500_devcode = 0x70; + avr910_devcode = 0x76; + signature = 0x1e 0x93 0x07; + pagel = 0xd7; + bs2 = 0xc2; + chip_erase_delay = 10000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 2; + resetdelayus = 0; + hvleavestabdelay = 15; + resetdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + size = 512; + page_size = 4; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + mode = 0x04; + delay = 20; + blocksize = 128; + readsize = 256; + ; + memory "flash" + paged = yes; + size = 8192; + page_size = 64; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0x00; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 0 x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 0 x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + + mode = 0x21; + delay = 10; + blocksize = 64; + readsize = 256; + ; + + memory "lfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "calibration" + size = 4; + read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + + +#------------------------------------------------------------ +# ATmega8515 +#------------------------------------------------------------ + +part + id = "m8515"; + desc = "ATMEGA8515"; + stk500_devcode = 0x63; + avr910_devcode = 0x3A; + signature = 0x1e 0x93 0x06; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 6; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + size = 512; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + mode = 0x04; + delay = 10; + blocksize = 128; + readsize = 256; + ; + memory "flash" + paged = yes; + size = 8192; + page_size = 64; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 0 x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 0 x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + + mode = 0x21; + delay = 6; + blocksize = 64; + readsize = 256; + ; + + memory "lfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "calibration" + size = 4; + read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + + + +#------------------------------------------------------------ +# ATmega8535 +#------------------------------------------------------------ + +part + id = "m8535"; + desc = "ATMEGA8535"; + stk500_devcode = 0x64; + avr910_devcode = 0x69; + signature = 0x1e 0x93 0x08; + pagel = 0xd7; + bs2 = 0xa0; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 6; + togglevtg = 0; + poweroffdelay = 0; + resetdelayms = 0; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + size = 512; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + mode = 0x04; + delay = 10; + blocksize = 128; + readsize = 256; + ; + memory "flash" + paged = yes; + size = 8192; + page_size = 64; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 0 x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 0 x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + + mode = 0x21; + delay = 6; + blocksize = 64; + readsize = 256; + ; + + memory "lfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "calibration" + size = 4; + read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + +#------------------------------------------------------------ +# ATtiny26 +#------------------------------------------------------------ + +part + id = "t26"; + desc = "ATTINY26"; + stk500_devcode = 0x21; + avr910_devcode = 0x5e; + signature = 0x1e 0x91 0x09; + pagel = 0xb3; + bs2 = 0xb2; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, + 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, + 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, + 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 2; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + size = 128; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 x x x x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 x x x x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + mode = 0x04; + delay = 10; + blocksize = 64; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 2048; + page_size = 32; + num_pages = 64; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x x x a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x x x a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 x x x x", + " x x x x x x x x"; + + mode = 0x21; + delay = 6; + blocksize = 16; + readsize = 256; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x x o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", + "x x x x x x x x x x x x x x x x"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x x x x i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x x x x o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 4; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + +; + + +#------------------------------------------------------------ +# ATtiny261 +#------------------------------------------------------------ +# Close to ATtiny26 + +part + id = "t261"; + desc = "ATTINY261"; + has_debugwire = yes; + flash_instr = 0xB4, 0x00, 0x10; + eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, + 0xBC, 0x00, 0xB4, 0x00, 0xBA, 0x0D, 0xBB, 0xBC, + 0x99, 0xE1, 0xBB, 0xAC; +# stk500_devcode = 0x21; +# avr910_devcode = 0x5e; + signature = 0x1e 0x91 0x0c; + pagel = 0xb3; + bs2 = 0xb2; + chip_erase_delay = 4000; + + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, + 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, + 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, + 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 2; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + paged = no; + size = 128; + page_size = 4; + num_pages = 32; + min_write_delay = 4000; + max_write_delay = 4000; + readback_p1 = 0xff; + readback_p2 = 0xff; + + read = "1 0 1 0 0 0 0 0 x x x x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 x x x x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x x", + " x a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 4; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 2048; + page_size = 32; + num_pages = 64; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x x x a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x x x a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 32; + readsize = 256; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x x o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", + "x x x x x x x x x x x x x x x x"; + min_write_delay = 4500; + max_write_delay = 4500; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 4500; + max_write_delay = 4500; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 4500; + max_write_delay = 4500; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x x i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x x x x x x x x o"; + min_write_delay = 4500; + max_write_delay = 4500; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + +; + + +#------------------------------------------------------------ +# ATtiny461 +#------------------------------------------------------------ +# Close to ATtiny261 + +part + id = "t461"; + desc = "ATTINY461"; + has_debugwire = yes; + flash_instr = 0xB4, 0x00, 0x10; + eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, + 0xBC, 0x00, 0xB4, 0x00, 0xBA, 0x0D, 0xBB, 0xBC, + 0x99, 0xE1, 0xBB, 0xAC; +# stk500_devcode = 0x21; +# avr910_devcode = 0x5e; + signature = 0x1e 0x92 0x08; + pagel = 0xb3; + bs2 = 0xb2; + chip_erase_delay = 4000; + + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, + 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, + 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, + 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 2; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + paged = no; + size = 256; + page_size = 4; + num_pages = 64; + min_write_delay = 4000; + max_write_delay = 4000; + readback_p1 = 0xff; + readback_p2 = 0xff; + + read = " 1 0 1 0 0 0 0 0 x x x x x x x x", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0 x x x x x x x x", + "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x x", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 4; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 4096; + page_size = 64; + num_pages = 64; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 64; + readsize = 256; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x x o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", + "x x x x x x x x x x x x x x x x"; + min_write_delay = 4500; + max_write_delay = 4500; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 4500; + max_write_delay = 4500; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 4500; + max_write_delay = 4500; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x x i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x x x x x x x x o"; + min_write_delay = 4500; + max_write_delay = 4500; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + +; + + +#------------------------------------------------------------ +# ATtiny861 +#------------------------------------------------------------ +# Close to ATtiny461 + +part + id = "t861"; + desc = "ATTINY861"; + has_debugwire = yes; + flash_instr = 0xB4, 0x00, 0x10; + eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, + 0xBC, 0x00, 0xB4, 0x00, 0xBA, 0x0D, 0xBB, 0xBC, + 0x99, 0xE1, 0xBB, 0xAC; +# stk500_devcode = 0x21; +# avr910_devcode = 0x5e; + signature = 0x1e 0x93 0x0d; + pagel = 0xb3; + bs2 = 0xb2; + chip_erase_delay = 4000; + + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 0; + + pp_controlstack = + 0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC, + 0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC, + 0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C, + 0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 2; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + paged = no; + size = 512; + num_pages = 128; + page_size = 4; + min_write_delay = 4000; + max_write_delay = 4000; + readback_p1 = 0xff; + readback_p2 = 0xff; + + read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x a8", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 4; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 8192; + page_size = 64; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 64; + readsize = 256; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x x o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", + "x x x x x x x x x x x x x x x x"; + min_write_delay = 4500; + max_write_delay = 4500; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 4500; + max_write_delay = 4500; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 4500; + max_write_delay = 4500; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x x i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x x x x x x x x o"; + min_write_delay = 4500; + max_write_delay = 4500; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + +; + + +#------------------------------------------------------------ +# ATmega48 +#------------------------------------------------------------ + +part + id = "m48"; + desc = "ATMEGA48"; + has_debugwire = yes; + flash_instr = 0xB6, 0x01, 0x11; + eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, + 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, + 0x99, 0xF9, 0xBB, 0xAF; + stk500_devcode = 0x59; +# avr910_devcode = 0x; + signature = 0x1e 0x92 0x05; + pagel = 0xd7; + bs2 = 0xc2; + chip_erase_delay = 45000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + resetdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + paged = no; + page_size = 4; + size = 256; + min_write_delay = 3600; + max_write_delay = 3600; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 0 x x x x x", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x x", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 5; + blocksize = 4; + readsize = 256; + ; + memory "flash" + paged = yes; + size = 4096; + page_size = 64; + num_pages = 64; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0x00; + readback_p2 = 0x00; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 0 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 0 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 0 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 64; + readsize = 256; + ; + + memory "lfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "efuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x x x x x x x x o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x x i"; + ; + + memory "lock" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + +#------------------------------------------------------------ +# ATmega88 +#------------------------------------------------------------ + +part + id = "m88"; + desc = "ATMEGA88"; + has_debugwire = yes; + flash_instr = 0xB6, 0x01, 0x11; + eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, + 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, + 0x99, 0xF9, 0xBB, 0xAF; + stk500_devcode = 0x73; +# avr910_devcode = 0x; + signature = 0x1e 0x93 0x0a; + pagel = 0xd7; + bs2 = 0xc2; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + resetdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + paged = no; + page_size = 4; + size = 512; + min_write_delay = 3600; + max_write_delay = 3600; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 0 x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 0 x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x a8", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 5; + blocksize = 4; + readsize = 256; + ; + memory "flash" + paged = yes; + size = 8192; + page_size = 64; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 64; + readsize = 256; + ; + + memory "lfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "efuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x x x x x x o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega168 +#------------------------------------------------------------ + +part + id = "m168"; + desc = "ATMEGA168"; + has_debugwire = yes; + flash_instr = 0xB6, 0x01, 0x11; + eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, + 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, + 0x99, 0xF9, 0xBB, 0xAF; + stk500_devcode = 0x86; + # avr910_devcode = 0x; + signature = 0x1e 0x94 0x06; + pagel = 0xd7; + bs2 = 0xc2; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + resetdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + paged = no; + page_size = 4; + size = 512; + min_write_delay = 3600; + max_write_delay = 3600; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 0 x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 0 x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x a8", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 5; + blocksize = 4; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 16384; + page_size = 128; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 128; + readsize = 256; + + ; + + memory "lfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "efuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x x x x x x o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; +; + +#------------------------------------------------------------ +# ATtiny88 +#------------------------------------------------------------ + +part + id = "t88"; + desc = "attiny88"; + has_debugwire = yes; + flash_instr = 0xB6, 0x01, 0x11; + eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, + 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, + 0x99, 0xF9, 0xBB, 0xAF; + stk500_devcode = 0x73; +# avr910_devcode = 0x; + signature = 0x1e 0x93 0x11; + pagel = 0xd7; + bs2 = 0xc2; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + resetdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + paged = no; + page_size = 4; + size = 64; + min_write_delay = 3600; + max_write_delay = 3600; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 0 x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x x", + " x a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 5; + blocksize = 4; + readsize = 64; + ; + memory "flash" + paged = yes; + size = 8192; + page_size = 64; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 64; + readsize = 256; + ; + + memory "lfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "efuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x x x x x x o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x x i"; + ; + + memory "lock" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega328P +#------------------------------------------------------------ + +part + id = "m328p"; + desc = "ATMEGA328P"; + has_debugwire = yes; + flash_instr = 0xB6, 0x01, 0x11; + eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, + 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, + 0x99, 0xF9, 0xBB, 0xAF; + stk500_devcode = 0x86; + # avr910_devcode = 0x; + signature = 0x1e 0x95 0x0F; + pagel = 0xd7; + bs2 = 0xc2; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + resetdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + paged = no; + page_size = 4; + size = 1024; + min_write_delay = 3600; + max_write_delay = 3600; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 0 x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 0 x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 5; + blocksize = 4; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 32768; + page_size = 128; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 128; + readsize = 256; + + ; + + memory "lfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "efuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x x x x x x o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; +; + +#------------------------------------------------------------ +# ATtiny2313 +#------------------------------------------------------------ + +part + id = "t2313"; + desc = "ATtiny2313"; + has_debugwire = yes; + flash_instr = 0xB2, 0x0F, 0x1F; + eeprom_instr = 0xBB, 0xFE, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, + 0xBA, 0x0F, 0xB2, 0x0F, 0xBA, 0x0D, 0xBB, 0xBC, + 0x99, 0xE1, 0xBB, 0xAC; + stk500_devcode = 0x23; +## Use the ATtiny26 devcode: + avr910_devcode = 0x5e; + signature = 0x1e 0x91 0x0a; + pagel = 0xD4; + bs2 = 0xD6; + reset = io; + chip_erase_delay = 9000; + + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0E, 0x1E, 0x2E, 0x3E, 0x2E, 0x3E, + 0x4E, 0x5E, 0x4E, 0x5E, 0x6E, 0x7E, 0x6E, 0x7E, + 0x26, 0x36, 0x66, 0x76, 0x2A, 0x3A, 0x6A, 0x7A, + 0x2E, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + size = 128; + paged = no; + page_size = 4; + min_write_delay = 4000; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x x", + " x a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 4; + readsize = 256; + ; + memory "flash" + paged = yes; + size = 2048; + page_size = 32; + num_pages = 64; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 0 0 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 0 0 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + +# The information in the data sheet of April/2004 is wrong, this works: + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x x a3 a2 a1 a0", + " i i i i i i i i"; + +# The information in the data sheet of April/2004 is wrong, this works: + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x x a3 a2 a1 a0", + " i i i i i i i i"; + +# The information in the data sheet of April/2004 is wrong, this works: + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 0 0 a9 a8", + " a7 a6 a5 a4 x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 32; + readsize = 256; + ; +# ATtiny2313 has Signature Bytes: 0x1E 0x91 0x0A. + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "lock" + size = 1; + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x x i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; +# The Tiny2313 has calibration data for both 4 MHz and 8 MHz. +# The information in the data sheet of April/2004 is wrong, this works: + + memory "calibration" + size = 2; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# AT90PWM2 +#------------------------------------------------------------ + +part + id = "pwm2"; + desc = "AT90PWM2"; + has_debugwire = yes; + flash_instr = 0xB6, 0x01, 0x11; + eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, + 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, + 0x99, 0xF9, 0xBB, 0xAF; + stk500_devcode = 0x65; +## avr910_devcode = ?; + signature = 0x1e 0x93 0x81; + pagel = 0xD8; + bs2 = 0xE2; + reset = io; + chip_erase_delay = 9000; + + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + size = 512; + paged = no; + page_size = 4; + min_write_delay = 4000; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x x", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 4; + readsize = 256; + ; + memory "flash" + paged = yes; + size = 8192; + page_size = 64; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 64; + readsize = 256; + ; +# AT90PWM2 has Signature Bytes: 0x1E 0x93 0x81. + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "lock" + size = 1; + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x x i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# AT90PWM3 +#------------------------------------------------------------ + +# Completely identical to AT90PWM2 (including the signature!) + +part + id = "pwm3"; + desc = "AT90PWM3"; + has_debugwire = yes; + flash_instr = 0xB6, 0x01, 0x11; + eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, + 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, + 0x99, 0xF9, 0xBB, 0xAF; + stk500_devcode = 0x65; +## avr910_devcode = ?; + signature = 0x1e 0x93 0x81; + pagel = 0xD8; + bs2 = 0xE2; + reset = io; + chip_erase_delay = 9000; + + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + size = 512; + paged = no; + page_size = 4; + min_write_delay = 4000; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x x", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 4; + readsize = 256; + ; + memory "flash" + paged = yes; + size = 8192; + page_size = 64; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 64; + readsize = 256; + ; +# AT90PWM2 has Signature Bytes: 0x1E 0x93 0x81. + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "lock" + size = 1; + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x x i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# AT90PWM2B +#------------------------------------------------------------ +# Same as AT90PWM2 but different signature. + +part + id = "pwm2b"; + desc = "AT90PWM2B"; + has_debugwire = yes; + flash_instr = 0xB6, 0x01, 0x11; + eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, + 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, + 0x99, 0xF9, 0xBB, 0xAF; + stk500_devcode = 0x65; +## avr910_devcode = ?; + signature = 0x1e 0x93 0x83; + pagel = 0xD8; + bs2 = 0xE2; + reset = io; + chip_erase_delay = 9000; + + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + size = 512; + paged = no; + page_size = 4; + min_write_delay = 4000; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x x", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 4; + readsize = 256; + ; + memory "flash" + paged = yes; + size = 8192; + page_size = 64; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 64; + readsize = 256; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "lock" + size = 1; + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x x i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# AT90PWM3B +#------------------------------------------------------------ + +# Completely identical to AT90PWM2B (including the signature!) + +part + id = "pwm3b"; + desc = "AT90PWM3B"; + has_debugwire = yes; + flash_instr = 0xB6, 0x01, 0x11; + eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00, + 0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF, + 0x99, 0xF9, 0xBB, 0xAF; + stk500_devcode = 0x65; +## avr910_devcode = ?; + signature = 0x1e 0x93 0x83; + pagel = 0xD8; + bs2 = 0xE2; + reset = io; + chip_erase_delay = 9000; + + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + size = 512; + paged = no; + page_size = 4; + min_write_delay = 4000; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x x", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 4; + readsize = 256; + ; + memory "flash" + paged = yes; + size = 8192; + page_size = 64; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 64; + readsize = 256; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "lock" + size = 1; + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x x i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATtiny25 +#------------------------------------------------------------ + +part + id = "t25"; + desc = "ATtiny25"; + has_debugwire = yes; + flash_instr = 0xB4, 0x02, 0x12; + eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, + 0xBC, 0x02, 0xB4, 0x02, 0xBA, 0x0D, 0xBB, 0xBC, + 0x99, 0xE1, 0xBB, 0xAC; +## no STK500 devcode in XML file, use the ATtiny45 one + stk500_devcode = 0x14; +## avr910_devcode = ?; +## Try the AT90S2313 devcode: + avr910_devcode = 0x20; + signature = 0x1e 0x91 0x08; + reset = io; + chip_erase_delay = 4500; + + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + hvsp_controlstack = + 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, + 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, + 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, + 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; + hventerstabdelay = 100; + hvspcmdexedelay = 0; + synchcycles = 6; + latchcycles = 1; + togglevtg = 1; + poweroffdelay = 25; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 100; + resetdelay = 25; + chiperasepolltimeout = 40; + chiperasetime = 0; + programfusepolltimeout = 25; + programlockpolltimeout = 25; + + memory "eeprom" + size = 128; + paged = no; + page_size = 4; + min_write_delay = 4000; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x x", + " x a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 4; + readsize = 256; + ; + memory "flash" + paged = yes; + size = 2048; + page_size = 32; + num_pages = 64; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 0 0 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 0 0 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x x a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x x a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 0 0 a9 a8", + " a7 a6 a5 a4 x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 32; + readsize = 256; + ; +# ATtiny25 has Signature Bytes: 0x1E 0x91 0x08. + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "lock" + size = 1; + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x x i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 2; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATtiny45 +#------------------------------------------------------------ + +part + id = "t45"; + desc = "ATtiny45"; + has_debugwire = yes; + flash_instr = 0xB4, 0x02, 0x12; + eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, + 0xBC, 0x02, 0xB4, 0x02, 0xBA, 0x0D, 0xBB, 0xBC, + 0x99, 0xE1, 0xBB, 0xAC; + stk500_devcode = 0x14; +## avr910_devcode = ?; +## Try the AT90S2313 devcode: + avr910_devcode = 0x20; + signature = 0x1e 0x92 0x06; + reset = io; + chip_erase_delay = 4500; + + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + hvsp_controlstack = + 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, + 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, + 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, + 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + hvspcmdexedelay = 0; + synchcycles = 6; + latchcycles = 1; + togglevtg = 1; + poweroffdelay = 25; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 100; + resetdelay = 25; + chiperasepolltimeout = 40; + chiperasetime = 0; + programfusepolltimeout = 25; + programlockpolltimeout = 25; + + memory "eeprom" + size = 256; + page_size = 4; + min_write_delay = 4000; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", + "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x x", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 4; + readsize = 256; + ; + memory "flash" + paged = yes; + size = 4096; + page_size = 64; + num_pages = 64; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 0 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 0 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 0 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 32; + readsize = 256; + ; +# ATtiny45 has Signature Bytes: 0x1E 0x92 0x08. (Data sheet 2586C-AVR-06/05 (doc2586.pdf) indicates otherwise!) + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "lock" + size = 1; + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x x i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 2; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATtiny85 +#------------------------------------------------------------ + +part + id = "t85"; + desc = "ATtiny85"; + has_debugwire = yes; + flash_instr = 0xB4, 0x02, 0x12; + eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, + 0xBC, 0x02, 0xB4, 0x02, 0xBA, 0x0D, 0xBB, 0xBC, + 0x99, 0xE1, 0xBB, 0xAC; +## no STK500 devcode in XML file, use the ATtiny45 one + stk500_devcode = 0x14; +## avr910_devcode = ?; +## Try the AT90S2313 devcode: + avr910_devcode = 0x20; + signature = 0x1e 0x93 0x0b; + reset = io; + chip_erase_delay = 4500; + + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + hvsp_controlstack = + 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, + 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, + 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, + 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00; + hventerstabdelay = 100; + hvspcmdexedelay = 0; + synchcycles = 6; + latchcycles = 1; + togglevtg = 1; + poweroffdelay = 25; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 100; + resetdelay = 25; + chiperasepolltimeout = 40; + chiperasetime = 0; + programfusepolltimeout = 25; + programlockpolltimeout = 25; + + memory "eeprom" + size = 512; + paged = no; + page_size = 4; + min_write_delay = 4000; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", + "a8 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x a8", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 4; + readsize = 256; + ; + memory "flash" + paged = yes; + size = 8192; + page_size = 64; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 32; + readsize = 256; + ; +# ATtiny85 has Signature Bytes: 0x1E 0x93 0x08. + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "lock" + size = 1; + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x x i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 2; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega640 +#------------------------------------------------------------ +# Almost same as ATmega1280, except for different memory sizes + +part + id = "m640"; + desc = "ATMEGA640"; + signature = 0x1e 0x96 0x08; + has_jtag = yes; +# stk500_devcode = 0xB2; +# avr910_devcode = 0x43; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + rampz = 0x3b; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 4096; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0x00; + read = " 1 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 65536; + page_size = 256; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0x00; + readback_p2 = 0x00; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega1280 +#------------------------------------------------------------ + +part + id = "m1280"; + desc = "ATMEGA1280"; + signature = 0x1e 0x97 0x03; + has_jtag = yes; +# stk500_devcode = 0xB2; +# avr910_devcode = 0x43; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + rampz = 0x3b; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 4096; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0x00; + read = " 1 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 131072; + page_size = 256; + num_pages = 512; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0x00; + readback_p2 = 0x00; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega1281 +#------------------------------------------------------------ +# Identical to ATmega1280 + +part + id = "m1281"; + desc = "ATMEGA1281"; + signature = 0x1e 0x97 0x04; + has_jtag = yes; +# stk500_devcode = 0xB2; +# avr910_devcode = 0x43; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + rampz = 0x3b; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 4096; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0x00; + read = " 1 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 131072; + page_size = 256; + num_pages = 512; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0x00; + readback_p2 = 0x00; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega2560 +#------------------------------------------------------------ + +part + id = "m2560"; + desc = "ATMEGA2560"; + signature = 0x1e 0x98 0x01; + has_jtag = yes; +# stk500_devcode = 0xB2; +# avr910_devcode = 0x43; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + rampz = 0x3b; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 4096; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0x00; + read = " 1 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 262144; + page_size = 256; + num_pages = 1024; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0x00; + readback_p2 = 0x00; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + load_ext_addr = " 0 1 0 0 1 1 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 0 a16", + " 0 0 0 0 0 0 0 0"; + + mode = 0x41; + delay = 10; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega2561 +#------------------------------------------------------------ + +part + id = "m2561"; + desc = "ATMEGA2561"; + signature = 0x1e 0x98 0x02; + has_jtag = yes; +# stk500_devcode = 0xB2; +# avr910_devcode = 0x43; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + rampz = 0x3b; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 4096; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0x00; + read = " 1 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 262144; + page_size = 256; + num_pages = 1024; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0x00; + readback_p2 = 0x00; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + load_ext_addr = " 0 1 0 0 1 1 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 0 a16", + " 0 0 0 0 0 0 0 0"; + + mode = 0x41; + delay = 10; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega128RFA1 +#------------------------------------------------------------ +# Identical to ATmega2561 but half the ROM + +part + id = "m128rfa1"; + desc = "ATMEGA128RFA1"; + signature = 0x1e 0xa7 0x01; + has_jtag = yes; +# stk500_devcode = 0xB2; +# avr910_devcode = 0x43; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xE2; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + rampz = 0x3b; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 4096; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0x00; + read = " 1 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 131072; + page_size = 256; + num_pages = 512; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0x00; + readback_p2 = 0x00; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATtiny24 +#------------------------------------------------------------ + +part + id = "t24"; + desc = "ATtiny24"; + has_debugwire = yes; + flash_instr = 0xB4, 0x07, 0x17; + eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, + 0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC, + 0x99, 0xE1, 0xBB, 0xAC; +## no STK500 devcode in XML file, use the ATtiny45 one + stk500_devcode = 0x14; +## avr910_devcode = ?; +## Try the AT90S2313 devcode: + avr910_devcode = 0x20; + signature = 0x1e 0x91 0x0b; + reset = io; + chip_erase_delay = 4500; + + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + hvsp_controlstack = + 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, + 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, + 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, + 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0F; + hventerstabdelay = 100; + hvspcmdexedelay = 0; + synchcycles = 6; + latchcycles = 1; + togglevtg = 1; + poweroffdelay = 25; + resetdelayms = 0; + resetdelayus = 70; + hvleavestabdelay = 100; + resetdelay = 25; + chiperasepolltimeout = 40; + chiperasetime = 0; + programfusepolltimeout = 25; + programlockpolltimeout = 25; + + memory "eeprom" + size = 128; + paged = no; + page_size = 4; + min_write_delay = 4000; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x x", + " x a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 4; + readsize = 256; + ; + memory "flash" + paged = yes; + size = 2048; + page_size = 32; + num_pages = 64; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 0 0 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 0 0 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x x a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x x a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 0 0 a9 a8", + " a7 a6 a5 a4 x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 32; + readsize = 256; + ; +# ATtiny24 has Signature Bytes: 0x1E 0x91 0x0B. + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "lock" + size = 1; + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x x x x x x x i i"; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x x i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATtiny44 +#------------------------------------------------------------ + +part + id = "t44"; + desc = "ATtiny44"; + has_debugwire = yes; + flash_instr = 0xB4, 0x07, 0x17; + eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, + 0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC, + 0x99, 0xE1, 0xBB, 0xAC; +## no STK500 devcode in XML file, use the ATtiny45 one + stk500_devcode = 0x14; +## avr910_devcode = ?; +## Try the AT90S2313 devcode: + avr910_devcode = 0x20; + signature = 0x1e 0x92 0x07; + reset = io; + chip_erase_delay = 4500; + + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + hvsp_controlstack = + 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, + 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, + 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, + 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0F; + hventerstabdelay = 100; + hvspcmdexedelay = 0; + synchcycles = 6; + latchcycles = 1; + togglevtg = 1; + poweroffdelay = 25; + resetdelayms = 0; + resetdelayus = 70; + hvleavestabdelay = 100; + resetdelay = 25; + chiperasepolltimeout = 40; + chiperasetime = 0; + programfusepolltimeout = 25; + programlockpolltimeout = 25; + + memory "eeprom" + size = 256; + paged = no; + page_size = 4; + min_write_delay = 4000; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", + "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x x", + " x a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 4; + readsize = 256; + ; + memory "flash" + paged = yes; + size = 4096; + page_size = 64; + num_pages = 64; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 0 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 0 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 0 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 32; + readsize = 256; + ; +# ATtiny44 has Signature Bytes: 0x1E 0x92 0x07. + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "lock" + size = 1; + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x x x x x x x i i"; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x x i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATtiny84 +#------------------------------------------------------------ + +part + id = "t84"; + desc = "ATtiny84"; + has_debugwire = yes; + flash_instr = 0xB4, 0x07, 0x17; + eeprom_instr = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D, + 0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC, + 0x99, 0xE1, 0xBB, 0xAC; +## no STK500 devcode in XML file, use the ATtiny45 one + stk500_devcode = 0x14; +## avr910_devcode = ?; +## Try the AT90S2313 devcode: + avr910_devcode = 0x20; + signature = 0x1e 0x93 0x0c; + reset = io; + chip_erase_delay = 4500; + + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + hvsp_controlstack = + 0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66, + 0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78, + 0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10, + 0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0F; + hventerstabdelay = 100; + hvspcmdexedelay = 0; + synchcycles = 6; + latchcycles = 1; + togglevtg = 1; + poweroffdelay = 25; + resetdelayms = 0; + resetdelayus = 70; + hvleavestabdelay = 100; + resetdelay = 25; + chiperasepolltimeout = 40; + chiperasetime = 0; + programfusepolltimeout = 25; + programlockpolltimeout = 25; + + memory "eeprom" + size = 512; + paged = no; + page_size = 4; + min_write_delay = 4000; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 0 0 0 x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 0 0 0 x x x x a8", + "a8 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x x x x", + " x a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 4; + readsize = 256; + ; + memory "flash" + paged = yes; + size = 8192; + page_size = 64; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 32; + readsize = 256; + ; +# ATtiny84 has Signature Bytes: 0x1E 0x93 0x0C. + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "lock" + size = 1; + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x x x x x x x i i"; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x x i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega32u4 +#------------------------------------------------------------ + +part + id = "m32u4"; + desc = "ATmega32U4"; + signature = 0x1e 0x95 0x87; + has_jtag = yes; +# stk500_devcode = 0xB2; +# avr910_devcode = 0x43; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + rampz = 0x3b; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 1024; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0x00; + read = " 1 0 1 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 32768; + page_size = 128; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0x00; + readback_p2 = 0x00; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 128; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# AT90USB646 +#------------------------------------------------------------ + +part + id = "usb646"; + desc = "AT90USB646"; + signature = 0x1e 0x96 0x82; + has_jtag = yes; +# stk500_devcode = 0xB2; +# avr910_devcode = 0x43; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + rampz = 0x3b; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 2048; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0x00; + read = " 1 0 1 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 65536; + page_size = 256; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0x00; + readback_p2 = 0x00; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# AT90USB647 +#------------------------------------------------------------ +# identical to AT90USB646 + +part + id = "usb647"; + desc = "AT90USB647"; + signature = 0x1e 0x96 0x82; + has_jtag = yes; +# stk500_devcode = 0xB2; +# avr910_devcode = 0x43; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + rampz = 0x3b; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 2048; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0x00; + read = " 1 0 1 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 65536; + page_size = 256; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0x00; + readback_p2 = 0x00; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# AT90USB1286 +#------------------------------------------------------------ + +part + id = "usb1286"; + desc = "AT90USB1286"; + signature = 0x1e 0x97 0x82; + has_jtag = yes; +# stk500_devcode = 0xB2; +# avr910_devcode = 0x43; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + rampz = 0x3b; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 4096; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0x00; + read = " 1 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 131072; + page_size = 256; + num_pages = 512; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0x00; + readback_p2 = 0x00; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# AT90USB1287 +#------------------------------------------------------------ +# identical to AT90USB1286 + +part + id = "usb1287"; + desc = "AT90USB1287"; + signature = 0x1e 0x97 0x82; + has_jtag = yes; +# stk500_devcode = 0xB2; +# avr910_devcode = 0x43; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + rampz = 0x3b; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 4096; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0x00; + read = " 1 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 x x x a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 131072; + page_size = 256; + num_pages = 512; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0x00; + readback_p2 = 0x00; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 256; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + +#------------------------------------------------------------ +# AT90USB162 +#------------------------------------------------------------ + +part + id = "usb162"; + desc = "AT90USB162"; + has_jtag = no; + has_debugwire = yes; + signature = 0x1e 0x94 0x82; + chip_erase_delay = 9000; + reset = io; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + pagel = 0xD7; + bs2 = 0xC6; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 4; /* for parallel programming */ + size = 512; + num_pages = 128; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0x00; + read = " 1 0 1 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 20; + blocksize = 4; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 16384; + page_size = 128; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0x00; + readback_p2 = 0x00; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 128; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# AT90USB82 +#------------------------------------------------------------ +# Changes against AT90USB162 (beside IDs) +# memory "flash" +# size = 8192; +# num_pages = 64; + +part + id = "usb82"; + desc = "AT90USB82"; + has_jtag = no; + has_debugwire = yes; + signature = 0x1e 0x93 0x82; + chip_erase_delay = 9000; + reset = io; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + pagel = 0xD7; + bs2 = 0xC6; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 4; /* for parallel programming */ + size = 512; + num_pages = 128; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0x00; + read = " 1 0 1 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 20; + blocksize = 4; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 8192; + page_size = 128; + num_pages = 64; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0x00; + readback_p2 = 0x00; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + + mode = 0x41; + delay = 6; + blocksize = 128; + readsize = 256; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega325 +#------------------------------------------------------------ + +part + id = "m325"; + desc = "ATMEGA325"; + signature = 0x1e 0x95 0x05; + has_jtag = yes; +# stk500_devcode = 0x??; # No STK500v1 support? +# avr910_devcode = 0x??; # Try the ATmega16 one + avr910_devcode = 0x74; + pagel = 0xd7; + bs2 = 0xa0; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 4; /* for parallel programming */ + size = 1024; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 0 0 0 0 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 0 0 0 0 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 0 0 0 0 a9 a8", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 4; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 32768; + page_size = 128; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 0 0 0 0 0", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 0 0 0 0 0", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 128; + readsize = 256; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0", + "0 0 0 0 0 0 0 0 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "0 0 0 0 0 0 0 0 i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "0 0 0 0 0 0 0 0 i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "0 0 0 0 0 0 0 0 1 1 1 1 1 i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + + read = "0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega645 +#------------------------------------------------------------ + +part + id = "m645"; + desc = "ATMEGA645"; + signature = 0x1E 0x96 0x05; + has_jtag = yes; +# stk500_devcode = 0x??; # No STK500v1 support? +# avr910_devcode = 0x??; # Try the ATmega16 one + avr910_devcode = 0x74; + pagel = 0xd7; + bs2 = 0xa0; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 2048; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 0 0 0 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 0 0 0 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 0 0 0 a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 8; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 65536; + page_size = 256; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 0 0 0 0 0", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 0 0 0 0 0", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " 0 0 0 0 0 0 0 0"; + + mode = 0x41; + delay = 10; + blocksize = 128; + readsize = 256; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0", + "0 0 0 0 0 0 0 0 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "0 0 0 0 0 0 0 0 i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "0 0 0 0 0 0 0 0 i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "0 0 0 0 0 0 0 0 1 1 1 1 1 i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + + read = "0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega3250 +#------------------------------------------------------------ + +part + id = "m3250"; + desc = "ATMEGA3250"; + signature = 0x1E 0x95 0x06; + has_jtag = yes; +# stk500_devcode = 0x??; # No STK500v1 support? +# avr910_devcode = 0x??; # Try the ATmega16 one + avr910_devcode = 0x74; + pagel = 0xd7; + bs2 = 0xa0; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 4; /* for parallel programming */ + size = 1024; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 0 0 0 0 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 0 0 0 0 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 0 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 0 0 0 0 a9 a8", + " a7 a6 a5 a4 a3 a2 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 4; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 32768; + page_size = 128; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 0 0 0 0 0", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 0 0 0 0 0", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 128; + readsize = 256; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0", + "0 0 0 0 0 0 0 0 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "0 0 0 0 0 0 0 0 i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "0 0 0 0 0 0 0 0 i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "0 0 0 0 0 0 0 0 1 1 1 1 1 i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + + read = "0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega6450 +#------------------------------------------------------------ + +part + id = "m6450"; + desc = "ATMEGA6450"; + signature = 0x1E 0x96 0x06; + has_jtag = yes; +# stk500_devcode = 0x??; # No STK500v1 support? +# avr910_devcode = 0x??; # Try the ATmega16 one + avr910_devcode = 0x74; + pagel = 0xd7; + bs2 = 0xa0; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; + + timeout = 200; + stabdelay = 100; + cmdexedelay = 25; + synchloops = 32; + bytedelay = 0; + pollindex = 3; + pollvalue = 0x53; + predelay = 1; + postdelay = 1; + pollmethod = 1; + + pp_controlstack = + 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F, + 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F, + 0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B, + 0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00; + hventerstabdelay = 100; + progmodedelay = 0; + latchcycles = 5; + togglevtg = 1; + poweroffdelay = 15; + resetdelayms = 1; + resetdelayus = 0; + hvleavestabdelay = 15; + chiperasepulsewidth = 0; + chiperasepolltimeout = 10; + programfusepulsewidth = 0; + programfusepolltimeout = 5; + programlockpulsewidth = 0; + programlockpolltimeout = 5; + + idr = 0x31; + spmcr = 0x57; + allowfullpagebitstream = no; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 2048; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 0 0 0 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 0 0 0 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_lo = " 1 1 0 0 0 0 0 1", + " 0 0 0 0 0 0 0 0", + " 0 0 0 0 0 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 1 1 0 0 0 0 1 0", + " 0 0 0 0 0 a10 a9 a8", + " a7 a6 a5 a4 a3 0 0 0", + " x x x x x x x x"; + + mode = 0x41; + delay = 10; + blocksize = 4; + readsize = 256; + ; + + memory "flash" + paged = yes; + size = 65536; + page_size = 256; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 0 0 0 0 0", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 0 0 0 0 0", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " 0 0 0 0 0 0 0 0"; + + mode = 0x41; + delay = 10; + blocksize = 128; + readsize = 256; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0", + "0 0 0 0 0 0 0 0 1 1 i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "lfuse" + size = 1; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "0 0 0 0 0 0 0 0 i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "hfuse" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "0 0 0 0 0 0 0 0 i i i i i i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "efuse" + size = 1; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "0 0 0 0 0 0 0 0 1 1 1 1 1 i i i"; + min_write_delay = 9000; + max_write_delay = 9000; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + + read = "0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATXMEGA64A1 +#------------------------------------------------------------ + +part + id = "x64a1"; + desc = "ATXMEGA64A1"; + signature = 0x1e 0x96 0x4e; + has_jtag = yes; + has_pdi = yes; + nvm_base = 0x01c0; + + memory "eeprom" + size = 0x0800; + offset = 0x08c0000; + page_size = 0x20; + readsize = 0x100; + ; + + memory "application" + size = 0x00010000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "apptable" + size = 0x00001000; + offset = 0x0080f000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "boot" + size = 0x00001000; + offset = 0x00810000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "flash" + size = 0x00011000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "prodsig" + size = 0x200; + offset = 0x8e0200; + page_size = 0x100; + readsize = 0x100; + ; + + memory "usersig" + size = 0x200; + offset = 0x8e0400; + page_size = 0x100; + readsize = 0x100; + ; + + memory "signature" + size = 3; + offset = 0x1000090; + ; + + memory "fuse0" + size = 1; + offset = 0x8f0020; + ; + + memory "fuse1" + size = 1; + offset = 0x8f0021; + ; + + memory "fuse2" + size = 1; + offset = 0x8f0022; + ; + + memory "fuse4" + size = 1; + offset = 0x8f0024; + ; + + memory "fuse5" + size = 1; + offset = 0x8f0025; + ; + + memory "lock" + size = 1; + offset = 0x8f0027; + ; +; + +#------------------------------------------------------------ +# ATXMEGA128A1 +#------------------------------------------------------------ + +part + id = "x128a1"; + desc = "ATXMEGA128A1"; + signature = 0x1e 0x97 0x4c; + has_jtag = yes; + has_pdi = yes; + nvm_base = 0x01c0; + + memory "eeprom" + size = 0x0800; + offset = 0x08c0000; + page_size = 0x20; + readsize = 0x100; + ; + + memory "application" + size = 0x00020000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "apptable" + size = 0x00002000; + offset = 0x0081e000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "boot" + size = 0x00002000; + offset = 0x00820000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "flash" + size = 0x00022000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "prodsig" + size = 0x200; + offset = 0x8e0200; + page_size = 0x100; + readsize = 0x100; + ; + + memory "usersig" + size = 0x200; + offset = 0x8e0400; + page_size = 0x100; + readsize = 0x100; + ; + + memory "signature" + size = 3; + offset = 0x1000090; + ; + + memory "fuse0" + size = 1; + offset = 0x8f0020; + ; + + memory "fuse1" + size = 1; + offset = 0x8f0021; + ; + + memory "fuse2" + size = 1; + offset = 0x8f0022; + ; + + memory "fuse4" + size = 1; + offset = 0x8f0024; + ; + + memory "fuse5" + size = 1; + offset = 0x8f0025; + ; + + memory "lock" + size = 1; + offset = 0x8f0027; + ; +; + +#------------------------------------------------------------ +# ATXMEGA128A1REVD +#------------------------------------------------------------ + +part + id = "x128a1d"; + desc = "ATXMEGA128A1REVD"; + signature = 0x1e 0x97 0x41; + has_jtag = yes; + has_pdi = yes; + nvm_base = 0x01c0; + + memory "eeprom" + size = 0x0800; + offset = 0x08c0000; + page_size = 0x20; + readsize = 0x100; + ; + + memory "application" + size = 0x00020000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "apptable" + size = 0x00002000; + offset = 0x0081e000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "boot" + size = 0x00002000; + offset = 0x00820000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "flash" + size = 0x00022000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "prodsig" + size = 0x200; + offset = 0x8e0200; + page_size = 0x100; + readsize = 0x100; + ; + + memory "usersig" + size = 0x200; + offset = 0x8e0400; + page_size = 0x100; + readsize = 0x100; + ; + + memory "signature" + size = 3; + offset = 0x1000090; + ; + + memory "fuse0" + size = 1; + offset = 0x8f0020; + ; + + memory "fuse1" + size = 1; + offset = 0x8f0021; + ; + + memory "fuse2" + size = 1; + offset = 0x8f0022; + ; + + memory "fuse4" + size = 1; + offset = 0x8f0024; + ; + + memory "fuse5" + size = 1; + offset = 0x8f0025; + ; + + memory "lock" + size = 1; + offset = 0x8f0027; + ; +; + +#------------------------------------------------------------ +# ATXMEGA192A1 +#------------------------------------------------------------ + +part + id = "x192a1"; + desc = "ATXMEGA192A1"; + signature = 0x1e 0x97 0x4e; + has_jtag = yes; + has_pdi = yes; + nvm_base = 0x01c0; + + memory "eeprom" + size = 0x0800; + offset = 0x08c0000; + page_size = 0x20; + readsize = 0x100; + ; + + memory "application" + size = 0x00030000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "apptable" + size = 0x00002000; + offset = 0x0082e000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "boot" + size = 0x00002000; + offset = 0x00830000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "flash" + size = 0x00032000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "prodsig" + size = 0x200; + offset = 0x8e0200; + page_size = 0x100; + readsize = 0x100; + ; + + memory "usersig" + size = 0x200; + offset = 0x8e0400; + page_size = 0x100; + readsize = 0x100; + ; + + memory "signature" + size = 3; + offset = 0x1000090; + ; + + memory "fuse0" + size = 1; + offset = 0x8f0020; + ; + + memory "fuse1" + size = 1; + offset = 0x8f0021; + ; + + memory "fuse2" + size = 1; + offset = 0x8f0022; + ; + + memory "fuse4" + size = 1; + offset = 0x8f0024; + ; + + memory "fuse5" + size = 1; + offset = 0x8f0025; + ; + + memory "lock" + size = 1; + offset = 0x8f0027; + ; +; + +#------------------------------------------------------------ +# ATXMEGA256A1 +#------------------------------------------------------------ + +part + id = "x256a1"; + desc = "ATXMEGA256A1"; + signature = 0x1e 0x98 0x46; + has_jtag = yes; + has_pdi = yes; + nvm_base = 0x01c0; + + memory "eeprom" + size = 0x1000; + offset = 0x08c0000; + page_size = 0x20; + readsize = 0x100; + ; + + memory "application" + size = 0x00040000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "apptable" + size = 0x00002000; + offset = 0x0083e000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "boot" + size = 0x00002000; + offset = 0x00840000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "flash" + size = 0x00042000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "prodsig" + size = 0x200; + offset = 0x8e0200; + page_size = 0x100; + readsize = 0x100; + ; + + memory "usersig" + size = 0x200; + offset = 0x8e0400; + page_size = 0x100; + readsize = 0x100; + ; + + memory "signature" + size = 3; + offset = 0x1000090; + ; + + memory "fuse0" + size = 1; + offset = 0x8f0020; + ; + + memory "fuse1" + size = 1; + offset = 0x8f0021; + ; + + memory "fuse2" + size = 1; + offset = 0x8f0022; + ; + + memory "fuse4" + size = 1; + offset = 0x8f0024; + ; + + memory "fuse5" + size = 1; + offset = 0x8f0025; + ; + + memory "lock" + size = 1; + offset = 0x8f0027; + ; +; + +#------------------------------------------------------------ +# ATXMEGA64A3 +#------------------------------------------------------------ + +part + id = "x64a3"; + desc = "ATXMEGA64A3"; + signature = 0x1e 0x96 0x42; + has_jtag = yes; + has_pdi = yes; + nvm_base = 0x01c0; + + memory "eeprom" + size = 0x0800; + offset = 0x08c0000; + page_size = 0x20; + readsize = 0x100; + ; + + memory "application" + size = 0x00010000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "apptable" + size = 0x00001000; + offset = 0x0080f000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "boot" + size = 0x00001000; + offset = 0x00810000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "flash" + size = 0x00011000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "prodsig" + size = 0x200; + offset = 0x8e0200; + page_size = 0x100; + readsize = 0x100; + ; + + memory "usersig" + size = 0x200; + offset = 0x8e0400; + page_size = 0x100; + readsize = 0x100; + ; + + memory "signature" + size = 3; + offset = 0x1000090; + ; + + memory "fuse0" + size = 1; + offset = 0x8f0020; + ; + + memory "fuse1" + size = 1; + offset = 0x8f0021; + ; + + memory "fuse2" + size = 1; + offset = 0x8f0022; + ; + + memory "fuse4" + size = 1; + offset = 0x8f0024; + ; + + memory "fuse5" + size = 1; + offset = 0x8f0025; + ; + + memory "lock" + size = 1; + offset = 0x8f0027; + ; +; + +#------------------------------------------------------------ +# ATXMEGA128A3 +#------------------------------------------------------------ + +part + id = "x128a3"; + desc = "ATXMEGA128A3"; + signature = 0x1e 0x97 0x42; + has_jtag = yes; + has_pdi = yes; + nvm_base = 0x01c0; + + memory "eeprom" + size = 0x0800; + offset = 0x08c0000; + page_size = 0x20; + readsize = 0x100; + ; + + memory "application" + size = 0x00020000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "apptable" + size = 0x00002000; + offset = 0x0081e000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "boot" + size = 0x00002000; + offset = 0x00820000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "flash" + size = 0x00022000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "prodsig" + size = 0x200; + offset = 0x8e0200; + page_size = 0x100; + readsize = 0x100; + ; + + memory "usersig" + size = 0x200; + offset = 0x8e0400; + page_size = 0x100; + readsize = 0x100; + ; + + memory "signature" + size = 3; + offset = 0x1000090; + ; + + memory "fuse0" + size = 1; + offset = 0x8f0020; + ; + + memory "fuse1" + size = 1; + offset = 0x8f0021; + ; + + memory "fuse2" + size = 1; + offset = 0x8f0022; + ; + + memory "fuse4" + size = 1; + offset = 0x8f0024; + ; + + memory "fuse5" + size = 1; + offset = 0x8f0025; + ; + + memory "lock" + size = 1; + offset = 0x8f0027; + ; +; + +#------------------------------------------------------------ +# ATXMEGA192A3 +#------------------------------------------------------------ + +part + id = "x192a3"; + desc = "ATXMEGA192A3"; + signature = 0x1e 0x97 0x44; + has_jtag = yes; + has_pdi = yes; + nvm_base = 0x01c0; + + memory "eeprom" + size = 0x0800; + offset = 0x08c0000; + page_size = 0x20; + readsize = 0x100; + ; + + memory "application" + size = 0x00030000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "apptable" + size = 0x00002000; + offset = 0x0082e000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "boot" + size = 0x00002000; + offset = 0x00830000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "flash" + size = 0x00032000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "prodsig" + size = 0x200; + offset = 0x8e0200; + page_size = 0x100; + readsize = 0x100; + ; + + memory "usersig" + size = 0x200; + offset = 0x8e0400; + page_size = 0x100; + readsize = 0x100; + ; + + memory "signature" + size = 3; + offset = 0x1000090; + ; + + memory "fuse0" + size = 1; + offset = 0x8f0020; + ; + + memory "fuse1" + size = 1; + offset = 0x8f0021; + ; + + memory "fuse2" + size = 1; + offset = 0x8f0022; + ; + + memory "fuse4" + size = 1; + offset = 0x8f0024; + ; + + memory "fuse5" + size = 1; + offset = 0x8f0025; + ; + + memory "lock" + size = 1; + offset = 0x8f0027; + ; +; + +#------------------------------------------------------------ +# ATXMEGA256A3 +#------------------------------------------------------------ + +part + id = "x256a3"; + desc = "ATXMEGA256A3"; + signature = 0x1e 0x98 0x42; + has_jtag = yes; + has_pdi = yes; + nvm_base = 0x01c0; + + memory "eeprom" + size = 0x1000; + offset = 0x08c0000; + page_size = 0x20; + readsize = 0x100; + ; + + memory "application" + size = 0x00040000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "apptable" + size = 0x00002000; + offset = 0x0083e000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "boot" + size = 0x00002000; + offset = 0x00840000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "flash" + size = 0x00042000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "prodsig" + size = 0x200; + offset = 0x8e0200; + page_size = 0x100; + readsize = 0x100; + ; + + memory "usersig" + size = 0x200; + offset = 0x8e0400; + page_size = 0x100; + readsize = 0x100; + ; + + memory "signature" + size = 3; + offset = 0x1000090; + ; + + memory "fuse0" + size = 1; + offset = 0x8f0020; + ; + + memory "fuse1" + size = 1; + offset = 0x8f0021; + ; + + memory "fuse2" + size = 1; + offset = 0x8f0022; + ; + + memory "fuse4" + size = 1; + offset = 0x8f0024; + ; + + memory "fuse5" + size = 1; + offset = 0x8f0025; + ; + + memory "lock" + size = 1; + offset = 0x8f0027; + ; +; + +#------------------------------------------------------------ +# ATXMEGA256A3B +#------------------------------------------------------------ + +part + id = "x256a3b"; + desc = "ATXMEGA256A3B"; + signature = 0x1e 0x98 0x43; + has_jtag = yes; + has_pdi = yes; + nvm_base = 0x01c0; + + memory "eeprom" + size = 0x1000; + offset = 0x08c0000; + page_size = 0x20; + readsize = 0x100; + ; + + memory "application" + size = 0x00040000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "apptable" + size = 0x00002000; + offset = 0x0083e000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "boot" + size = 0x00002000; + offset = 0x00840000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "flash" + size = 0x00042000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "prodsig" + size = 0x200; + offset = 0x8e0200; + page_size = 0x100; + readsize = 0x100; + ; + + memory "usersig" + size = 0x200; + offset = 0x8e0400; + page_size = 0x100; + readsize = 0x100; + ; + + memory "signature" + size = 3; + offset = 0x1000090; + ; + + memory "fuse0" + size = 1; + offset = 0x8f0020; + ; + + memory "fuse1" + size = 1; + offset = 0x8f0021; + ; + + memory "fuse2" + size = 1; + offset = 0x8f0022; + ; + + memory "fuse4" + size = 1; + offset = 0x8f0024; + ; + + memory "fuse5" + size = 1; + offset = 0x8f0025; + ; + + memory "lock" + size = 1; + offset = 0x8f0027; + ; +; + +#------------------------------------------------------------ +# ATXMEGA16A4 +#------------------------------------------------------------ + +part + id = "x16a4"; + desc = "ATXMEGA16A4"; + signature = 0x1e 0x94 0x41; + has_jtag = yes; + has_pdi = yes; + nvm_base = 0x01c0; + + memory "eeprom" + size = 0x0400; + offset = 0x08c0000; + page_size = 0x20; + readsize = 0x100; + ; + + memory "application" + size = 0x00004000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "apptable" + size = 0x00001000; + offset = 0x00803000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "boot" + size = 0x00001000; + offset = 0x00804000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "flash" + size = 0x00005000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "prodsig" + size = 0x200; + offset = 0x8e0200; + page_size = 0x100; + readsize = 0x100; + ; + + memory "usersig" + size = 0x200; + offset = 0x8e0400; + page_size = 0x100; + readsize = 0x100; + ; + + memory "signature" + size = 3; + offset = 0x1000090; + ; + + memory "fuse0" + size = 1; + offset = 0x8f0020; + ; + + memory "fuse1" + size = 1; + offset = 0x8f0021; + ; + + memory "fuse2" + size = 1; + offset = 0x8f0022; + ; + + memory "fuse4" + size = 1; + offset = 0x8f0024; + ; + + memory "fuse5" + size = 1; + offset = 0x8f0025; + ; + + memory "lock" + size = 1; + offset = 0x8f0027; + ; +; + +#------------------------------------------------------------ +# ATXMEGA32A4 +#------------------------------------------------------------ + +part + id = "x32a4"; + desc = "ATXMEGA32A4"; + signature = 0x1e 0x95 0x41; + has_jtag = yes; + has_pdi = yes; + nvm_base = 0x01c0; + + memory "eeprom" + size = 0x0400; + offset = 0x08c0000; + page_size = 0x20; + readsize = 0x100; + ; + + memory "application" + size = 0x00008000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "apptable" + size = 0x00001000; + offset = 0x00807000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "boot" + size = 0x00001000; + offset = 0x00808000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "flash" + size = 0x00009000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "prodsig" + size = 0x200; + offset = 0x8e0200; + page_size = 0x100; + readsize = 0x100; + ; + + memory "usersig" + size = 0x200; + offset = 0x8e0400; + page_size = 0x100; + readsize = 0x100; + ; + + memory "signature" + size = 3; + offset = 0x1000090; + ; + + memory "fuse0" + size = 1; + offset = 0x8f0020; + ; + + memory "fuse1" + size = 1; + offset = 0x8f0021; + ; + + memory "fuse2" + size = 1; + offset = 0x8f0022; + ; + + memory "fuse4" + size = 1; + offset = 0x8f0024; + ; + + memory "fuse5" + size = 1; + offset = 0x8f0025; + ; + + memory "lock" + size = 1; + offset = 0x8f0027; + ; +; + +#------------------------------------------------------------ +# ATXMEGA64A4 +#------------------------------------------------------------ + +part + id = "x64a4"; + desc = "ATXMEGA64A4"; + signature = 0x1e 0x96 0x46; + has_jtag = yes; + has_pdi = yes; + nvm_base = 0x01c0; + + memory "eeprom" + size = 0x0800; + offset = 0x08c0000; + page_size = 0x20; + readsize = 0x100; + ; + + memory "application" + size = 0x00010000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "apptable" + size = 0x00001000; + offset = 0x0080f000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "boot" + size = 0x00001000; + offset = 0x00810000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "flash" + size = 0x00011000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "prodsig" + size = 0x200; + offset = 0x8e0200; + page_size = 0x100; + readsize = 0x100; + ; + + memory "usersig" + size = 0x200; + offset = 0x8e0400; + page_size = 0x100; + readsize = 0x100; + ; + + memory "signature" + size = 3; + offset = 0x1000090; + ; + + memory "fuse0" + size = 1; + offset = 0x8f0020; + ; + + memory "fuse1" + size = 1; + offset = 0x8f0021; + ; + + memory "fuse2" + size = 1; + offset = 0x8f0022; + ; + + memory "fuse4" + size = 1; + offset = 0x8f0024; + ; + + memory "fuse5" + size = 1; + offset = 0x8f0025; + ; + + memory "lock" + size = 1; + offset = 0x8f0027; + ; +; + +#------------------------------------------------------------ +# ATXMEGA128A4 +#------------------------------------------------------------ + +part + id = "x128a4"; + desc = "ATXMEGA128A4"; + signature = 0x1e 0x97 0x46; + has_jtag = yes; + has_pdi = yes; + nvm_base = 0x01c0; + + memory "eeprom" + size = 0x0800; + offset = 0x08c0000; + page_size = 0x20; + readsize = 0x100; + ; + + memory "application" + size = 0x00020000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "apptable" + size = 0x00002000; + offset = 0x0081e000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "boot" + size = 0x00002000; + offset = 0x00820000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "flash" + size = 0x00022000; + offset = 0x0800000; + page_size = 0x100; + readsize = 0x100; + ; + + memory "prodsig" + size = 0x200; + offset = 0x8e0200; + page_size = 0x100; + readsize = 0x100; + ; + + memory "usersig" + size = 0x200; + offset = 0x8e0400; + page_size = 0x100; + readsize = 0x100; + ; + + memory "signature" + size = 3; + offset = 0x1000090; + ; + + memory "fuse0" + size = 1; + offset = 0x8f0020; + ; + + memory "fuse1" + size = 1; + offset = 0x8f0021; + ; + + memory "fuse2" + size = 1; + offset = 0x8f0022; + ; + + memory "fuse4" + size = 1; + offset = 0x8f0024; + ; + + memory "fuse5" + size = 1; + offset = 0x8f0025; + ; + + memory "lock" + size = 1; + offset = 0x8f0027; + ; +; + + +#------------------------------------------------------------ +# AVR32UC3A0512 +#------------------------------------------------------------ + +part + id = "ucr2"; + desc = "32UC3A0512"; + signature = 0xED 0xC0 0x3F; + has_jtag = yes; + is_avr32 = yes; + + memory "flash" + paged = yes; + page_size = 512; # bytes + readsize = 512; # bytes + num_pages = 1024; # could be set dynamicly + size = 0x00080000; # could be set dynamicly + offset = 0x80000000; + ; +; + +#------------------------------------------------------------ +# ATtiny4 +#------------------------------------------------------------ + +part + id = "t4"; + desc = "ATtiny4"; + signature = 0x1e 0x8f 0x0a; + has_tpi = yes; + + memory "flash" + size = 512; + offset = 0x4000; + page_size = 16; + blocksize = 128; + ; + + memory "signature" + size = 3; + offset = 0x3fc0; + ; + + memory "fuse" + size = 1; + offset = 0x3f40; + blocksize = 4; + ; + + memory "calibration" + size = 1; + offset = 0x3f80; + ; + + memory "lockbits" + size = 1; + offset = 0x3f00; + ; +; + + +#------------------------------------------------------------ +# ATtiny5 +#------------------------------------------------------------ + +part + id = "t5"; + desc = "ATtiny5"; + signature = 0x1e 0x8f 0x09; + has_tpi = yes; + + memory "flash" + size = 512; + offset = 0x4000; + page_size = 16; + blocksize = 128; + ; + + memory "signature" + size = 3; + offset = 0x3fc0; + ; + + memory "fuse" + size = 1; + offset = 0x3f40; + blocksize = 4; + ; + + memory "calibration" + size = 1; + offset = 0x3f80; + ; + + memory "lockbits" + size = 1; + offset = 0x3f00; + ; +; + + +#------------------------------------------------------------ +# ATtiny9 +#------------------------------------------------------------ + +part + id = "t8"; + desc = "ATtiny9"; + signature = 0x1e 0x90 0x08; + has_tpi = yes; + + memory "flash" + size = 1024; + offset = 0x4000; + page_size = 16; + blocksize = 128; + ; + + memory "signature" + size = 3; + offset = 0x3fc0; + ; + + memory "fuse" + size = 1; + offset = 0x3f40; + blocksize = 4; + ; + + memory "calibration" + size = 1; + offset = 0x3f80; + ; + + memory "lockbits" + size = 1; + offset = 0x3f00; + ; +; + + +#------------------------------------------------------------ +# ATtiny10 +#------------------------------------------------------------ + +part + id = "t10"; + desc = "ATtiny10"; + signature = 0x1e 0x90 0x03; + has_tpi = yes; + + memory "flash" + size = 1024; + offset = 0x4000; + page_size = 16; + blocksize = 128; + ; + + memory "signature" + size = 3; + offset = 0x3fc0; + ; + + memory "fuse" + size = 1; + offset = 0x3f40; + blocksize = 4; + ; + + memory "calibration" + size = 1; + offset = 0x3f80; + ; + + memory "lockbits" + size = 1; + offset = 0x3f00; + ; +; + + diff --git a/avrdude/avrdude.exe b/avrdude/avrdude.exe new file mode 100644 index 0000000000000000000000000000000000000000..12c3225ed2637beeae48ddabf10c5bb5863552f2 Binary files /dev/null and b/avrdude/avrdude.exe differ diff --git a/avrdude/libusb0.dll b/avrdude/libusb0.dll new file mode 100644 index 0000000000000000000000000000000000000000..9387bedad1d4ec91bfb903486d1ed37abccab63e Binary files /dev/null and b/avrdude/libusb0.dll differ diff --git a/files/flightgear/Protocol/qgroundcontrol-fixed-wing.xml b/files/flightgear/Protocol/qgroundcontrol-fixed-wing.xml index 94a60ded590e9c6d832220ba3c9639265702c04c..0ecbf20d5dde9d6a742eef9a2d37f9bf318d8fc5 100644 --- a/files/flightgear/Protocol/qgroundcontrol-fixed-wing.xml +++ b/files/flightgear/Protocol/qgroundcontrol-fixed-wing.xml @@ -141,6 +141,41 @@ /velocities/airspeed-kt 0.514444444444444 + + + + Magnetic Variation (rad) + float + %.8f + /environment/magnetic-variation-deg + 0.01745329251994329576 + + + + Magnetic Dip (rad) + float + %.8f + /environment/magnetic-dip-deg + 0.01745329251994329576 + + + + + Temperature (deg C) + float + %.8f + /environment/temperature-degc + 1 + + + + + Pressure (hPa) + float + %.8f + /environment/pressure-inhg + 33.86389 + @@ -184,4 +219,4 @@ - \ No newline at end of file + diff --git a/files/images/devices/AC-0004-11-2.jpg b/files/images/devices/AC-0004-11-2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..334486b6756e6b2671c1a2dd1099f2c051e4a20c Binary files /dev/null and b/files/images/devices/AC-0004-11-2.jpg differ diff --git a/files/images/devices/BR-0004-03-2.jpg b/files/images/devices/BR-0004-03-2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0126646ef48942d00ed34f2b0e720b26a308f155 Binary files /dev/null and b/files/images/devices/BR-0004-03-2.jpg differ diff --git a/files/images/devices/BR-0016-01-3T.jpg b/files/images/devices/BR-0016-01-3T.jpg new file mode 100644 index 0000000000000000000000000000000000000000..534eba3f0b7cfa4f16f7aeab02f410bc489bc50b Binary files /dev/null and b/files/images/devices/BR-0016-01-3T.jpg differ diff --git a/files/images/devices/BR-APMPWRDEAN-2.jpg b/files/images/devices/BR-APMPWRDEAN-2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..62a6a83b8380283f52d1b9981cd960711a2e8630 Binary files /dev/null and b/files/images/devices/BR-APMPWRDEAN-2.jpg differ diff --git a/files/images/devices/BR-HMC5883-01-2.jpg b/files/images/devices/BR-HMC5883-01-2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f695795f6f93082d0e4a9b588aef3e9f515ff133 Binary files /dev/null and b/files/images/devices/BR-HMC5883-01-2.jpg differ diff --git a/files/images/devices/MinimOSD.jpg b/files/images/devices/MinimOSD.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b24c7e4a9759278435edcefe778e51765177d26e Binary files /dev/null and b/files/images/devices/MinimOSD.jpg differ diff --git a/files/images/devices/Shutter.png b/files/images/devices/Shutter.png new file mode 100644 index 0000000000000000000000000000000000000000..0362734d5762771d2b98bcfe55fe6c08138cf412 Binary files /dev/null and b/files/images/devices/Shutter.png differ diff --git a/files/images/devices/cameraGimalPitch1.png b/files/images/devices/cameraGimalPitch1.png new file mode 100644 index 0000000000000000000000000000000000000000..158429893b5aa82506f4ca902b7d8acdec03253f Binary files /dev/null and b/files/images/devices/cameraGimalPitch1.png differ diff --git a/files/images/devices/cameraGimalRoll1.png b/files/images/devices/cameraGimalRoll1.png new file mode 100644 index 0000000000000000000000000000000000000000..bff678c9e7adc2264732f2df1d2bdfd29e7e3368 Binary files /dev/null and b/files/images/devices/cameraGimalRoll1.png differ diff --git a/files/images/devices/cameraGimalYaw.png b/files/images/devices/cameraGimalYaw.png new file mode 100644 index 0000000000000000000000000000000000000000..0375add2c31bf2c7a5926ce864037bd43a550068 Binary files /dev/null and b/files/images/devices/cameraGimalYaw.png differ diff --git a/files/images/firmware/FW icons 2013+logos.ai b/files/images/firmware/FW icons 2013+logos.ai new file mode 100644 index 0000000000000000000000000000000000000000..5214ac6900d9dc8dcdd2c29cbc3f210232fcdb6e --- /dev/null +++ b/files/images/firmware/FW icons 2013+logos.ai @@ -0,0 +1,2008 @@ +%PDF-1.5 %âãÏÓ +1 0 obj <>/OCGs[5 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + application/pdf + + + FW icons 2013+logos + + + + + Adobe Illustrator CS6 (Windows) + 2013-07-07T04:01:27+03:00 + 2013-07-07T04:01:27+03:00 + 2013-07-07T04:01:27+03:00 + + + + 256 + 68 + JPEG + /9j/4AAQSkZJRgABAgEAYABgAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAAYAAAAAEA AQBgAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgARAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9UO6Ihd2CooqzMaAAdyT gJAFlUku/Ofl6JWWO8SSY7RqgZwWI23UEUrmDk7SwjlKywOQIfSfO2jy2cC312sV7wUzBlZV5EV2 NKZVp+08RiOOVSrdEcg6p99dtfqv1oSq1uRyEqfECOm3Gtc2Pix4eK/SztKX856CrMrXAjZdiJVd DWlR8PEtT3pmGe0sI6177DHxAvtvN2i3ESukrMTQOER2CE/zELT6cMO0MUhYP2FRkCZXN7a20Qlm fjGehALE18AoJObCEDLkuTJGAspfesLiSGWF0liuf3cRJUbgPVdxUb7mm+1MxNRCQlR67ff+NkCQ kLHJFx6lZJOlk84a5ACmoNCwHTlTjX2rmZHFLhtHjw4uG912oSyxxKUJCkkOw6j4TTejUq1BWm2Y +aRA2bCgDrBGnu/qH1w4CoApm4EgmiDYsFbwp3wafMJc+fd18mrJMiNhFaTPPKknNjJEOPpyNuak fEvIBeQB70zKmNhYqXUIwyJvewhbmS9S4LRpI8ockqC/2Q23EU9MoU+mvvmtmZA7Xd+f9lU2G27j XYLqK6t9PMsl3DRWVEYMtRU/aFAQPHvmRg1WOU+Eb15fewyyJieHmv0kzNOSPUERQ+orGQqH5/DQ ygNypXlTbMo8XD664r6dzDF9W11XW+fx+1Ncrcl2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2K uxVxAIodweoxVB6jcWFlatNcJSM/CAiF2JPYBQcozThCNy+5BICH0KTT5bFLeBN7RVhkDoVNVFKi o3Bp1GV6SUDARH8OyI1Svq1rczWLQ2p4vyUlQSlVB+IBh0yzUQlKFRWQ2S638rWNzCrapbiaVS3p guxKoeilgd99+u2Y0NBCQ/eCyxEAealeeXZ4pI49MQRWygCNFdkEbVJZm3+Ku36u+QyaMggY9o+/ l+P2KYdyZ6npP1xIDHIIZbfkI2Kll4uvFgVVkPTpRs20CBExIuJ+DDNhMqINEJVcaPptt9Thf1JH t5muHZX48pH5yEBWY9dzQdswdbwZJxJvauvcNvuRjwiAA87+e6Kh8uxfWVnjnraGUXSxcWL8+XqD 4y9OPL/J+nNhHLGrA9XDw3fT3NY0vq5+ni4q8+fP9iYajePbJGUALSMVqRUbKWoN13bjQb5ADYmr ocg35Z8NeaUrbyyudbZ1W/hJgQVHoemWAIrSu1d2r19sws+n4ZDL/HQ2PIX0P62OORlum2n3Us6N 6gFVC7igoSN1NCwqPY5bhyGXNuBUb/VZYJGiggE0gKooLceUjioVdj0G5JoMvkYxAs/UaDVPKbIi LpBIkemJFfwgyyXg53tajnVefqU3pw8B2zAlj8A3zJ+rz8/h9yYnYEdU4trj1lYleLKaEA8gagMC Dt1BGZcJ8TYCrZNLsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVUZr SGZuT8gSOLcWK1HgafPISxg80UrAAAACgGwAyaWnRHUq6hlPVSKj8cINIIB5rA9upEAZAegiqAen Tj8siZC6vdRQ2XoiIoVFCqOgAoPwxAA5JQt1p9rLI0sjNGXASUo7IHUVoGoRXrlgymIap4YyNr5o rNoo0LCNU3hKtxK0FPhI9jTKpQ42ewFKkEEcKcUqankzMSxJPck4xgI8khUySXYq7FXYq7FXYq7F XYq7FXYq7FXYq7FXYq7FXYq7FWnNEY1C0BNT0HzxCClCyOJ3aN/VkSp9MHdyBUqtR3pkJ4zEWN/J pjOytZrqeOOe4U20zULWzEMUpsRyA6GldshDLIxFgxPcP0plG9ymEjzpaJ6Z9WSlOYBPbrTfLSSe TPcBSm1NbKya5vgyxoQCyqSTUgD4Rv1PhlOTN4cbnyTxbWV1xc3RCNbofTYVDUrXf2rTbJ3KXLki Uig9ZsLy+jtpFhWUR8vUtZCApYlSrfECPhCkfTmTjkREi+GRrfn8Pi4+oxGdGuIDofv+CpDfNptv aWl8GkuJCIo5EAYO1CfanSm+Ymo1UYz3B9R2bsQMYgHcoWbS9Tn1X6yyqg5o8VwGUvEilKxkU3qE bv8AtZmY8npFmtjce899uNPBIzvzFHuG233/ADTW+uLqIL6EfqEgkjizdCPCnieuVAOVkkRyQKyW pu1LT0kb989sQeYIKCgQn+am/GuYZMOPn5116JBR1jcXUwf14/TIpx+ErWvXrXMwoxyJ5oe8ured hbMzQjmUEpoBWhXb4gw3qAaUrlebFxCrAPPzpByi6+CF9S2uj6AlWOSyDC4PUVYhgAAVrypXKMOo j9N/Tzo/jmicOJM7O5ikRYlJ5Ig3NN6bHoT9I7ZdHMJnZsjsKROWMnYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FXYq7FXYq7FVk8KzQtExIVxQ064QaRKNikNbWLxyl5Cp+LkAoHWlK9NshEVyADAQN7lde2 jzqeJWpps4qNjX3xlASFFMgeirbwmJCCasxLMQKCp8BkqHRMRQUdRjnkQJGzKpB5FRU12oe2CXI9 /wA2MwSq2vrel+9ryrtXrTtX3yRNsoXW6tgZJRq168VwKJHS1AmrINzVX6big+GlfEjJeEJGNgn1 fLZxsuUxJ5bC902RuSK1CtQDxPUV7HAXIBtDXyXTKv1diGFa0p4jxI98pyiR+lSltLQ6ojmN2uVU wyXYf4wWZdgK04hmp0+imP5WPECT6+H7GjxPVy8rTKxS7Xn9YYk7ca09/AnBiEh9TeFC8tordvrU aGSQMWWMseHKhNQCaV/jlmbNKMdg1+ELtCvxtVE0KI8t4GNyWNA9GArt4ctvbKcGCP1fzvqrrfX4 fcjJPh5JnaW0UaiReRd1FSxLEA70qctjiETs2R5WiMmydirsVdirsVdirsVdirsVdirsVdirsVdi rsVdirsVdiqlJdQorUYOy9UUgnrToPc4JnhFseILIb6CSESswjVvs8yBUbHvTxyOKXGLAUyA5ojJ slD65D9a+rb+p+Gw5fxw0w4xdLre6in5ema8ev3kfwyuGQS5M7Vcmq14onKl0Viu6kgGh9q4QSEG IPNdgS7FVE2dsZvWKVkqGrU05AcQ3GtK02rkuM1TDw43fVWyLN2KuxV2KuxVDajfwWFo9zOSsaDd wjuF26t6asQviegxClLfLfm7R9ejYWs0f1qKomt1dXIpsWVl2dPA/eBk5wrkbDVjycXMUfx807yD a7FXYq7FUjj856A2ptp73ccU/RUlJievdXjkCOp8NqHKzkqVEbd6LTzLEuxV2KuxVDajfwWFo9zO SsaDdwjuF26t6asQviegxVLfLfm/R9ejYWsyfW4qia2V1cimxZGXZ08G+8DIxlbIik7yTF2KuxVZ NKsUTSN0UVyM5cItUr9SGMSXqhz19SNlYqymjEA8RRq+OY8s44TKvfz3prEaNqds0V5YQXL840CB Y4wtKcqBi54sK5HT5wcYlW21IlHiTJrgyWRlX92SNixoOtOppmQCZxsc2wna0snultIxdzcZ5ozX lGeRII4UKg7dffMfJnnij6muo3a//SBwNs6xooo6lwGLA9WB6fLfL9PKAHQff+xjMSvZN3Eh+wwH jUE/xGWG+jeksWu3sl7La/VmQxtxDyIVDH/JBbf55gx1UjMxrl5ftYcRtMZLm5hj5yR1psVUAVJ9 +Z/VmSZyAsj8fNlaLy5LsVdirsVdirsVdirsVeY/mn5Y8v6bYv5ksXfS9bjdfQa0PD1pGYDdRSh3 J5CnvXCGJQOi/mn5gtbiHT9WWK4EFtcveXRjKubi3heb0QVKpVQqq/w/ar8ypXzfmp50s9Mhur7S YY3uZEa3JinjDwLE0tyVjd+R9McaPXj88VZf5E82an5kbVbme1W1sLa4FvZJxYTfCOT+tViOVGXY AU98CWVYqknmfyh5f8xWhj1S3DOgPpXS/DNH/qv4ex29sbpXkOj+ffMPlu1vo7S7Gp6ZHK8GkLdq WLLE1WlHFgwjWPanKlWFO+KGXH8zPMMmpyNZ6fFcaLZxwyX9wI5gVDW/rTt6vIxL6fQK257YVU/L P5o+YdZ1XRtLawhiuLqSX9ISlJBGI0X1QIgXNG9MgksT1G2KvT8CXYq8w/NPyx5f02xbzJYu+l63 G6+g1oeHrSMwG6ilDuTyFPeuKoLRPzT1+1uYdP1YRTi3trl726MbK5uIIXm9EFSqVUKqv8P2q/Ml C+b81POlppcF1e6TAkly6Pbn0p4w9usTS3LKjvy/djjR68fnirLvInmzUvMrarcz2yWtjbXIt7JO LCb4Ryf1qsRyoy7ACnvgSysgEUO4PUYqlzLcRzNJOvK3jJMK/CFDFgF6bnY9xtkMgAF91V+OTVHi vfkpIt00EUlqnElOMo+E8ioAWoagr75DTgGN+6+fL9az4uiZywpJEYjsp22y+JpslGxSCitBHMtu qE24YuxK7V4ADcUGY8t5CNekMYxpbaW7T0NyhVoVUIePGo3HU1rt4ZOWCO3l7mMCTzTLLG1aYoy3 IopbryoK4OEKuwq7FXYq7FXYq7FXYq7FVC8uXt4C8cLTyn4YoU6sx6Anoo8WOwyURZYzlQ5WwjWt D1bUtSku5V+uzaNA91FbptHJqLITbwoHp8MIoxJ6lh75aDEyA5RtolGcYmXOdfgJLpehfmFpl5o/ 6XSTVtOLvPfW1stvI0RMIQIzSiCvORizgVoBSrdczcksExLhqJ6X+C63FDVQlHjJlHrVd3nXVD3t v+cF6uosLH0ZrqaGTTkZoGS0t1WYyQrufthYkfxyY/LCt7oG/Pl+1rkdaeKhRJFcthvt9yL8q6d+ Zh8x2P6Wa5tNPAE95wEPoySszzOr8ZUYU5LFsjVp4b5DNLAIHhq/wO74s9NDVHJHjMhHryrv7/h1 eq5q3eMc80HU73TWtbOsUt+wtbSoINZAec7/AMqxxhmA61AykAzNnaP3o5pQnl7VNNWay021dYbO D0NO4iAxSRlT6nrF/jZndi1OlcwM/wCYM5cN7fTyr4+bWeK24dG81SL9Ut62lnIzuWnEQYrxVVEi xqymtCeNOnfKRj1UjQJA7zV9O77kVJdd6T5hhklns0m9Q3TrHwEIItwoqw+zTm3TfoMOWGp3MTL6 vL6f2lJEkx0SDzQNaZr6SRbBFcKHKsH40RagbqTQvX6Mt00NR4vrJ4Pv6ftTESvdP725e3gLxwvP KfhihTqzHoC3RR4sdhm0JptAYRrGiapf6nJfXKm9k0SB7tLaMExyagULW8EanqsS0ap6lhXvkdwC erLYkDowu10f81009Yb2C7mhaYieKFbU3CH6tVGiklVVCTTvSXaqhO9d8MDLW9uSfDvoj7vSfzaC zxTvJOtpYQzRyRrGzvdfV/RNtFtTiZDzlp1C9d8kRl+xAONBQWP5vCOxhtpb+BXb1b66aKON1eaV I2LRB5RL6axtJ1FQ3bI1l25srx78nuGZ7hOxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KrU 9PfhTqeVKde9ad8VXYq7FXYq7FVp9L1Vrx9WjcK05U25U706VxVdirsVdirsVdiq1PT34U6nlSnX vWnfFV2KuxV2Kv8A/9k= + + + + + + proof:pdf + uuid:65E6390686CF11DBA6E2D887CEACB407 + xmp.did:B7D30232A0E6E21186CBB3ABC4A69F81 + uuid:6e717a34-d9cf-4b98-b305-8191aa11dbfe + + xmp.iid:B5D30232A0E6E21186CBB3ABC4A69F81 + xmp.did:B5D30232A0E6E21186CBB3ABC4A69F81 + uuid:65E6390686CF11DBA6E2D887CEACB407 + proof:pdf + + + + + saved + xmp.iid:B5D30232A0E6E21186CBB3ABC4A69F81 + 2013-07-07T03:57:28+03:00 + Adobe Illustrator CS6 (Windows) + / + + + saved + xmp.iid:B7D30232A0E6E21186CBB3ABC4A69F81 + 2013-07-07T04:01:25+03:00 + Adobe Illustrator CS6 (Windows) + / + + + + + + Web + Document + + + 1 + True + False + + 600.000000 + 300.000000 + Pixels + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + White + RGB + PROCESS + 255 + 255 + 255 + + + Black + RGB + PROCESS + 0 + 0 + 0 + + + RGB Red + RGB + PROCESS + 255 + 0 + 0 + + + RGB Yellow + RGB + PROCESS + 255 + 255 + 0 + + + RGB Green + RGB + PROCESS + 0 + 255 + 0 + + + RGB Cyan + RGB + PROCESS + 0 + 255 + 255 + + + RGB Blue + RGB + PROCESS + 0 + 0 + 255 + + + RGB Magenta + RGB + PROCESS + 255 + 0 + 255 + + + R=193 G=39 B=45 + RGB + PROCESS + 193 + 39 + 45 + + + R=237 G=28 B=36 + RGB + PROCESS + 237 + 28 + 36 + + + R=241 G=90 B=36 + RGB + PROCESS + 241 + 90 + 36 + + + R=247 G=147 B=30 + RGB + PROCESS + 247 + 147 + 30 + + + R=251 G=176 B=59 + RGB + PROCESS + 251 + 176 + 59 + + + R=252 G=238 B=33 + RGB + PROCESS + 252 + 238 + 33 + + + R=217 G=224 B=33 + RGB + PROCESS + 217 + 224 + 33 + + + R=140 G=198 B=63 + RGB + PROCESS + 140 + 198 + 63 + + + R=57 G=181 B=74 + RGB + PROCESS + 57 + 181 + 74 + + + R=0 G=146 B=69 + RGB + PROCESS + 0 + 146 + 69 + + + R=0 G=104 B=55 + RGB + PROCESS + 0 + 104 + 55 + + + R=34 G=181 B=115 + RGB + PROCESS + 34 + 181 + 115 + + + R=0 G=169 B=157 + RGB + PROCESS + 0 + 169 + 157 + + + R=41 G=171 B=226 + RGB + PROCESS + 41 + 171 + 226 + + + R=0 G=113 B=188 + RGB + PROCESS + 0 + 113 + 188 + + + R=46 G=49 B=146 + RGB + PROCESS + 46 + 49 + 146 + + + R=27 G=20 B=100 + RGB + PROCESS + 27 + 20 + 100 + + + R=102 G=45 B=145 + RGB + PROCESS + 102 + 45 + 145 + + + R=147 G=39 B=143 + RGB + PROCESS + 147 + 39 + 143 + + + R=158 G=0 B=93 + RGB + PROCESS + 158 + 0 + 93 + + + R=212 G=20 B=90 + RGB + PROCESS + 212 + 20 + 90 + + + R=237 G=30 B=121 + RGB + PROCESS + 237 + 30 + 121 + + + R=199 G=178 B=153 + RGB + PROCESS + 199 + 178 + 153 + + + R=153 G=134 B=117 + RGB + PROCESS + 153 + 134 + 117 + + + R=115 G=99 B=87 + RGB + PROCESS + 115 + 99 + 87 + + + R=83 G=71 B=65 + RGB + PROCESS + 83 + 71 + 65 + + + R=198 G=156 B=109 + RGB + PROCESS + 198 + 156 + 109 + + + R=166 G=124 B=82 + RGB + PROCESS + 166 + 124 + 82 + + + R=140 G=98 B=57 + RGB + PROCESS + 140 + 98 + 57 + + + R=117 G=76 B=36 + RGB + PROCESS + 117 + 76 + 36 + + + R=96 G=56 B=19 + RGB + PROCESS + 96 + 56 + 19 + + + R=66 G=33 B=11 + RGB + PROCESS + 66 + 33 + 11 + + + + + + Grays + 1 + + + + R=0 G=0 B=0 + RGB + PROCESS + 0 + 0 + 0 + + + R=26 G=26 B=26 + RGB + PROCESS + 26 + 26 + 26 + + + R=51 G=51 B=51 + RGB + PROCESS + 51 + 51 + 51 + + + R=77 G=77 B=77 + RGB + PROCESS + 77 + 77 + 77 + + + R=102 G=102 B=102 + RGB + PROCESS + 102 + 102 + 102 + + + R=128 G=128 B=128 + RGB + PROCESS + 128 + 128 + 128 + + + R=153 G=153 B=153 + RGB + PROCESS + 153 + 153 + 153 + + + R=179 G=179 B=179 + RGB + PROCESS + 179 + 179 + 179 + + + R=204 G=204 B=204 + RGB + PROCESS + 204 + 204 + 204 + + + R=230 G=230 B=230 + RGB + PROCESS + 230 + 230 + 230 + + + R=242 G=242 B=242 + RGB + PROCESS + 242 + 242 + 242 + + + + + + Web Color Group + 1 + + + + R=63 G=169 B=245 + RGB + PROCESS + 63 + 169 + 245 + + + R=122 G=201 B=67 + RGB + PROCESS + 122 + 201 + 67 + + + R=255 G=147 B=30 + RGB + PROCESS + 255 + 147 + 30 + + + R=255 G=29 B=37 + RGB + PROCESS + 255 + 29 + 37 + + + R=255 G=123 B=172 + RGB + PROCESS + 255 + 123 + 172 + + + R=189 G=204 B=212 + RGB + PROCESS + 189 + 204 + 212 + + + + + + + + + Adobe PDF library 10.01 + + + + + + + + + + + + + + + + + + + + + + + + + +endstream endobj 3 0 obj <> endobj 7 0 obj <> endobj 8 0 obj <> endobj 9 0 obj <> endobj 20 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 300.0 300.0]/Type/Page>> endobj 21 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 300.0 300.0]/Type/Page>> endobj 22 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 300.0 300.0]/Type/Page>> endobj 23 0 obj <>/Resources<>/ExtGState<>/Properties<>/Shading<>>>/TrimBox[0.0 0.0 600.0 300.0]/Type/Page>> endobj 24 0 obj <>/Resources<>/ExtGState<>/Properties<>/Shading<>>>/TrimBox[0.0 0.0 600.0 300.0]/Type/Page>> endobj 25 0 obj <>/Resources<>/ExtGState<>/Properties<>/Shading<>>>/TrimBox[0.0 0.0 600.0 300.0]/Type/Page>> endobj 43 0 obj <>stream +H‰ì—ËŽEE÷õù•“‘ïÜz@¬,d±€ýð¢düÿçFöLF°…²<Ý‘•7õôýsxzÿœÂ»ožÃñù˜=¶²B^#ÖÙ§ÃF‹«YÈ5Å’-ÜŽ\-æÒƒõלX]ÜžaqµNÚˆ£æ{\©éÂ|ã'âõÂÉÇãÇðöž¾û!…_¿`&Åd¹¯V™kL©¤TíÏ߯—úÀÑ”G©8’ã¬m¤báåÓñî§ðôÃǾ| ßþ>ާgŒ¼| )Ö<ô·4ý­%„//¿É“Ÿƒ…Ä? M +Ë$€G«Kjõ8R‰½UüÊqL~¥¸2'8' 8É3öÚñ'áv ¦ ÖKœËï”ÎYbëÓùW?c‡hCçÿ©/¿ÿìHá.¸‘PLÑ@Ã]¸œKг[ ßG½xmȸ¤¨ c81…CCÙËÑ¢å…DÄ¡ïÌÆ²f1'˜a·f´Y‘h̸8+qu +¶™C‹Ùx¸6QSÛ +­wô¬Õ$ k\ŸÖ÷Å9K0s† •>‚’"•P+XÕ@þnÇN 4ÛÔ÷9»Âx/ljC€|—oÇ)ÕЅí™-¶:B»}K]*¶x“?«¼ÉØÆeœ\À1£¨…dMP ªT°€ô¦Âˆ†Ÿä<”/mèct¿;cCE ê +sƒV%f(=T‰ W%Ã7W‰ iŠÜ-bAPZFMÝW ÛAÒ¤uÊ䓊ïúE!<•ñIÕ/®'#Œ»üª÷¹.'wª?¸;aQ÷Þb~÷TÓ¡JhUŒÍyÍ;å) Xð ¦ oFÎ"‰· l¢ÓšýM‚zÅa~=°î‰“h€ ú­-edeEéÁ%LÁªžâA-C™O# ZK"*I®ƒ§ê & +4ç]r¤Å¦ªi”¢«Ãýo±£Žðwz†Å"rXûæÏK,¨tV‘L -'YÚªÛ~nY>`Ö §ƒ’øBw :QÍ·§ÔÚò§eL±¬ˆIâܸ5ÚÈ;½:1ZÓx-tœÎ‚¶ª[ +Qb+Nn4›Ê"æìÕnÛ:ˆ)bj<…òÆ\WÒ)d¡¬D|ò£ø+©YÊýKn‰ès% S>œ2¹•ïÌìôC’¥´Bˆ/‹ ;»“•JœÊœy¥b¾ª¿PQ£ÐU¤‰Ë»É rVVìJDöΗvvUß[V­â³+Pªö2°¡šã¸Ñ1Sp¿‚¹üÁYFJ­>5¥@¤©Ãë<«†[`榴glhÌE8Nþº.6ÛœÚÖR£%Ë «#©…˜\VXütp©ûäÖ§ÜŒÜâ æÔIPºÜ|‹ieï §–w+0—Ò” x¥yy(¸¤d5êˆŰF¤ø¼g*úƶä„Ý®¦:ÆPš—æ%h'åUzÙ#íUÄ?±S?]jtD¢²Sù9ç}òȘ"Uï÷&,s¯›UކŨ¾–3KXOØ.½û$)ÃÆnÆÎWFȬêŠYWÔJߋ…Ì/_µ¾"ü'ÈY¢RÔ—ÞzvPj~)±TÛY“—ëí¨jþH[(ø-áDdlÍW8Ö.â×m—T“hÍ¿ØKRs­¢íèëôÕex§ºèK÷ÀûÐ0…)>0Ê‹räK½d]¦W×y·{;àS¢_h¶‚ó-4µüC|´_è¥Mæ__‰Öÿ+Ñl%êÿÅ•èo^P.›oCÛ†Q–cN»¬J@7}j×´Üjõ²¼'{¸ÁJ{nûµŽÙT_å›v‡ÔÌ»h7eC99̯JoΧ¹œL'Ìã7gSÑ–ËÉ×%Zè ‰7rÚÕíæ#ž½K¤°Iìu—#¨ø²@ÅÀ4neN3©H@]µSœFë£ú:ÀjÑ]ëLfæóÊÊ Ë]Pó'†ú*{ÅÔa׊§o\Ÿ´‚»¨WÁ]#[&heÉ>HªÓÕô±–o¬@"/ôZÖ^Ïfõµ¢ø{mt¾¢¯.èÙ}5”çÞ, ½–æ^VÇ^mÕÀ×ô -Rûî›ôâD-åñüvìé=–s‡_õR[.'Éàz)íUUzצ·Þ^Oñ]éž‚ŠMßÖ~¶²¼ôYVvGÕA¿i9ÉÙo]¤S%™ÓÞÒ=Ù”ÎÁ Z{RšjûUÖðÒ#ø, Åwæ‡Æ“¤ÉëÇÉŽðÛ÷Ï?–áK +endstream endobj 44 0 obj <> endobj 46 0 obj <> endobj 29 0 obj [/ICCBased 49 0 R] endobj 48 0 obj <> endobj 50 0 obj <> endobj 49 0 obj <>stream +H‰œ–yTSwÇoÉž•°Ãc [€°5la‘QIBHØADED„ª•2ÖmtFOE.®c­Ö}êÒõ0êè8´׎8GNg¦Óïï÷9÷wïïÝß½÷ó '¥ªµÕ0 Ö ÏJŒÅb¤  + 2y­.-;!à’ÆK°ZÜ ü‹ž^i½"LÊÀ0ðÿ‰-×é @8(”µrœ;q®ª7èLöœy¥•&†Qëñq¶4±jž½ç|æ9ÚÄ +V³)gB£0ñiœWו8#©8wÕ©•õ8_Å٥ʨQãüÜ«QÊj@é&»A)/ÇÙgº>'K‚óÈtÕ;\ú” Ó¥$ÕºF½ZUnÀÜå˜(4TŒ%)ë«”ƒ0C&¯”阤Z£“i˜¿óœ8¦Úbx‘ƒE¡ÁÁBÑ;…ú¯›¿P¦ÞÎӓ̹žAü om?çW= +€x¯Íú·¶Ò-Œ¯Àòæ[›Ëû0ñ¾¾øÎ}ø¦y)7ta¾¾õõõ>j¥ÜÇTÐ7úŸ¿@ï¼ÏÇtÜ›ò`qÊ2™±Ê€™ê&¯®ª6ê±ZL®Ä„?â_øóyxg)Ë”z¥ÈçL­UáíÖ*ÔuµSkÿSeØO4?׸¸c¯¯Ø°.òò· åÒR´ ßÞô-•’2ð5ßáÞüÜÏ ú÷Sá>Ó£V­š‹“då`r£¾n~ÏôY &à+`œ;ÂA4ˆÉ 䀰ÈA9Ð=¨- t°lÃ`;»Á~pŒƒÁ ðGp| ®[`Lƒ‡`<¯ "A ˆ YA+äùCb(ЇR¡,¨*T2B-Ð +¨ꇆ¡Ðnè÷ÐQètº}MA ï —0Óal»Á¾°ŽSàx ¬‚kà&¸^Á£ð>ø0|>_ƒ'á‡ð,ÂG!"F$H:Rˆ”!z¤éF‘Qd?r 9‹\A&‘GÈ ”ˆrQ ¢áhš‹ÊÑ´íE‡Ñ]èaô4zBgÐ×Á–àE#H ‹*B=¡‹0HØIøˆp†p0MxJ$ùD1„˜D, V›‰½Ä­ÄÄãÄKÄ»ÄY‰dEò"EÒI2’ÔEÚBÚGúŒt™4MzN¦‘Èþär!YKî ’÷?%_&ß#¿¢°(®”0J:EAi¤ôQÆ(Ç()Ó”WT6U@ æP+¨íÔ!ê~êêmêæD ¥eÒÔ´å´!ÚïhŸÓ¦h/èº']B/¢éëèÒÓ¿¢?a0nŒhF!ÃÀXÇØÍ8ÅøšñÜŒkæc&5S˜µ™˜6»lö˜Iaº2c˜K™MÌAæ!æEæ#…寒°d¬VÖë(ëk–Íe‹Øél »—½‡}Ž}ŸCâ¸qâ9 +N'çÎ)Î].ÂuæJ¸rî +î÷ wšGä xR^¯‡÷[ÞoÆœchžgÞ`>bþ‰ù$á»ñ¥ü*~ÿ ÿ:ÿ¥…EŒ…ÒbÅ~‹ËÏ,m,£-•–Ý–,¯Y¾´Â¬â­*­6X[ݱF­=­3­ë­·YŸ±~dó ·‘ÛtÛ´¹i ÛzÚfÙ6Û~`{ÁvÖÎÞ.ÑNg·Åî”Ý#{¾}´}…ý€ý§ö¸‘j‡‡ÏþŠ™c1X6„Æfm“Ž;'_9 œr:œ8Ýq¦:‹ËœœO:ϸ8¸¤¹´¸ìu¹éJq»–»nv=ëúÌMà–ï¶ÊmÜí¾ÀR 4 ö +n»3Ü£ÜkÜGݯz=Ä•[=¾ô„=ƒ<Ë=GTB(É/ÙSòƒ,]6*›-•–¾W:#—È7Ë*¢ŠÊe¿ò^YDYÙ}U„j£êAyTù`ù#µD=¬þ¶"©b{ųÊôÊ+¬Ê¯: !kJ4Gµm¥ötµ}uCõ%—®K7YV³©fFŸ¢ßY Õ.©=bàá?SŒîƕƩºÈº‘ºçõyõ‡Ø Ú† žkï5%4ý¦m–7Ÿlqlio™Z³lG+ÔZÚz²Í¹­³mzyâò]íÔöÊö?uøuôw|¿"űN»ÎåwW&®ÜÛe֥ﺱ*|ÕöÕèjõê‰5k¶¬yÝ­èþ¢Ç¯g°ç‡^yïkEk‡Öþ¸®lÝD_pß¶õÄõÚõ×7DmØÕÏîoê¿»1mãál {àûMśΠnßLÝlÜ<9”úO¤[þ˜¸™$™™üšhšÕ›B›¯œœ‰œ÷dÒž@ž®ŸŸ‹Ÿú i Ø¡G¡¶¢&¢–££v£æ¤V¤Ç¥8¥©¦¦‹¦ý§n§à¨R¨Ä©7©©ªª««u«é¬\¬Ð­D­¸®-®¡¯¯‹°°u°ê±`±Ö²K²Â³8³®´%´œµµŠ¶¶y¶ð·h·à¸Y¸Ñ¹J¹Âº;ºµ».»§¼!¼›½½¾ +¾„¾ÿ¿z¿õÀpÀìÁgÁãÂ_ÂÛÃXÃÔÄQÄÎÅKÅÈÆFÆÃÇAÇ¿È=ȼÉ:ɹÊ8Ê·Ë6˶Ì5̵Í5͵Î6ζÏ7ϸÐ9кÑ<ѾÒ?ÒÁÓDÓÆÔIÔËÕNÕÑÖUÖØ×\×àØdØèÙlÙñÚvÚûÛ€ÜÜŠÝÝ–ÞÞ¢ß)߯à6à½áDáÌâSâÛãcãëäsäü儿 æ–çç©è2è¼éFéÐê[êåëpëûì†ííœî(î´ï@ïÌðXðåñrñÿòŒóó§ô4ôÂõPõÞömöû÷Šøø¨ù8ùÇúWúçûwüü˜ý)ýºþKþÜÿmÿÿ ÷„óû +endstream endobj 5 0 obj <> endobj 51 0 obj [/View/Design] endobj 52 0 obj <>>> endobj 45 0 obj <> endobj 30 0 obj <> endobj 53 0 obj <> endobj 54 0 obj <>/Shading<>>>/Subtype/Form>>stream +q +0 g +/GS0 gs +170.0126953 -24.0030041 -24.0030041 -170.0126953 67.5302734 162.8457031 cm +BX /Sh0 sh EX Q + +endstream endobj 55 0 obj <> endobj 56 0 obj <> endobj 57 0 obj <> endobj 58 0 obj <> endobj 28 0 obj <> endobj 59 0 obj <> endobj 60 0 obj <>stream +%!PS-Adobe-3.0 +%%Creator: Adobe Illustrator(R) 16.0 +%%AI8_CreatorVersion: 16.0.3 +%%For: (Max Levine) () +%%Title: (FW icons 2013.ai) +%%CreationDate: 7/7/2013 4:01 AM +%%Canvassize: 16383 +%%BoundingBox: -83 -938 3544 -20 +%%HiResBoundingBox: -82.8662 -937.7588 3543.1553 -20.6021 +%%DocumentProcessColors: Cyan Magenta Yellow Black +%AI5_FileFormat 12.0 +%AI12_BuildNumber: 691 +%AI3_ColorUsage: Color +%AI7_ImageSettings: 0 +%%RGBProcessColor: 0 0 0 ([Registration]) +%AI3_Cropmarks: 2996 -940 3596 -640 +%AI3_TemplateBox: 790.5 -630.5 790.5 -630.5 +%AI3_TileBox: 2875.0098 -1087.5996 3716.8701 -492.5801 +%AI3_DocumentPreview: None +%AI5_ArtSize: 14400 14400 +%AI5_RulerUnits: 6 +%AI9_ColorModel: 1 +%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 +%AI5_TargetResolution: 800 +%AI5_NumLayers: 1 +%AI9_OpenToView: -1733 1529 0.25 1821 1035 18 0 0 50 116 0 0 0 1 1 0 1 1 0 1 +%AI5_OpenViewLayers: 7 +%%PageOrigin:390 -930 +%AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9 +%AI9_Flatten: 1 +%AI12_CMSettings: 00.MS +%%EndComments + +endstream endobj 61 0 obj <>stream +%%BoundingBox: -83 -938 3544 -20 +%%HiResBoundingBox: -82.8662 -937.7588 3543.1553 -20.6021 +%AI7_Thumbnail: 128 32 8 +%%BeginData: 4352 Hex Bytes +%0000330000660000990000CC0033000033330033660033990033CC0033FF +%0066000066330066660066990066CC0066FF009900009933009966009999 +%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 +%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 +%3333663333993333CC3333FF3366003366333366663366993366CC3366FF +%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 +%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 +%6600666600996600CC6600FF6633006633336633666633996633CC6633FF +%6666006666336666666666996666CC6666FF669900669933669966669999 +%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 +%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF +%9933009933339933669933999933CC9933FF996600996633996666996699 +%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 +%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF +%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 +%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 +%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF +%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC +%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 +%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 +%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 +%000011111111220000002200000022222222440000004400000044444444 +%550000005500000055555555770000007700000077777777880000008800 +%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB +%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF +%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF +%524C45FD1DFFCFCFAEFD07FFCFFD09FFAECFFD04FFAFAFAFFD4DFFCF83FD +%14FFCFA8AEA8FD05FFAECFA7FFFFAFA8AFFFFFA8CFA7AEFFFFFFAFA8AFA9 +%FD4AFFCFFFA7A6A8FD06FFCFA8FFAEAECFCFAEFFFFFFAFFFFFCFAEFFAFFD +%04FFCFAEAECFFF84CFA9FFFFFFA8AEA7FFA8FF84AEA8FD49FFCF82827B82 +%81827BA6A7FFFFAE82825781578283ADAEFF848584FFA7CFA98584AFFFFF +%A8CFA8ADA7AF85FD04FFCFA8FFA781A8FFA9AFFD4DFFCFAEFD06FFA7AEA7 +%ADA7ADA8ADA7FFFF8BAE85A8ACA7AF84AF85FD05FFA6A6FD09FFCF82FD52 +%FFAEFD05FFA8A7A7CFFFFFFFAD82ADCFFFA98BA9FFA8FFFF8584FFFFFFA9 +%AF84AEA8ADA7CFFD04FFA9AEA8FFA7CFAEFD4EFFA7ADA7FD05FFA8CFFD05 +%FFCFAEFD05FFCFAEA7FD06FFAFA8AEAFFFA7CFAEFFFFFFA9AE83FFFFCFA7 +%CFCFFD4CFFA8AEA7AEFD13FFCFA8AEA8FD05FFA9AF84FFFFCFA7FFFFFFA9 +%AFA8AEA9FFA7AEA7CFFD65FFAEFD11FFAFAFA9FFFFFFAECFFDFCFFFD4FFF +%AEFFA8FFFFFFA8FD0FFF8485A9FD04FFAF84FD05FFAEAEA7FD07FFA8CFA8 +%FF84AFAFFD4CFFA8FFFFFFA9FFAEFFFFFFCFFD07FFCFFFAF8BA8AFFD04FF +%84AE85FD05FFA7CFFD08FFA7CFFFFFA8FD4CFFAFAFA9AE82FFA8FFFFFFA8 +%AEA8CFCFFFFFCFA8AEA8FF8485A8CFA8FFA88584FFFFFFA8AEAFFFA8FFA8 +%AEFFFFFFAFA9FFA8FFA8FFAEFD4CFFA9FFAECFFFFFA8FFFFFFAFFFFFFF82 +%CFFFFFAFFD06FFA6A7FD07FFAFFFAEAEAEFFAFFFFFFFAEAFAFCF82FFAECF +%AEFD49FFAFA8CFA8FFFFFFA8AEA8FD05FFAFAEA8FD09FFA7CFFD06FFCFFF +%A8A782FFCAFFFFFFA9AF84FFA7A6CFCFA7CFA8FD48FFAFFFAFFD05FFA8FD +%07FFA8FD0AFFAFAFFD06FFCFA7FFFFFFCFCFAEFFFFFFAFFFCFCFFFFFAFFD +%4CFFA8FD07FFAFFD05FFA8FFA8FD08FFAFA8AEA9FD05FFAECFA8AF84FFA8 +%CFFD04FFCFADA8FFA8A8A9FD64FFA9AFA9FD09FF84FFAFFD07FFAECFFFFF +%AFFD66FFA9FD0AFFAF84FDAEFFCFFD2DFFCFA7FD08FFAFA8FFAECFFD2CFF +%A8A85AA9FD12FFA8A7A7FD13FFA8A87DA8FD13FFA8FFA8CFFFFFA8FD05FF +%A8AEFFCFAEFD2DFFA87D5284FD12FF7D587CFD13FFA87D52A1FD11FFA9AE +%A8FFA8FFA8AFAFFFFFCFA7FFA8FFA8FFA8AFFD04FFA8FFFFFFA8FD24FFA8 +%52527DFFFFFFA8FD0DFFA853277DA8FD05FFA8FD0CFFA852527DFFFFFFA8 +%FD0EFFAECFCFFD05FFAECFCFFFAEFFAFAFA9FFFFFFCFCFA7CFA8FFCFFFCF +%FD23FF527D7D7DA87D7DA87DA852FD0AFFA8527D52FFFD047DA87DA8FD0B +%FF527D7D7DA87D7DA87DA852FD05FFCFA7CFCFA782FFCFCFA7FFFFFFAEFF +%A7A6A7FFAFFD05FFA782A7CFAEFFAEAEFD22FFA8527D53527D52A8525227 +%7DFD0AFF587D5352FD047D525352FD0BFFA8527D53527D52A85252287DFD +%05FFCFCFFFFFAECFA8FFCFFFFFFFAFAEA8FFA7FFAECFAEFD05FFAECFFD26 +%FFAF7D7DA8A8A87DFFFFFD04A8FD09FFA87DA8A8A8A7A8FFA8A87DA8FD0A +%FFCA7D7DA8A8A87DFFFFFD04A8FD06FFA9AEA8FFAEFFA8FD05FFA8FFA8FF +%A8FFA8FD2DFF848452A8363636FFA83684365A5A0DA9FD06FFA77D7DAD82 +%AD82A782A6A7A6FD0582FD05FFA8A752A8757C7C7C767C7C7C51A17576FD +%05FFA8FFCFCFFFAFAEFD05FFAECFFFAFA8FD2DFFA9AFA8CF60365A368436 +%0D600D360D5AFD06FFA7FF7ECF81CF82A782A6A7ADA7AD82AD7BADFD04FF +%A8CAA8FFA751767676A175A07C767C7576FD06FFAECFA7FFAFFD06FFCFA8 +%FFA9AFFD2CFFA8AFFFA8FFAFFFFF8485A8AF84AFA8A984FD05FFA8FFA8FF +%FFAEA8FFA7CFA8FFAEFFA8CFA8CFA8FFFFFFA8CFFFA8FFCAA7CAA8A7FFA8 +%A8A8A1A8A7CAFDFCFFFFFFFFFF +%%EndData + +endstream endobj 62 0 obj <>stream +%AI12_CompressedDataxœì½ëŽÉ‘&øŸßáì¤ÁT*Ü=ü¦ p.™=š•ºI=Ý‹Á Àf¥$nóR`±Z£}úµÏÌÜÜ=Î9É$™¥ÖvW:“™Ç2Â#üfn—ÏÌÿæÿøõo¿ÚóîŸï¿ +7Ëîù³¿ù›ãûûÞ½ÿùŽÉ»_¼~ýýwÞƒô“ßütçÒÍ‚«ö¿(_ë•ÿãþýw¯Þ½ý9ÿí&à¯w¸ÿ'¿zñ¿w¿¼ÿ×WoïºûÉOAÿÝ«¯ïé/wÿ¸{õòÝÛïv~qáæÅ«ŸÚƒ©¢Ó‹tMþYþþº[¾¸ÝþW|Å‹·ÿúâ»ï^ý¿÷xX(ü¬Ã»ïß~óêíïþ÷Ïw_•°ûª†² q]w_y~×ÿöê7÷ßm.ó7%%kóMŽ…o7.Æ€»nÒân=½{ùý›û·~ýþÝËûï¾;¾{ýîýw?ßÿüâíîW/þ@y±û¿ï_¿~÷§Ýáõ‹—ÿB÷쿾{õúžúàÍ‹;ç¹Ãö¿pþëÃ÷¯^ówß¿ùç{êžTÓÃ×\ë?|GÕQÍøéùë_¼!Òoï?| ×¦‡r[~ó·‡ñ]ˆÊå'ÿó7÷xÅãD=ø¿~Új~ÿîÛ7/Þÿ ÝíkMÔÜu¡–â·´.zÑïîß|ûšúœ{&×å&Ò_~ŒÚÅÔ2¾Ð—o–¥–ÝWn)ù&¢þi”LöÕZýM,KkcïHš÷úùîïÞ½½×ÞÚ¿ÿð[Óu]ù_ÿô›ï_ß¿ÿ‡·¯>P ÓªtׯÞ}sÿšîèUܽ~Á½ÄÅõÿõŠß½xÿ‡û4Þ½þþO×bO¡!ùå‹?ßcd>ä�û»wÿƒ_õ+—Cعèën¹ñqçŠw;·üÆÏ‰ô(—ìÑ®ÿ¯@m¨«=%c(M£û÷ï_ýáÕÛŸ‡º`*.:ðûþÕ7}ܳßùÛsS†ïÚ¾õµ©>|¸ÛÚAsîø«a-7¿ú-}ûö›ã»7ïx ÑÜyKÓêõ»?è_ûþUñý·Ú&|MÃ÷ë÷¯Þ¢âçÏþNþV¾þõëïéûþÝ÷ßþâíïß=öa"ÿãþ%1 +ãovÿÏÿ} †À³{÷»÷/^RôÙ®!~ðíO?R!µóýýNþJ÷òGúù{ü|Ìý§ûßÓòìõöí¿Þ¿~÷íP±Q^¼ýf÷/Þû˜ÊýúÅÛïwü«û—¯þ•þò‚º¬×Þiª–¦Î·ÔI|_³yÄ zÔ£^|ø#1´û·ß|gµËÇÍË ñ1UþöÏoþùÝëWß½± +GŠýþÈ·ûpÿþíß¿•×|ÿýwÜýîÝ»×½#äýSä÷äž¿š‡ØÅ—@üë­üøâõëWxÿâÛ?¾zy©þ ·]¹÷Q³è%÷ú¥'β‡ßñ×ôœ6‰n¿yEÌïʲ~ðšßþéŇ—$öòÏï_¼uÿ‘µˆáýý«·ßЋþöûWîûx½{ó-$¤Ýoÿøâ[qåÝpe¯7~Mĸ|õÕógawx;nûþÅ7¯h!aïÞ¾}ñ†8ÿ”´s*ºH¦ýÍïß<ö?Ÿ?û/ÏŸn©àëHå@eO¥r)§L%Q‰TV.á䩸ӂr¼;Þr9ñu ²þì¸?Öc¡’¹¤c¤²tT–ÃÝá–Ê 7‡=•z(‡|HTâa¥þàËþnûü^iOÕÒ…û}Ý—}Þ§}ܯû°÷TÜ~©wõ–^ùXu_k-5×D%Öµ†ê««K¹+'z©CÙÚÈK)¹¤ËZBñÅ•¥,ùÍ¥WÞçšKÎ9åHeÍ!ûìò’îÒ-uÆ‘^rO•—”SJ1­)$ÿüYrT–xKåD >Ä}¬±P)®TBôÑÅe½[o©ë~­kYóšèëV¿:”pn©œÂ‘†ûöäìC +1¬!\Xü¿¥A8ú5¾úâ³O>úÕï½ó IôwîÖ¨«nïŠ#ÑE·>æ‚óιe¹[n1| u0•ŠÆ/ôòTÖ% ‚…¿ž?û¯-ÚGî‹õz£D¾èù³ˆ¯À½âù±wTNÔ74Q0üÔ;{êôP¦Jëʽ„~òëÂý$=u¤¾:poíégåþBEz‘•û ½†~£žã¾Cï¡ÿЃèCô"ú=Y¨'3½RòÔ[ܧèUô+zÖSß:î]ô/zßègôô‘úý½w•{½Ò7ú½oj5FAKàoŒ¾1*ø¦±áoŒÆHF ß+|cÄdÔ¨<Fc‡ñÃÊ(â[Jâo)QG·•ÕJàoŒ9¾i/<컕ž7_mŽXOœ´ÜjïÌŸîô÷;þýNçŸô8þÒª·kå¾[»oü)u/ÒÆŸôfüŽþ]¨Ã߆ŸÏ6¢ýçž FVÆ–øˆŽqá1æQ¦ÿãÙ'¬?ü”±<ú2þ+Ï™ô?Õèµ`F,:'†ŸËÎ[ú>Ù 9é,‘9räYrÐ9rÐY"3eÏs³?ÛŒIú›-óœ™f ÕtÎôâ¦ùreŽ\úÛ_½–j|â¯kü·ªÑæˆçY¶òüËž^ˆ¿ƒÏˆçŸˆÿßÑvÄÚíØ+2í•öì"ØSnÃöÚí<Ø2íFؕϟÑuâÝꎇ£,ÐigË´ÃUÚù´ëh÷»£…„Ý0”€/Ñ.Yh·ÜÓ®y$Yâ6ÝѲs´ÃzÚ]WÚeÉ…ä}>$r"™äŽª£­)Ðvˆ-4‘äRJ%9æ@ò̩ܖ;ZÎŽ6°@ÒN¤Í8×òüIA{’†Ž$ÝÖ;êBGÍ$3E’2ÉP•d©ÉT§ýíþŽ˜…£­0ÐÖiKÏ$ÑÍ$—HB;‘¬vGrÝBŒÑ“·Ò¦žH²+$çíI„;’üw{¼#äh[ Ô5‘dÆLòc%Áí@rå‰dÌ;ÚΈÉÓ¦½’`nóóg·å¶ÞîI<’z{{G› míÔ±wÔ5wÔ´;z¹;ªüŽþlòHåBXȲÐ|‹Þ®ô¦¼A;îuéwô<ú½þÇ` 0 +–nO<4<Œ F…Æåù3›È2ræêct`IúÄ#EcE¶ðha¼i­xÏ雚ùà±&ï/šˆ¼1)ðV·ò–·êo²ýSWVŸÛw/ž¿½üdåZ>9þÍÙÏ¥}c«•¹mWÕð«â'YqºÎÁ…IpWõ\JŽúz´‰¯ZD5u&ßñ4•÷v˜MÍM“‚Û”ÛÛaô›B›†Qojìí0Þm´“¨34²uiSVÇG·)¦6²0I1§l&)1H]6I5£Ô¹IÊŒR4WÔ,ÅF©n’z¬Qjœ'þ§Ù UÔIÿS£7*Úÿã§î›jï/UÿÉÿ«Ïje(Øÿ~ãÅòþE|¢êëRoÖVôÜ–eúyèï*~Š‡ì£‚â àˆaAÖ*ÄÂ"MbO“åŽ܉ÝX^!Ö—hbVùí[·Œ +90$1$òƒ$ZøÄb÷ªøAéóŠìè +Ÿ¨|¢î –㤎®ì»UïPI`– c6H¨¸¥­*ž 5`"pŠÓ£€`4‚˜xícå 2cUÑ(ûGU늩uM©Õ^” Y»ªÌ©Ñ¦¨"‡õI½Éf¬ÉÊh8¨;gˆ E[ˆb3â,”…ÑÂÃô9ΆÉѰq5Tµu6<ìjX?æf0 ¼Éà—Ý ] +?—Ã7.’ÀgCºêb˜Ý î¢{¡Éi»šaùškaãX d2Ü`è_&CÿlêÝÔo†þÑÌß ý$Í|ª¡ÿ‚‘?ŽF~êÑs3ÿU#ÿUÿ`à§=7ñ_4ð›yÿô°yŸmN™÷³ÈuÓþdØÇH¥åsî'KË"/³ØÐ%æ NÜGÉ˃´LTmš÷57î§ÉË43/éK“÷ÓäešGuã~š¼lcôÄóZ‰ið†ÐøfH¶5¬ ‡ÜЀ¬²m^뉖f„ ùAù)j{Œ||ñ§[¯‚<ÿöÝëoîßî~,?ÉÎãGzvnBó2üsí_ëîÿrÁì´•I¶ÒP0‰j5y+š$F“ÄpfR²•¢2_5Ù¯‘¥œ†r»Ü±A°ñŠñÕÆ/?”0”u*QŠÊ¿ “…Ÿe(u*{gcg®\FŽìÓ‰Ñd áv7–IdtŒD‘¯0”u(bHŒTÓ@/Eåþªø•VÔ•møù×åQ Ó¸®Ãèö1yyäë&wTaaѺD߯¹#-8´¦4=¡·ü¼SL›:ýï y>æžñ¬}ăê7m—x”™3oFz¯ecŒéQ±„·mT§‘DM;”¬Z™ü¬:f{uâ5Œi“Njð‘"{`[hԌ͘:EDIÿ JÐPwÜCž{ á 1 ÆÍ¼0Ý :bkœ¡jŽÊQFDi——ŸÊ5MÁ7u01¼ÿ¿Î{@Û „ST6Í6Ì]šY~ØFFåäœìfî–¾N-"Ðñywqm¶ÕyR¿¬ØXFÛáâÚ´š7kUcÒ.þíÓWôƒ«ú¯` >}W„ÞQ½:W°Dj9W°š¬²°Â~kþéž©`m +XmìRIž¤?¨Xp°Šõü»;³*Y¤|kùš¢ULÑ +ªhÝ1\îšÊ[ذ}Z¯Ê–x´›O[”-.·,wš…Þ×ÊàΆwa¸ûógªvݱ.-ø#ÖÅ.”KC¸ìÜ,±ø¤i‘ŠÖ"ñ¡[N u°s$ÈA€ï#¾Etx ¬"Þ.YÊű€Õ9û‰ýéc,~Ǻ•Õz4þz.— RX³ç ýRMŠê2ËK¬y®qÖ‰—N’ÍÄ5'ÉÑø]fAÙp»‹|îùâ‚<ñ8®q•›<ñª6Utô-æÙϺP×þö™_¶×쨃 D—Y/„²—lö×å²W”ËÁl·§ ÖåÖ†¥ñ[7a^¼YŠÅnLóû ýÒÃ\³Ùž +¦‡»îcfŽe6í ÜêœOMê2ošýOºÂ®q¡‘ótŒÍeÞóÏ™xŒò¶¥]ç18ËÇ8 +Õø yÙp +ör×ølN1¬þ«|â‘\áœ<°ª.ÁUýIfÛ95Æ6 +qU÷:$Ç8CV… ²ê¶jŽZyþŒÙæJî«åjÌÊáJÌŠ¢­ž?³ø„quâœÆ(§¹2Æ®ç'DÂÚ²§uè8ËÃÇ2¢,-ƒâ³ cIªGµ8§ÏHæ0â …Ç¿ЖR:„MŠ€<¥v¨ç˜AµP_G ÎÜïa¼ s7âe³]J +`Üë‚dtΟF™ç²\sël¤’±Pp‘rÇîþŸ¿ª?‚¤+H °ä]7´ZüƒºíµŒ­Û^w|WÜ ééz…Û ©çR®„â û–pÁ&Ht£×?{Sm°:ªÅ#$ePz_Z“¼ÏBJmLÀúѲO¸‘4sRݹ²ºF¤_&Z ‹ñž³,ôÊÂÍBœfx­'ªPß.-ž“;7]bæ ñg©,!õ?ÀÆ+z„ñÔ©²¸,u|»§©ð ÆÒç›BEU%æú¥º­îҜ՗¯õ†øüÕ ;_õ‰ñMÿþå_}\¦þ6Æ1Aï¾IÉe¸¯©ëƒÏ95€&à¦èm¾sa»¤õÎ]»Q²në];½é*nö3îÖ.|ìè·5Ý„€Yÿ9ž+øÄŽÿí¿ü½Žtó:¦6ÕxM¬Àyìî#pgæMÔ®E]ß©|›˜ÄQW†°hÅIäˆÄÄže‰Ò„ ²‚È {6'ž.8¬ÙœQbN³<6ðEá®âenpÕ“$PTÐ_|zéë:x4–ÇÁäcñw^` C +ŽÙ"ÙpDMðâÍ&Ù2¥£yš†» `—GA]¶¾âMÀJ˜°ená)s 0¤Ú¡ðæ«"‘X‘“„KCM²ø+˜ÉÂ"/D]º‘zÂí‘æàÂmT|ä)›_zY$J2QZúóÄ‡Ä -z¯%sqÝÿh8У @^èö÷)K°B·† Á +Òºžøîp{æç°²†–ã­8ìƒ),‘•–¤Ô™­ÐÕrûØ‚qâ‘[–—Aôkä8Î,ÒÕš“æ÷‘•kHNÛÌ‘£•-ì¢âœ&5gž/jèáùMÙ±¬€cHIU$mËy7b7Tí¨ì !ú4öcþ6̤§rƒô[@YBNLÁÑÜÌ]Å9Wr¢eU›S9š’cÌêÖ¢QOj}ï”K¿ßÚï3Um÷ìÿTK~‹víþÒöÛøÓ0çc¬AËÅ*ˆsgž‚–³uü¦Ÿ«2ê†N ^‰Ë#Z\BÖÿÅ!ÿ·ÌÂ{ïގ“"×[\‚åÕ°ë¹Ô›’»žÔW.^—kp”ƒ¯Þ×__w1<Û5ÇS‡±>§pi›;ß‚.ý>oOg÷°'uôwôˆÜÑ[rî­=÷ø®æsÙú‰Ï??·¿´h±=zf½Š4¹ŽC sòF®ôçÙ‡4z–.{Õ/DNë;nûÄ >ïÞ³½—ûHÌ¡ {¸€ÎÍ–-ª!rWQ¸² °@pâ˜Óƒ%ŠÑ`N/"‚ ³ÃvoÛÌ,L¶Ä¸<¯¢æº=ñë4›YaN+›£m¶A¶-Rò˜eΧC]¨[å¸YŽÛåˆÑ³3~Ö´šª §)˜1´×P´àh5?ÕÁR|2Ï»>GÐåãúnW›<‰{³ÔoqãÙ¬û3v|@k°ãTã?~šðã×çg?¼`š¥4³;v|DŽ/6gïÔœ%;êmöî5¡hQ mC^´8Ìç ÈFáòâmnsûV»ì8€džWΣ#³=ëŒO¬uHÚ2áÊ^ç¾Sßµ¬€[^¼ ²qɸٖË^Jæi8‹)¹[2Ç9œÅ™Ð<<‹6ÙÄA\Ž99;ÑøNK|}’7>å´ñ8_A `¾‡âXE×ÖÐ ì‹+é0x¸úZ×Ó°ªÎl‡7•„ÒY/‡ÜÏ©_ÖP ²/ŽXXds )é…SÆÄê]݄̓® ŒOU¡&XM©:6T‹Ún83ªš‡Ä´ÖMUé†$­2fSýÜ*ä òèfwÛ”WR_‚¥¸V®HØ®’\—–8k ⪚»RÚCÛB•i5ljH‡^±åªQ[^ܨ‡·dM‘Ôrèjâ×–M»[EÛ°Í ÞpP†e9§eûmÅRò¦þ•­+{+‡^¨ÆãP:8`vèT7•0î>RÆW+q*ç_eSê…BòNÞŸ•ã•rz ˜K ¶É+.öå“ Oh’iýS”‹!Í=¨¹óp`§®Y7GÔ^¡‡ uI+PTÚ)2‡×ÜÝ ¢v/vÕˆ Ó`øYÛZ¹‡ÖË^óƒÀT¼XðsÔðçÂæ¼½Îlɦ‡¹,¬Ç|zž“'ž‹ÍƒíyFuïµä[Ôqd¨c"°ám<®@¼Öœ›“Í8‹šq$OPË4æºSoµg‰¯q n²±ç!Ou÷U×1'‡Yìz;dÃa/5IʳŸ:±4=çÀéIî;hÎw3à~í3§´?Ohÿ˜¤ö†çQæR:ûõ §sŽÏ9ÇTà%4΄ùŠÉ™äã)û:âïšœ>ãrÖ+¨ÀkˆÀKS÷ÝÝbŸ[Ìs‹vî‘ÎíMº® zÀ é‹\?Ç2÷Øð&wÉ»G-›L=ÈÐ'ÅvÍQÊ]2>MîšåF«µIEXÌÚäe[Ç™&¹Ñ"UTÔݬIκä¬MÎúd±ã+ÚFH£dZe×,›né-ÏÉ2h˜wƒžykê„Y¯hï_ÕJ±Ò·µ¾IG+k/TcJäsSÑÖ3`cTâxP‰Cv†pœÊá¬ì7åÒWáätÛrqc×£¯”4Ÿù¥²~rá­M³Ç}qù¬ø‡cà9p”Và:z?αðc4¼:iv§ÉIØÝ„§Éú7ÙþÄah.Ãæ4ÜÛ8g'éW¿ ß8šƒ¬n‚8B·ÿ©ð6Ó\dГ˜–!é:X»uv¤öàŽ,©Lù„Õª~ +ó˜Ó™J°Ç6¥i´3.4ìƒdú9¹©€´s.æ0žê4Y8H?÷B²$9ª…†Ü©¾" õ8%BÝÛ¤+›p‘¤Š‡*5f¥%Im:nƒ¯… ¶à’9P˜d=ÕØê ª^ îe½8láÃç_çñ|×"È.@þùĹÜ~NùRŒ‘4ew=ãš]ÐÀ!q)¦©~«b;,;š3Ìt±E¥|Æí_˜qøR¾ám¶áIAif†læÍ»ä΃ý{¸ÿqÈ¿,áw6ÃÀÉ”“13 ¯SŽé +±Tý¾°Ê ed„Ò^HQx=¥73¨æK^fè¬ù’Å“ÜRŽÀÙ °Yb¢#pvLTzžªôò¹hÝËÌ?MèhbHKn›Ú2øŸ5™é™Ï±›‘Ö3Õ³mKæðÀëY§ýœASŸC©/çÀ¸¦¦•ÙÆ;)æ` ¢ž“S^Næ>$§¤-b‚OÛè_NQùˆñ·„ÿÛ3ò.A§NV»Èø«Ø·Û9°Gþ“Æôpvjä¥dÓ[ÍööiYM®Àã‡1ÍÓƒšËúa1Âf0>®¦!F¶²>Ða3Â3<ž]–ýdÄb+½ä?ñ4D^ùmÔû¸ß*®z1àtfWì'Õýõ­ñcð¹­ÁZyçÉ8 fåÏéྻ³$2£™«™¸*ÇÞ/"ÒÄÕðhœ¿ÍV‚G;pÎ>ÇÆ©Ì†È[6F>¤ æ§[69­4Ú03x¯lN:¾£e8_%ýôY*Ĩ@\I£Å‰Ÿ4’æ²ðIiq/=÷ÈTZàËSi}öéò?&Fûwší?ȘnG•Æôq«ôÑ£Š|¨O;ª4¦Ÿ Ò¹¤ê]V¶ʕë¤~ÝDüÒC_ÜÅC_Ü“©a£6lšì©…0·äæät³wMƒo”˜¡‰oõ‰m+œŽødèÇ +¥ÄlŽBé‰ÒIYÏ›(í¦w½s×Ò^9íŠÞÚFbN¤ûÃð¬'âXHÈß9ÖÎi|ëù­'hS ­hÁW> ÖúOfàÍ@ .ürÙvõuý…xí²\æ¶D§êã–ßz7Âz?2>0H½òº3G#­_Q; +¯XQ9$y8ŽÄjA0žùdf3ÕiHÞ‚`úùÞT×áäŒÞ@›u p˜ƒæÓÛéí¬ÊíI•ƒ)‚TÕK&©Ñ(ÕkÕÍÝ4ÑÍÍ@!FªËªÛÑP5M?P¿)4üY Ëz¥Ä¹¨?°—ô¨’¯F°^.åóЦáz\¹àÐ;/]ÿ„åǯ]1HM~KÆUDjó,9äé¸ÏA)b&ÃF—Î +ÒK&_“Ì ŒÆè¤ùô »:?·‡ä3Îfñ‹'¡žå•X7f31‘ã™r&5ŸuÚxžn7¡e3¤5cZ3§5î…ÒýØÍ»Ý=ß=}A÷”»mḇ^Â…²^)ñ¬0w¤ÓÕrâv¥tÜ@Qû§”3'þ\ølÙ'-®ñÑ_Tãýû¨ñŽäV#¢#k!{Áš±4©ÎÑŽ=?Q]O ¥Œ õvè ´¼; ÝÓ''5™^;9wËQOiΖ ¹j.r•á|n6Qt£üh–?ç-¿xuªw.}B»õÀiÚWŸ®3Ÿ™B¶Áãˆ5qkÜÇ_)´Á]çHãOV¨Æþúåa®÷YåÇÿR5þ›8œfçP8³³äÉ:¤–!> !¨´4œ(0æz`kØUšÜÔBI­Z1 ’çëjn!qIÞ™ü´*¤ ã›ïX~ +ê&ÊÌDì,w‘ËT#;Ög£@fáNŒeŽ +…ÛXä-;”P‚ᘣð&â(òuÔìÛ.æ8öŠf^Ùý$¥1°†LìaP¬m±ñønЬFÍiÔ†fýe+Ý_‘zºPΓ… +8xy°x=¨êqe}LÑhÅ—ôØB5>úÚÿH5f²ÓÙ9.8\9ßFZ‚8Ääd*#Q5¥|<°É+±¹ËiJêÍ7Á7¶ã“aÞ:?<ùŽ]Íá[ºivu˜ûªäæä ‰¢¹9ãäØº9Ì}Õc’Ÿ?S¤aC6„aèǦ+®ð4D(ÒIÈ(BâQÛÃÓGôàxˆú6Éôˆ /¨G +¸ G +l‘‚[œà„àógŒà5„à„|H5^Á^Â> xR ÒãÊñ1EHüx¹fÐ:+|“–5þÈQ~ä(?r”9ÊÓÕø#Gù‘£üÈQ~ä(OWãäfðÔùÏÿ#{ï³_‹«ìL_kæÌ¡‘f!(9GqÆ»I<.ü¿¦KŽü'­¶ùô‘FÕ…]t7 q»É³¿ù“ÝA¥¿$wƒts»°Þ$7ä9~à’M ™*Ž>íür|Í—jØ^ÒkÈùa¤9Á_Á#xà€G°TÛ·›ØÓ&öji»ÝþtVŽŸV¬¦mÌ+¾òüœy©,sV‡Æ,£|²Øäó³“ËyʇÁ‚9ŸŒÜÞò ŒG¿ÝnË_mMcâÖ£eÄïö5!6:ó¨M#n×\ÂnìvÃÒ˜ÚQ·zš¬«;$ªìÉVËfuH²ú$×ÌL0¤"L*‡è +³­eåDãeu“Š/q­‹¿ðË(ÓÓÕ©’ââWG™Ô Ï>¢ü—V )Ô`Â@ ¸T0¼ÐçU O’Ö<}ÿ|9ë¼Ì8ýgÁfoÀyá â!¦-Hé6}X4ŸE/Á\7`]2Žî”9?£GçŸóž2g²ýË_Ú.®‡°] +¬ó›WÆ<IJ±ÜÚ!+ýˆ•8œ‹.¹ÁœØTTRÔôƒT’ ²×Ô36¯ÙÉ&iµ<+ž‘•Ь¥Ê.·(Pƒ_ +C2,¸áŠFx¶Ï;Î&.©«¼Â2+Î=ÅИ]\Öe=Ýæ=3ŸzF,Œ7hÙOÇü§CÍz! ‚iÙr XÔBŒ¯¬ÉÇCŒ/ÌüOM¸YŸs»ìftã² `p.ðÙ r+ñ·TÒx`ÅøÀO¹ë‹Wa¹¼ Ëö † Q¾ý¨¤1¾wÖÎ⋤wˆ6m°^»g¯º½»Ý_«íhS–þ£º¼Ã…˜Èší9W¢y®¤Üý Þ3 +Íèš1)Ð6Éì¥4³îBšYM1Ë +PWyZ‚ŒgKçc›ßtÕ'¤¢ÕT>§‰-í9Ÿ@îôä,¾GvÙ³ûsâŧùßÚ;+¤gÏÉ`¼Î¬ÅX¢›G=±’[>Q¸òIÂáà¨?O|jE¢7ñô\œ\Ù¨Aaü Ä.aò¬4Û"Í:Ä“á”ßÍÅL¼?Ð"¾ãز=ŸÞ‹Ùáì`·‹Ü£"Ø?t£G»Å¯ÿ‡~ö°Ö†óŽgÙ.Æ\gº8¨âz˱,·g9-Ü0ÂûG¾Áâ+† ¬|á¼xí–Ûrrè‹9=.‡P$kož ºëN®ˆSÂÃþŽ×¸ú–¯o3œæü(Ñ_|× Ô¬§»ÄDµ‰ª?jTý¥ýã<ªÀ(Y†DE†Bö°Ó­ÅÔ×K1õ !ôÇÞnŒ'þ²¸S‰:eHì'Ç…÷Ôðl¢?üøv_øv“šh=x¶<¸¥²å!-Ë +Qò†ÖLˆˆ&i¢Ïé©´ „ãY}O\¯Š¬ëâù`¯˜œã4ßÔ‹ÔÃ,Žf±ìœáæ/übu&SIßõIëUcÑ—ÿ[îÛõÓ96õj¿.8Í&fÃm‹n •‡hIEÚÏg÷]øå²šðD5~© +±^Ô Ö­?€S‘ nѳÖîøœµÆ:qÊÚfº—CŠd;½Õí3¨$â˜öý¢éP°U³3UÇU‡ªim“¶9M½9•z>‘z„ÕϧQçRO9þ{ÛíùÔ/$"ÚÑÆ/ 5šáPÉ™#Í`„)…D“%бµ4lGÝè%V^¶z‚šÚÿZ5 z3Ýy ¹SÄ´g£ÍjYË7M›N3ØHjáEsB{6٠МÍ$ÞCÃ:,ypm3~s,É\•/–•-8—Júܧ/?iùômŽôç-ñ{;*“oÚiY¿ë@o‡)Áì &Ï›ñؤñü¢Z†C©ÆØ€ÇÅ|Ö×5>öŽ~ºåBËóHj@¡å»ÒR^hqC:¬´à!z– !B„4YP,1’»e”ÚsM +ä@“O +OÙëÙor>\?ù1p`ˆ×êÚ™vý,<Í"-9ÅÔ¡e;ýí4>Sl<l>Éìü¼´‹( ±ðÙl•¿À >}fë9²9³ ÙO¸¢¹)$3EÏYô`Æ"µquã»Y·&ÃûaH=Ü ï-ýðhzwea±iááÖŒð'=Pâ Æø½¥%nfù¢Æùö5œºÁ美e=+áJñ— Ÿqy©¸Ï-TãgßûT5У»+.å¶sgðþ(–~LF!ÓO‰èû¡fIA?'¡çôÚ"¬ŒaF3bn²d ±Üò9»×ÊEI÷#åh'+ 5nmˆÿö‚ôRãƒ* Õxù/— Øp§ÐhñÚîïèÅÌáñt_lÏù·¤¿¨ÆËŠÅzEQE…í×s9Sr6ÇH¹®6™*Eü¼ÓÔv69æIv‹äô—£Ì¬ÀeMÀ¿²LèY â‚Ô0–šl?+¸œSëkB}ØLË!솋æùÛ«¤(ÖB‘œš^$D– U"„$ùò¤¼=+(×þ}dÑý÷Qã¬ÚiØ·#ûÉÄÁðMãÿ]‰lا`'õÎjjeu¶)ªe£¨æIÅÕ2¨8_Ø?g_¡V(ær¦ž°¶~~øóöðæQ 2õè¬3Y¢«*X‡ ¶ÕŽ"÷®Ÿ>(|‰È/¥"È¥yžÃ²g°”«¹«æŒlGΑäÙR…³ôްJ5Vòo/HQWTŽ+EÎf0—s%gV‚éÒ€T£ù§å Y`úÉ~·C>˜ÅrÂ<”æšwtâötü{uˆÞ²Ü±¥\΃ƒ[v¯™ëšµÜ«­¼°ãñÈrÇ®ÇH¯ ‹¸Aaþí餯U¸<>%óÈWKW¥Ú¹_…kTź‚Ö²6t5.©¿"÷óõ¨ÆjgìµSöŽ“cöb´sö:”1©ÏB½$Z+¤Q¼ 8¦Ç0ê™y‘ÏÊ+z2Þ'à]@ÓebT€½7[£ëp¸æ_„¥ Fõ0årS|ˆ»¼Þ¸˜G‡à—Õ#Nµ¸øÊóÅùħí3uQòx®¡zÇ0o@ÏGG¢ »5ßÃ^ç‹«ÒŽ?©U%ïüz“ç7ùì*¾Ô‘/:òâ‘{£³ÝÒx]ÏÐ:[¼N;i£%óšÓ;)Ú!Ãí¯ÿoÏrè2YØ~¦×ÑþߊÐH:иÐÿ÷›ÃÑ>5/î&+. §N6xDÎtâŽÇ1Þ ‡­ŸÇX‡cÒçW;‘Þäꡌ]£ß¶/‘S·A€¤3ñâ‹/9·#³ÓB«Ës8éAuÄ·n“ö~úÝzÊ6­ö‡Ó,Y}Ö[K ö¨à½ÇýŒ›¿x%^ÇÇÑñ +DÇÿˆŽÿË ãS½¸‰|)jË="jëúqª0>½ hÞ£9 ‘~˜ÖýØ`98¸Ü.vxpŽ2v„0”|aÏødö;ÏÏϺ]ÏG<;;”-šÏ…aêù3=²™¢ZÒóÇÀ0¿p"¾$:â8Ÿù‰S¡>?>B‹å µÄž[#ÐÆ„óC÷óɧP^=ð‡“]Ÿ3-éë| +å|²èœîruå‰Kg‹~$…þ&Õµ44f>.&åÂÁŸ•2'…öئ9]N1ñ¨9ñ9‡)-OuœÒæ\Ò½[çSI·ç’ž®ž5û±9ñ±$ès +t5u³ùK"¶³ã4Ä,}r,Ð0W†£‡\Nô?¥y:i¼ÉäÁ/9ÔF§Ùè—8Õxý$奱ž“XkôÕóg_•%«Ç_Ñ,ûì,uƒÄâÁ¶Žp¢]Êœ@æör +™ÿç-þG9C³Ån1Z¤(]às±¶î6‰~òåt@?ΉçÄsâÇ9ñàœ˜S‚}B¶¬óÜ_Ÿ~ójÚ"Ê×÷îí¯ß¿zûáÕÛ?|õÕ¨¶yþìï¾å¿ùÛ¯_|øpÿþ-iôû×þî»Ðåõ·]­75….à5¥°óëzC>ýâÒ M®$o¼—ÿô'üü^>4çé?ýY>ÿwúýÿ!꟨+v¿ÚýÏÿµì¾yÎwý´'µŠwo@={Þî—¹½×/Ç*.ç +Þ⿟íß8½zùáÕ»·/Þÿy÷s1ˆüìðîÝkê‹_h¿|}ûÍ«ïÞ}xñò_¨÷¾þÝ«×÷_ÿæþ凟îþ3îø?ñŸµû?}/µœ¤Ñ/sÅãÈK1„:yÖ¬4[Šfˆ¤ •væåZËêîŸ^H]sOçn–hR”›@J‚vµÓ“ȶ‹õ&‘L¶#ÖpCµÅ]ÌÔŽ: ÐõŇ]Œ7Ž–àî%ßWâ ­ò²‹þ&!º–Ôˆ›•ßn­7¤@$"¤Gët·†Z’¾ÝWoâ»@Í\}–çùr=œe¹‰µÒÎ7f`¹/¯7¤ÑÐe ‘Ïô¼DÏYÖ´ ^^ „KÝj ÉzQ+yG#_͇”o µPKjoÌ øPZóÒr%g·¦œPµóÔ?Žìnu7¦]âÍjw¹x“½ºO¹ò$eRÓ¥t³ººî\¤±¥±ÐÛÒMu!íðW*¿ÕI••uÍôìp£¼‚’ÝE-âŽûÊÝCC‡r³Äâv+õ$qK"Ð{`j8f;Qo¤®ìuç²6e%ÞSñÚ4ôèbú¼"Þ_ÛÀ,êVj/+ªáåBO‰ÚV·5ÞÐ˶q î†>ÐtJÔ½ŽÚF÷RNvi¥ñ‹ôÐÕÓc¨âD£!Öûhú9ê¾]Nˆ‹/Ü•ÄÏWÜGÛh¹†è¨¢DÎå>¿hÕ$Ô†Ðê]X¨Q•&@YiÀi¸hðt¦éI[„޽ÙMZ¨ëi6Â)F³ +£Öº=Òô +4ñx~g/P&UÉs{¦^èCz½þƒß­:¾í÷²ÊO2ú…“â^8o&*M3ä¨ä©SáNs íðÜ‹}Ö™D/Gû|¿ˆÖ)‹C-Jh³Ù.TšË5á2­‡f7ÏžÖ}ââúe­-VѦq½ùÁ¡Gh„r N@ÓìÍL]ešš¥´Whs&ÆA 9ÒˆAf£ÅÒ/[åɽ¢FÐçé}êoH¦´ŠÜÍJSaxžô¾öZvY{q«hÓ¾Þôÿôøÿ>a/ùÅw_ÿêmÇÇwßþùëw¿ç½åoß¿ûþ[ÝL.ßò›ûoï_|¸ÿækzÈvש»Ÿüt÷Oÿxe¢ÙÓÂÐ*â<•]·KÎÔOØyˆYeLJ¤AÚŒÚγ–›\#m¨XL«ÎèNEŠx}iÖ„B›1q»TˆS¯ËÈ·Lò£ô˜#ÆãA¥)$÷ÑZEÐÆ.G©ÞU¯ûÕ-UoôØàiOw.)…dòu È­«nþýBšÐráRäÝŒR‹Èrg£â`­.àŠuwÖ7güÀ­èb4ÅSÿçy3SI‚_sÄ6W§_sؘh|ô£¶¹²S¿]h³JŒ Ïê=ÎTG[ð¬VÏ"«Ø¶ «º¿‘]ÕÞÙêÙ4m»$6“0„¥¬€ð-´¡°k‰Ù%M«½pØ"ú¥®´Ñëô´ãr÷ÆNä¨LkˆÄèH$!îìúsŒÄ¾1ǰÍ/´;ÑþW^\㪠1óDk÷p5GÜ;d]iG.´cÒZ¯´]í*í$„è}Ø2¨••m;Þ iê$2‘ +CŸ‰U8’hÓ©Õ·Œ¨9Ùyˆ5í<$#ÒÌЯ$‚@×Uˆ³,am÷u¥Víh£„–— +I´õ–Õ¶SÎ÷"¬lÊôì¸Ð;¼™©h6öpjn\Ï+L#OÌСóõóKëì\|¿ˆäd‘éµ4‚>LokTmR6wVOF¯©?­ô>}§~Y{k«hÓ¸íìs»ý·OÀýäPÚk!¹è ëר‘ƌƚpã +ÍÄ‚I ^CÚq1‚r1’³iJ —Qw&¯zE ÏÓû5ß@óßõŠH4úó” ÷µ×²ËÚ‹[E›ö ݨ*œtã,cGs'B€Æ"î)] Õ;v¢q"ñÕÛ'a˜ßÐeELŒˆ† «ºbÁè¡y–L,:bö“,}ã±ÐhY¤…Œ+ð‚'oéhKêWÑrbBÛ”@ªÐ¸(•$ ”ˆ58È©ÌùW½dª’±ƒw¶­ÀAÉ4³"®Ÿ„±Ì›T ¹S£m¡.òÛÙz¾µC)á)ëð¨Ü$£N†¨IOàpY˜sxGL)s:Å&ËŠ`¸ÐS/$7Ôe}¦Þidê@Œb¨‹DÚDëhx¨RôV{;»Ð`•m[Ú;ƒô_é&Ìð%z•ü1Ð%‚Á42éÛ$Ë/ Ðd¨q¢dÑâthŒŒÅVân¨ŒVˆÃàô§*Eo 7ž¸ýx!íÊ@ •e~ª‘íõ¬2k¶­C?ÐÂá>"…™à73! +Ë.Hw¯Eô}G*GÀ´lcSÈÔ/KEFØ*2‚>ïe›|B 4_ .[E^[eÏS‚.ûöZvY{ñVѶ}‘ö¾ÈØMt!údÜûƒ*×l[P0"ð§Í¶åVàH›m[ni§¬fÛ„8D³mAÔ]–um[¨­Bàk¶-0S~^³m9¶™™l[ÌOÁ›m‹š3»Ù¶@ð~cÚr~1PM[à¿$83m1k$=f6m1g%ùÓL[ØV¨ëV3mÙƒi Lu]KsçIŠª%™mËyZu¶l– qñfÙ2á¡Ù¶°ìJ(u¶m7Ç@¼Ül[´²ª‡OM[Xi´ÇÌ–-ZqAÿ©a‹ØMdßìZô1¬l™ìZ`gû¨Y‹ê!ÕfÕ"ÞN–g£Éëœý°Ù´* ÚÙLZ´`O-f5;3h¡!…6{=ý‹ÙžåèÁ¼Ìš=ËÑÜm7ޏ1OáÉžå çnÎÂN»”´š9Ë/Sz2gaKcѸ™³èÉ´ƒÓ[7{ÖÙB;ßä8´É­³=˨Í…©Q"ÉÑjªržÓLÆÉž…mÍC.l9ØOaókµ4Âd_êT5CY=ÍPeO›ìYöNý²Ö–VѶq3;'1jíYªf(ðÍP£Ù©HbE¨ZÍY่¬.[äÁ½žFÍKªV¨^‘Ú©úóFs–½•]Õ^ÛêÙ´îÿWÖ¬/0$ð…• +ßLdZêl-4omø€ÙÁɧб™µ¡£¬žm¡.prPÇ“À‰ûbP‹)ïßtí0æÆP/ìJ‘X¹Hgá•J ‡ÞÜ;#¨“â~îWÁöŸI!(EÝP«< »@Å:YÞ“¶>bJ•Ud`#öi h ©/¼¾ÛuÖƒN-èç}znˆÈ‹]±a¥V°N&æIJÁ*fvqx¯N ðÏ]§hÂ]Òx¡ÆPY£´§šU]ÉY½ŠVT2G{j£è­íõìÂÞ²VÙY[@AÉü™SªëÆ ݇½ùqað@†7G ÄÜ“yôÔH;B‡­—ͼ„l׈Μ‹ê&DëÅÔü„0T ß<…èÅe5ÞØ\…¬4U´³ù +ý ¢Öî,$KbSÛ¾Ì[èÙS\wò­h³ù aãíó¨ù QaÉ>u‡!Ì¥¬÷˜ËvBôšAÉ|†ÞCÙ¤-Õœ†lÓ±;°ñ<·È4݆°A±¨Úü†P\WêõÝùB½î9Ä%¼ÎÞlÈ…vs_»ïVn’ùóŒ2û‡ Õ58Tf}êìCw(‘½ØZe¶7ÛS2»‡ ­ VÙ¶­<‰žú,Rïm\‰0ùðT4§w´)g×}{0ûûeºO 5E9{1Üòv¯ ŠŽóÃ#•0»ûeöòVÓ¶•ÿAD0œN]€m²Ms쟬9â豈b3^`*„žO} }™­àL!ÉSfÅ5˜ÅB 1þ¶â$2EéabwlÕÇ‚x#û…p²n–+˜¦²5Á íVR™ôVÚ»ø©të`/‚Á[×YSÏÕ«… fº¸ ø@v²3¡.˜Éa®Ž·8B`2mUzhe…% w*P%{]² ̨“©!²ã[e+± ïÖá©ò² *¿]¿®5Àê:kéGä¢'ñYÃÝÄSbvZú,ÃݼÖð2,p8™ÛÚ‘ëÄÆoÍl¾µy¤ÁWdÚ%Äq’ym“¬¹®}l,´¹®2»®û…Í%íyU„‘ò0Ë:ÃGg56¾%êpÍÝtÝí!Vã´ˆ72¼>u¶m´Í­l„ًݯkê^W§èCgO6oÈl0°Ê l³q¯=´fgöp5ÀêÚ¶ôógƒ£Û(5ÔÈM 5ÃdSC1MØ¢3©¡`/¤;xSC¡­¹BŒ²©¡0t°érRCÍ¢ØÔP3 6&òœ|žÕP(—Ë ¬ÂP·ÒünZhû<)¡h:(lè ¾IÓ-Ù[jÚ(¡0¥å¯gZÿ5%ô¼G/X²’˜Jf%´“›ÞÈV!L3Ó-ñK +1o”P6;…Õº"öÇ^™Q&up «ÞØ+kºe꤄ö×ëZˬ²m[¯{Ç¿ÈP¿FÅàÀ&ÿõ› 9«>µ®ÍÇ™D3Ár[ ÷Ŭõlu.„·b¯Ì(úTã,J®jµ°ÊhÛ">—†§6ŠÙúÕ×jZ¬²m[@W¹Ç +f?3í¬8ˆ2@*IÍ ®ò"tøÀ¦öÌΈ€lYà÷9³{•jðš-ìCƒÍß;a®"¯PW“æ‹Q½—F³¡Ð@TìábbXV"t:L HºÒùÐJ»¥ œêtD-lWH!Ë­¹¦•½Äl„FSµysB@ËH` .ºÂxÕa.¨Yì˜ÂHm +$i‰´½8væ Îxa’7K*“ìÄ8gª‹ã…=Ô{n6©ÂNÓ„¥U›*4弈®ê9U¬Š²ƒRé#V»éØD‹É®M!˜†ÙC±ò›ÑU€,XŠ¢º çÊ£O‚“ÁMk^¼“›™3ˆMÐÔ5‘ +¬ ¼@):_‚† iu%Ž•EŸª·9(L¸Wæeožê‡Ývx=»Ðš`•mÛúJ’>6¬Ã’IÒÈ@ °æ½:… +¶…‰AcB¼Y|sÉ`†•Ë/Œ8«$ˆ\¹´¡•²;“4Ã.ÏAdͬÓ@œGÓi Ü4EÜ7…c"á.ÂÜíæÚ°“UžÁóT€u’"ó† V)BóTÄ^£ÐZêRd'çÐ$UvûÁŽÜAž—‚ 3Ë$kgÛÀâ(ï›ÚûÒ/òвhSŘFžÈbµÄ>«¥c#`«¬Žj¿/TijÕ±¦DÆfiaÄO‚=•'ü²1FÑm–E]ðº¬Ádƒl§dêÝ* &»6s.^û$ÅfÔ‰MÓôƒÚË6³"ÕlýwM%³eû”i™Óû®Š‹d • ‚6ͽN×ó‰Ît0AåC“Ø|÷fC¦ ¨¬bhIk‘Q[aüÄ"cÐ(º<¨Ç3˜k¿0‹Kx¨Ì(a4vrÄyln7T‹‚ úS•¢·ÚëÙ…Ö«lÛÖÁWHÓ˜½rX¼¥½Ù«ØTÊa,‘Ý- ðPö(EaN°JÃ…´†}œ*3Š>ÕnUrV›U·/ì®ý©¢·¶×ëZ¬²m[‡~ !ªû3é• Ò|3“±‘gö$,Í>ƒAåm³0¶ÃÆ5ôëV$! C]FiÕ[ ‘‰}ž­2ÀD²ëÏÔÏÊ@Ú«µ«z£ZEgÍì] paÄ`ð¡ùò + ZàŠ$ŒŠ#„%ti} ¹S”-Á€ã}#3 _­U6Pô©z«‘½Š„½2x)àéOUÊËöÂúzv¡5A+;oëÐŽj/.ÒƒšÇÏÈ0îA–£\0i ²|tXªë”—M’aèÂp!0ðjZ]Fi5™BÉj é•k´´?T êÂÐwkWõFµŠÎšùƒÙ î…=t3»Z⤴ Í*Exµ ÖPÌ=ЀðÐÄõÑð@­G˜ù +ïItˆµ¸>€FAV…DÕ°ðè1ñÆ60<® ÑÜI +†g£ËšÖކgÁðƒÃƒã†º…ãuŒÑ2<< rú¨m]ر4Ž_X«›!ñP‰‚hBŠ?ç­˜[éå¥õ?ö…áB…¼•5J{ª©UJ.Ò›V=‹ý·ý¡bR¤¼]¿ÐÖêÚ¶ôºàIðñì«ó‚íd¢sŒ&Síˆu£¨eD‘íÃ… +~ïuAŸ©w™6þİc«+«]º?4öëþvv¡5À*Û¶t`w0#ÃQ Ûñ‘†+12‰_qqÆ$-‹­Ñ©tYZ0k;1 ÈyMi¸0, +_µªŒÒžiLKȰîäÖ+ÃüZëøÔFQ±P^Î.³×·ªÎÚùÚ@ €¥ÅÀó)`€…9¶Z¶ˆ¬ŸØ;§!Pš†(Ô3À~H0 €ŒT³÷=jÀ(*IØ@¿®@nWË|£T7iPJfv ÉÚBXîõFcÀe»˜nÁðý‹FÒb0,…vJ‚!Ãn52ÉA‹g·‹Êĸ 0ŠJN<Ð/l1>+|¢SšyÄ.%»FN·ØÏÞ( Zì H©¿o‹€D t-v®Sì±PMe¦Å6À¸‹`&øÐ£P}Wf,zP +6î´à 3^‹À~ƒ”HM´Òð¨ù© áØÑø-Χï¹Iºáê1œá(o6dÒìpf·ô¹éuˆ h›0 úï—i\ÀP“Qô‘z§‘›Æhu+æÇ¨£è­íÝú…öþVÙ¶¡ƒÖÐ@õ@·­ÎLæßÈ€åÀÞœÇÈ™N†½ ÞÊ^Dv†7ÙS•¢·*æ¸Pã†ÊŒ2?ÕÈözV™5aÛÖ¡ÀS)¯fKïdân ÷iX}’‚o¢7L¿QŒi1ö¿_ØÂze¢O}Ù¦ ’Úlze‹6¯?U)ÊìõìBkB«ì¬­‘›Ÿ$š`ɵpÃÈY˜aq~`°8‹?0\ÜùÚ¼à·UþŒ‹È +e3¼¿ÁÝ,.`ÆÅYü@¿°…ôÊ:eD¨ d…²Yew³§Î¸8{½áBkB«ì¬­óþÀ¾®7ÍÖÐÿ ïf1,ÎB úel0Td”£6ÌÖëR¼[䋳³«ìÕ­¢m¯i­Ýï C1f`22ìY´È¼&# +F=Åñ"UŠšÚ>Ð/$V7Vf}j·N™Ö˜ýP™ÊÃSG©ax½vaoB«ì¬­Ã"ù"í}›Ÿ‹UŰŠ%(ƒ¼ÙÄ-Áð“ÅÈ-AfŒbÕÍìB§ ž^—Qô¡/›­PÉAB…‡Ê"8>U)zk{;»Î`um[:öé(­ð[.Yô’8›4ÛÉ0¨qÆ ò±ˆÏ*D\T=mUåZ†»c*ë}ª²ýF®‹à¢{eDÉLÈžÚ(úÔözýÂÖ„^Ù¶­·Z‹Ê&Ø¡°vÞlÈèeÅÛÕ5ï 0ÞNŽóª¢Ö§øñBÚ’ØjÛ+3Š>Õ¶?#—ÄðÅVÌvex¦|ÖÛÚ«µ‹†6i5ÛV>ÕÊÜæ{c…T¼}AðSo6d`¿ ÌÃtËÎÞÕi¢€p;XJ¥¯¯äýx!½„oè©Ì(úT³1Y2¢Y]+‡ Ï‚q}·vÙÐ*©hÛ̱C¿D ز:Q 9ôUcEßlÈ€Ø 5— 4ÆVþYˆoU”Øu¥‚­®Nчš×Zɤ¨9Z]°ôªÐ ÏTÊ˦<ëËÙ…Ö«kÛÒl’Â7éÈÝÙœ_ºÊ~/T©Áí ŽÑÀ˜ëgmÉŠ™ži%q2õZAfº¿Pi¯ìÄoõd‰5éOËc༽Sn!)í­µ¢³Æ`/úuETù=Jݶ$ñØO¯R1ƒƒ¸YCne½U”c» ¸Š"Ê„Td}žÞר˜*àWVU­Ãó”`cy-»¬½x«hÛ¾jQò® IÚ »µÞlÈ“yxª ø,^IŠ×(ÆåRa¼PãX™Qô©Æå”œô>TVTéO-C*”áõìBk‚U¶mëI Û>õQŒá,·Ã:ûf&ðw6ô¾Õ/b­c9Ý7KŽTb…¯o­Ãe‹xõ†š¥=Rï4²çæìz]l4 +exf£è­íÝú…Ö,«lÛÐJLkMšóÇî¥S½"4àff”¤E ]“B'¨fnp$ÄxVçb±ºŒ¢Ï4¥RÉpÚ0¼Ó*Cª[W†‡*Aï´—³ëÚû[U›fþ0”í=‹F·Ó¢1`¶‘aÝŠ"«Q5b‹”I¸XkH¢mã<Ìu¼pa;ÉPW#è3íÆ¥MÐ…°­&¢†¾ly·~¡½¿U¶mè“mÄ.‰9æÐ73µ´¼I —2µŠQ§CtŠ +$kKÆh’€†,QCeFчšÕGÈÔuœ=¯Wæ  êOm”—í}åõú…Ú‚^צ¡½Ÿ2^î#apOèä:4¨ñ¹ã¼u[±$Ì›š½d ™Ê(´~8¼ "WJìïÌæµÐ!Þ£6oZ$<øŽïFRÏçGƒw'dÌ`¼÷ˆîF@\Âx5p7 ¶K.Û IÎaí†|i .NçÌÍÐÝ‘aúX7=náÁo¨nIõ©£ºÀ¬\¨î̈µµƒºs¥5Í(oÅt³°ÍöÉÒ krÍkê˜nÇKv«Û“‘@©Ö ªp ÓxuC”[C‡tŸ û™Ù³ÀF5º;UmêHÆÉÚPÚ°ÙmÐÜþ‰T;5Ó hÄ­¢NAÕªàë^‘â³ûóFw­v™½¸VtÖ¾x€¾ ¤â7ømPt +‚Á¶KœÛ™ƒm‚ᵉ—#¯‘¡µ9+ß`µá qšm‘¡ÚÄ;ú³uL mZØöx£¤€×áÚ¢³ÃHZ:${Ù`±—Â>º`‹S ¶‡V³E`COïèk¯oÒ ÕHˆ•Òy½r’ÂNDn~¯P[†]¯Z˺V°¢t­­~ମ£·2ǵ#­‹¾LÃYc^-Ám`Ö¹è’W”5zgÄXsŽâ´AX{‰Îå°†u:¥¯.Yr|CÇàdkàjž~ W=ÍųUŽ´ª§®#ª;U1М> +H¨“Ã>CSc®®e f 8×ëé„ÔÜ© +~î)>Ú7¨ûK)µ¿¶ÖsÖºÞ~XðbŒu§6Ð3[ËX4¢ò=MbkvuOÓ¦›ÆjŒ0C§µ[E†‡ÖÇͰi}§Fì/­Õœµ­7;pÈõ^~3QÈ+ŽJÃA¤|Îiƒ—†ÑÍ•á*lgì_mõ4„\îTE8·zmÒöJí"kI«dÛ´Þj¤ÛrKÝ€¤;UaÍèP7¢#yPh Áúh» NUV[[EFʪ€æ^‘bžûóFlt­v™½x«hÛ¾Þt˜—"çƒqÑFmPfZ15pF"E;Ãê•Ùý>¢¢‰Ù­>Tøf—8à«0”;UÌV‘Bíq#Ú^ª]dmiµlwÍ{÷½çd^²“Èá¼nmÑÙBÒncç6€IøÏ]öZ¥»ÈK#LÈE£6„£UÔ@ö¼ *Ùß«‘û»·ªÎùÃ(+_”Üãê‹Äe÷³ßÜ¿¸tÎéÕ›¯}ÿþåýÛ_ÿ_÷ÖÚ×ÝÏ~ñöÃ…ËñãÅ?¿¾—üòÝËá¦xí¦_¿¿ÿ×W÷úú7ïþôÝõv/D•¿ºÿn¨ªJ@>ÛkÍà#|þÛý«?üñÃcßæøîõÇßæwï¾ýš†ëîý»·>zñ/ïÿáìj‰œK¿ù?¾úæÃ¯Žìís9Ûéöí7zóó‹‡=ý÷Wÿz£žø'ëoIfnâ@|è/µ¾ÜTû•ÓAO +&ÿÔŸô‰­þÍš+Ç5ÙÞï—C‰sÑóžØêMûÉ‚s¹ýŠCÔ ½ç9´Û·C»×9?N”ÜÏȹZÂyP!¸"O<²Ÿ‚àÜ€à–XŠ „µ2°D_ØØ»híÉÉÄB†³ÛÀ¡9E‚ÁóQÔ­+»KRwe¤Ï€=v÷ k?¤ìÕÌgÈbL¨UOä``”±{&(Õï*©æbüVæóz‚j—&äfBð½urº@€•ݱÈåœ=ȆËû/›6áÈ }YG»zž±Z•»(Uhi•ë!pö?hy«aCGòšœÜÖ*”ÈæG[Ø 8Ü ïgžzˆÕÞ¦ਡo’°Õ¯© òÐ#~G˜E‰Ûfû’„$ÉàÆ†¤«I]”El «Hä•$³,_ç–@Bpz:f,"%=…#Ž“Sû/gœXà@”øx9ä°g™ZSCŒ»fHèN¶¿PY•² +î¡~ëÊ–Z‡£óVµ‘sæiäN[ª>•#à@ñflØ•šîuØ9=²ˆ† w‡ã“@ ÉäTÌ ‡®l‘ÊIT;ôÉêYcLšoQ£œÌ"À:s¥HnÁ²bh­u‚ž2îVNxW‰RËòçõ­"7e^¦ES’½/pƒzcä‹$‰'êQà¿™ +Ë5z¬Q0daè‹Â>%Iå—"üôEõç +›?]{´;WR+ŸL €Å° ÕLf@ tŒ£D&†5Yø T +ä©…q‡‹*š]¼¸W9ƒ #-p‚©œƒ(K/µcŠ2:Pb$h’üy5Ç;üÚwÒ˜et(ü”HIX9ß®¤®”¯øCCN +ŽF±þ…µV8³Šÿ„\Xá¶þd*R”ÁÜè9Ø*‰€kç¤vP‚¨[AHnˆc ¨È¹HŸ3`¨‡±˜ ¬AÒCóx£È<;,A㜯p†jÇ>î¢fEðm]`Œtí…ã‹\[HQÞ*”yš[ˆ‰@ØæEli‡a§¿´3Ùˆ¬O¤; ?ƒô>Ò1Öá¾"©UZÍ/ÛоΖj‡Å§HS–ÆÁ.ˆ\E¡ÔÖ9y^FðW¼+”øVü"P× KÜ *›P€zÄ©z‹nmD ^*ö&®„ñ6Îmšàïók8¸(±,8:[‘5~sÏ],8áÀi+Ÿv²J09ƒ à"J†½Ê8zþˆó$Àb˜ùD7³\;dœ„ù¸³3P=ÍË5I—³Û˹‡eáÈŒ$§ ­AêqF œX¨líMIrâ¾ì”ÀÏKÀ•ûÎx+2œÒÏÄÚ"ìçj]&™F¼F>ÃRÙ–'LC¤Ó»s4É<‘½)ÉËÇÛÆu¹Î$Û²®ÙSWšªÕñPòF®BB…±*ÊPiŠ?ÅXfF#Á±xìœ ƒèçˆ`lüy‘!§Õ(à/ÎCB„ ½n•!Ý~¤y¡õÇ må­+i”h)Ž«¶:Vf +ç™Îlc\‘EîDl÷ +gO©5@ÛüŰR/âváD`#IŽI˜<38² ¤—ƒÞŽ0Y% +Ò3 +—_¬v8ù@ÂØyGñœaÜw¡CB³‰‚§3±ȆŒ’ìÀ±-Øö¶ bÃ,âLYøX4dÁYÀ-¬õ áeÓÖœ]†#8k?.’(Fà@íwmSãU„H¸*+ž±ðŒ½H³.0¾ÏC³Xˆ¤¹¡>O”¥pP™}v%¹ŠiÌ Ñ…•å2 擃DFò+‡ ?ŽÀL’Ý ×.Š.ÆÂ&;ÛüðÇQ¸Ø¥[f+R/6GœÀŒÃ&HØ•¨¿•϶T †¾e`»8L}Ñ«¥ isA` d* n[ì„âd5ÎY¤6>—sS•ŒÌÃ*[¥¶­ˆ³žMiAsÏ!P†ãÅŒµ]ò éUÞŒÅu„d“eÃm‚¬\xCegŠÝůžjk‹çÓûð9&lD¤Maé2{–Ù…<ÎÌn0^$òà\ˆ„ÝÈi˜EìåÇ&ê;ô\dJ`½ d-¨¤ÌÝV uXiñØî[$’uŠ ØR,f„ÝùEÒA Kpb}ifDt€šÙâU$n„ˆEà]ÅŽŠù\¿of{í@_àýZã âæEÚ§üÍi§'Ñ?ÖUuÃ\’eÈý„ÅXƒ18 qà Ô³«*ë[’Öª) +#ØT‚<–vE¯]†ˆ^ì`Ì’À3ØÖ÷Ñ(Hò)QÄdiˆx­€C`×_£îŒœéËói+Á„P3¼â dÖCV^cˆAuBà|ˆñËKî÷q&ÄuÕ!¶'î'© 9„b1ND´È¹·#›qYažÁnz/g2KC‹“¾$q¾Ðˆ“°©<ï¾²Ö,Gš‡²ïwvé ? D^›HzÕBiiI]Š›]T 8 ÒKˆz™cI’†Ùø\¬/‘ølÓz)˜³ÓgY§mÛ®Q‹ªJ ua©qp"°ÉgÍ*XÙEªà°A€³Í5Âc1uJ…}êŒ$²¥ÊWh†|4N˘²<œŸS‘G…¨âå$½2'Ö ‘X[HÛ`:茉áè5A$‰[4C9e9«‹h)z\SFïå~PY ¢ñ1 câ‹¶°³0¤Ð€ _ò’vŒ+ëU"10³àÄ¢¡M0޶ {úÍ¢ ‰½ŠòX]ؚ̚cOÚƒÔkNj&ñ‚üÚYÅÖEó’â¾jQ +K•¬• zÖo+Ö;BÇm°ê ªoX<|gõ6 =”-è¤HÔ˜Ð&™ëÒ `Ì|ås“ãœÈ‘8 ÉI&[Þù,¬Ðø3"¡ùb?ΚÑaÕžm\âÏ_V!᦮ãÌ”h,ÄòóE<$‰¯è[Ü!)ãC÷ìAE°Ä$£›œ£îDWäÏÙé³8eÎKK¾¡.=>TñˆYrå$ÛÿÒ9J£"WpY%>"I +~:ŽyeŸ–e"ay>!Ö3iú]ÉÚ™•ƒ‚ 眉Zf÷±¢ ùM4W0§]Ⱥ'csäT]B–Ed°Ûm^"ʧ¯Â Ûdù„ÐJD–B}´ÍUeÅ+ +„HT%˜#«@œùÌF0͈­£ý²*V4ØgÄǬÍE š4*ì®QÒGÒþÃï)“n#wžpdá’DA柞Ðbä\bóBúù¸ZFäaçõÌV¢æ-ªnqÊ>üÂ;Au!u´dèGL'þõ° _#"È):Ùº ”È1ðŒ á\Ȋʉ@YìxξԴηòi +òŒ"·z9k A—mÁð3ø:v¤éi~‡ý1a ›‘¾`DØ$¤¥¡h`4–V9Ô‚½ Å怣ˆ…¬’½HUòL°öøs+8òE?LY®ÁGváÎjù€ÛÁ¢gräc9x©yÍäTžº–Ü6Øá™‚»MÂüq]àI¯ ý ѼAc£ÞêDı"r\b@x3sêÀgVD—‚|õ±g j}ÅúÀ̲š“¾#g>:YvÙ*ŒlËfdEø¢œƒ‚=aåÀá*AB °@ À¼X¹9‡¢…Äl òš4¬ˆ-¶hH¬Êg¤(¬òÛ­,%‚+òÌ¢2>Ì‹ó?‰ŽäIø¤Ë«ˆ“µÉDï£×Il_çé–$¥“X Ë«ïGÛ¾ÃfHXÊàÒu˜íl$Žú•KâyÙlnbvIÁLЫX’äS%%›_&Ââ‡WIéÌ65¾JàB0 z¯Ù>Yt²,Ì0%ãÌ‘è\> µ +ÿ`¬‚ycºHÔ„–uuða™XHÇ/–í” ÖÅ|°£r´÷ B™ ²yË®“U9HnáäCšMÜåBϲqU™‹÷ý•ÂÓÂ}µÝ #ÃCÍÉËâEaìL±4ȉA ìÉ—¶¢ bïGX¹UR‡/* ÁZÇf]ê¶éu^Áy²•Í0†žmÖF€—'gÀ±*Ò‘U¨Â:g'ÛE–ƒTü®» ¦9çд;E^û¾D·¹JxM³aEmoø,ÇÛ@â`ƒï*¾Rܶôœ´HQT¥2–m8¿߯[œä¦rRÙò³Œ˜(4q§XÉY1PgO"2öÖ$SE¤XÒ,º¬Aé(||#丗ª[Âémpy-’ÏHÀË«¾ÅÐ)¨—¸Â›Ð +ó¦L͈/c ‹ #¬¼&áD_‚=q~‘V˜o{uy‘ˆÇöÉ3ÙçhbÑå¼ë4À®H’ +⹂QjDCr“‡{…Ï3C¾ŠöO›ö&?E–pF8áŽ|cTv&EV±©Ðñe Œ™-€Å>š¶È":Óªy°¹òÀÑU’±¢²Óë¿©ÂN ð¯œjLµUÄ®±xôÔ·u²ÈâÜ¢•‰ €ΑµA­”šVrŒ”«ØîV®x\ó &”ÁÎÈH6ÔÎ02'éÙ + ÑŽ.ø`ïmSQ2Eð:¾ÁÌ æXЙOŽTl)üÖ~>/k† +>¼Ê"³ÛpH^í=ž÷á€â*P &€‡ÀÔ¹$“^«"3œ,†íÁœÉÉ@²¤IcEŒ£3ôìml€dë('w\å2¤¼¯Ep–ÜÑò +è{~‚ +ôÐÚ’8Œdm,’}‹Q6ë`Iâd1¼RWIÌVäÄYa|8”çyŸ†ûë³(ÂÓ©ù¸®ú<°i‚émlväc‰ÄÆÈ¹·ùTj$‹Š_Yn¿é{ RÆ1«àØ¡!Ÿ²V‹¨S†ÇÀ‚Åï]ŵ*ûb¶a–ÃÐÀ H+§”ô€ŽBšAÆR1…Áœ*3@ô&C™¢L<ÙhëN’® qÂ>$t"°ã˹ƒsðùÉA®Lœm]ºÛncß5Fkœ³«rt¯S  #‚ùþ¸dÂîsÌÌùŒ|®0_"2±FY­‡XŸK€ƒ ¬`¼j“d·`Û$;ïyœ‹"r!‹>ý>ìy€‹-¢ë0¸2(ç]¢L0ïXÎ"H‰Ìp…[! "±;ÚT4+6`‹¬;iŸ”Oj¼s +^xàc4 vÎÎù5 +"O|‹pâÁàÅÏUîcS®€dm÷1^Ô¢™ÚYþKA½s @M` ¨‰²Y#óc¹1ê +ÎQΩWCPðÂ×öq AÅamB‚+g5`PIpýÐ>àË<+É)ÖŸ+€NÒˆæäDÜÕ»‚øk™Þ­‚Ôbdõxq//wðfâ ¤rF¼zÓ¢W,Jβ1Gæe¦ò8yZ\56SX!ážäHøYKOEÖóË6ä¼ê€tæ” +I7- ©Y> ¸kpƒã%‹ <“\ÄNC|‚‰—~~Ø¢ÿPY/b™Ž-y¬ñÉš«˜;TÒ½,©S/„­4 P”1ÆÐ/Á3B÷ÝDサ°váùà@˜8 °+³2/ˆÒ;ƒÈÖªEMû¨§èÁ_©=.õà «ø*VcAs-ÀˆÕtjÀ†óíWމIêØPµ.^r6…ñNƒ ëà;‡„(Ó§™ÚÉ+gÐg¯*M¼ñâMŠŽƒH°I“J±Ú"OŠdHDP9Ž TÞ¦|°T ˆ”Â*5›Y£W†ã:XT€½Qè|ä­Æ’ÁCí`“Zߓͤٵ\xjx6i$ìr %ê¼E<8@@åêƒnoQg²b·Ü] +AûÉWœù&ÀOw?ûí‡÷¯Þþa÷“Ãaÿòå÷o~óîà \¼=k§Ú@°`lŒ°0¼iäÂñ'niBWÖtHnp"Ëœ9†Z±=Žq —U„FîJÄF!°Ë¡=®‡p$A)Âb¹²•ŸŸÊ1@P/«Å ª=Zrê~a•À™WDùj1§—MpLÐ^Ä3Èü„Õ/ößã@`ìbâ¬ôœ‚7½ÍÉô泎Þ8™ œRf½½s‘ÍdF1%&±Tkdˆ“€PزaZŸuF£,²Â;ŠYØ>@Ncòñ + Aa•¤xfœsQÇ3s K¾é*´w^˜ÊpD0êøìtt9L ·­kì·`69…â*·1dv‚ÕILóߪpm”BÇG_fi]sJn†nð0ð_lioÂx±…—,Ãwù2f=^¬‡L@ KÒì1]ôÄÛƒ*óh Ç%ä +Ó®°-u_Þ=¢p6 ú ­&ÍÅ"™ŠG]ÄGS†“fÚáóÍ5I š­ã|0|»sq6LeÖ‘*³¬•- €tõ¤e´±…P§Eù&DE˜Wp&»C>—ÅrRƒ[6ÁeYõ\ÙÈ‚Ìu\ $èä¤qzÛ¢]U—ñ™p„|9œ³¡>]š—   +ˆ¬¼UWá‡b¯zà +ãdbph "cì*l¾Éqòq,CzÁñ.ˆi0©Çó .ã~ä£_JÎ<ãd Ɖ9ØÎ‡phÆ¥-Oˆv¼Ì²zÉù€£Ê¹ |?) I‹°ª`ç€p°F\¤"Iì”D‹0O&À¼\lþ@HYy9.ÊŒŠ|i&(xI(Ãr¡æ‹Ãn-"P,ßñ@ˆ‡(«xÉåqkÁ“å,O€®ù­VÕ3ÖH´²™©aâË*§`;:×¼J +¶Uè}QاhE¯Ïôö"5 “lîÑû5¨ aÕpœ((§g¹À¾{h ð],ÆÙeAµ©Ì˜á2 kªi£–(ÎÏ.Š% œk¡ÍMøBªc Ä?‚Ža(dôXZ$“ÄGrƒæó`Y=4~—`q… `AŽmxìÖˑǯÇÏðÜ'†Äµñ5´$xГ—•ÁØGŒ]çaXô•×k[eb3^šyò beSú±8‰\ޝ‚$bby¹K'ž×|W‰@å#ÿ?öÞ¤W—$IÏÛ7Ðÿá.%Õ ŸÂÝ—dŠ‚(•(‚ ! +‚P ²“d UD³¨†þ½Î;˜çdª9ܸà¦*݈øbt77{í1$ìy@å7ZÊCfMUfÊ}W¡g®«FÅ8 !ÏUVÜ îÏ· +™)•"²…œ}8Ò®Ao_†ˆ${µç-}ãÌ+6}V´ñ(MíÔ8/#0¿ÂƒØ”JhçP£)SŽêÜß‚\5 ÙþV(’¤Y¯¦’•Lc¡D%†È¯E7^m˜%QZDÓÂË,®á¡åÐ2pBÖÜT£ì’ìð`ÖQ?ÄöjÖ_j“ú(‹I(’àž§Ê‡XX^-åÒ®³߬¤Ì ’¸¸‡;Rœ”êQ¦O3bäõQƒÉþ°è¾>i9bt]ÁÿDŸbŠRËÁƒÌ­#²’ƒ.úh{¾Uq>¢x¼.ˆò¨„ÆÑ½ +Äø1$›=ÖU$Š +ëiÁ¢bŽ£ÞÓæ×½x!¦Ijª!oøvÖ¿ÿº€eìK4ôv›y—T÷ט¨¨)†(NÍ¡QõUà+-U—†ïNµ2ì2Ä%Ö©¬Ýyå#hX O^uõQ™¥ ”̺=ü”ȤÄ:N‰²÷š/SN±W¶1.ÃÃDÒvùkÌ¿ä@e& × âdrŽ%•|…¢ÓÕAX?ؽHy}$B>:ð P´jÅZq¶I¿Æ‚Âɳ\ÄKv4-üܳH«Sо +Nš3céaQ)LŠeeãaH¸'å¨)ůä C’؈­}’Ãt¹G&í†iŽ}Ö±@ÇN\„()DåÔ„ì‚ä ÐÎgºŒJ´ª‚ÄŽq0tbœšQµ[5$ Y‡GðÒ]Åo×V“îDR쪾j5j”?„ø±ddŠWßh|3ÙfÜO$fYÃOd‘V^Nˆ°t Àd­»(Á9xï¿yþB½-èW +Å•?üá¨Ñ¿Zdöø`PgúvòؼËE{*åG(ò—«ýûX;؆FÒ?š4C4TöÈV ví×± Âr1Ü Ž§7à bw¸Ïµê#+‡‰RVš§±N†ã–•o~Îf“bµ†hd +±?îœÏØÞ€„”M}»‡xB­|%î¦+ï|ÕH@uð²ß*¬ÔXŽ`ŒçÝ äø¾f>ŽÎÞ“Ãõ³Æ³röv/pZb´þ!žëwXΖT=J!Lq–IxÄ—K>ÖÎLúC ++K­¨ (Lî0Ó)ñÂËh=C;9>Ç’Uu¹ŠãKD»Ñèyq¼+I±áòÁ¶j˜‹Ö[ª…׿¾®¯NÉÙŠƒõÂ(F,Ôõ×sG¯Ëç9¸+¬o+Q²˜4¦ùâå·€ +о[MU^¦ôÔ<<¹Ó<Ô9|€eŠ¥±cêp¨ +¦ê¬«£çTœ†dýüPîR0?½¬l6ÇäFñøòšaCâ-Ä':ž5>¼Z‚ÌrúJÄÒ€DÁS©Na‹6òÞ’tXUŸd"ASªŽ#¢Ñº"Þ q‘áªQ­âXéAòSM·@‘.œx?;|iH€¨‡[aêbDSW©ú~[?CÿHóœÚµx†XþÒ=0¬8¬tJp4ÖM£\!Vâ÷$~ë’CþS%W ’!L½^±A\ Õ“ÅŠÁÚ-‘H/kqa¢d:Íá¿Ë ûÎÁŠêŒ(2¤Š³å²P# +ÖõI{¿.ÀÚ(c×ø#b—u®¯šõ° ú‰áž±ª!¥ùñ^¢ö÷•ƨž¡«‡(:r½Ó¾_ÑßÊáo¾áI9ÀµûŒ z‘3Ž3˜S®ú‹2ªâ2Aû8I2(,K2«˜š…KÙ¨¦ì³HÉ-Ž8Ö( • •ƆíÊÅR÷û0`yÎ?¾ ÕIŽ”Ôãž,VÌ.q–¹=g%(ƒ¯¬8‹e^p$£‡ ·¨€ÊŽŒ¬ë£¯õá²M,YèÃ1E_&b-{ј å”}¸W¯y\5n_>S:…M5=\ ì•Sâá3‰ãlÄ×™³‰xáÓ¯B8uHZDA5ýmÌ|SRþM®ÔÐw¸v«LL«f€³×`p¶>»í‚•Fi|úX‰—¼Z¡~¼mx¯ØõUf•SqoA{,­m=xxäá!XÈ’náb¿Uädb`Ž#€«œ0–µÁjrãÊ8z }íX#áèT" þ<î…4»P™ÄÍBUÂ’Ì0ú +KÇ‹f«K §ÔäfB²2üÛéÀge¡µÕì¾+*¹UÏ ü|Rpeåœ'Ï9Ø o5¢€XV¢"Emèy½ý” á*ö>²‘ úy30Òà8Kw´×/ÝKN¶—D¬£KC3&¡~qjúû³6ð£ÈouF½ö³•Ð|,&†æyè6ȼî2{{C!ùµÙ|ŽFå‹Ê—á9”gË:ÎŒ,dJ£Ø&“Œ|fŽGÑÈ1Èö0sZ[Õþª}kÜÇíÌ•Žl¶Á° ’JŽxø¹®ývØgE¬÷±…×ì þZíµúpF¯&€P/ã€öÌ"´nù ­Y­5ÐÜZñ5âQÑÆùuôäåx¸!rSìu°¾×YœÐž )R§‰%þ&DrimpœM±²Ï‚¬™·`½¦Ìš§Æé˜A™¥6Ä»9šBTQ;Çú+¼ÉŒ®¤X×pªÍ?˜Ðžù¹ä'ˆÛc ½ÆáºóµóÞ°"3Ì»‡·¼±h3«„†t½v$,3i€¨©ö²ŠŒ‚I˜` +Þ^v^Ì]kb_žùm0k…4c} š*âÁ%×™é˜ÈPŸ$ZÏ#KâË@ÉÜY¹¬¹;eÁó  *ÛçqºØ~ô‘Ñ…¤ÒÀ|æ¶8WZ@¥ä° ¾Æa•WÕø 1ÔCÐGßY…añ8ÑMË\"ƒƒu!=-ªš†Vr8Õ]uDY{uéµVãL5U•T“ÞÁ]£ìú‘]z­EF9fw±ì£Ëü«‘ó8EB(K¾N&ß´$Ÿj½Äµü¶¤³ b[³¨ø],%¤|yUÔf·(CBÀD·µÂ0µ—:X’.¤üæš>FTû8¤I®‘¯fm`a%¬&ST+ù2Œº®ä­ iRÝ¿a¼§¡6܆ ¡ýh{ijåbÇ¢”½SUá(ŽåÄMA&ÏULTဋAžnòvê¼Dšä]Û-í’^¬T£WzLµkÆ…Ù +OIú¼+ñ»ïñPßÓ•Š×gÝ, e¦yæìCÁSsb”À0 €óuÉÌg/ê‡ïî¨ýw¿ +æþO9Ú1¸ñ¯´äÿDLò—ίÚ×_Ôd|Ê©MÎìtV3¡f4O»Ée*÷Èd4ÂÅ×Ää—ífÞ ˜Œu:^ïà%c¥ûñË —ŒUÙP/ËMKÎ,ò© –Œ¿q¶ÁJÆßUˆåJæN©-R2ŽÜû\ äÌâÿ“ õ¥y‹Ìv"¾‹ð½ ÉÍ2´“‘ ‘8Ýh#’QXЍM’«µ]7 ù´’\‹©»G®E㛎\‹j.Ë‚\¦¿ÑÈÌþådäj…’ÁÈÍïÅE†bTÔ^c‘<·¨È iL8¡ÈŒäÒ7™ÆÜHd +JùDDn®”Y@äV¤ \Ä…eòâúñ¦~§Ynúpž‚ê|8+ÞèáL ü .îkmîpaV-/ìp¡ö5ßÔaäò²êÁX“ ¤¶NMº¥ øy#‡‘ +ÉC ! ‡†‚Ö8üñöâ¡8Œ‰POÊNðõm¥­oØ0O߬áGªû5 ü]ï›4Œ[tp†e“ŠWƒ2 AgQÏKUíU®.Ä0HÁ˜8bù1€EžB:Ý€aäôž¾Ã(Útáluá5ó"Çš„­¥‚•¼ÑÂS-xo´0²Û(o +²0ªþÚÜ`áøûâ +‡1°ÂS±ƒÁlÅŠý„ +£¾c.êB +¯¿O¢p(Œ*(wñ„ýÊ]8áÉÒûºhÂàÀ¡ ˜ðÃå´x$[¹ÄQA†.…¸  ?¾•O4a|¯Ô·Mø7ÌsaU8ᇕÆB:ïa³o9hÂpÃðwô^}ùKøIPœŒþxo88.”05œåIsù“H ¡¸i€„1j0°r„qKé¹HøÍé c‰ó h–6Gø1Ø/0ÂÞ”qS„±FÌ* ÂPù<­C£ÑÓóÆŒó¢×a XIåCC•róƒsÓÄ`~0KÃUüM]þê°°“_8Pi}Áƒ‘üÄɪԦ Ñ‰†çöª~™ì,¶äuƒ!žDpçâ‡1°ÁPµŒ‘5˜w…|“C™^›`C»€Á1Áøw¶9‰Á0¶c’ §¸>xÁÐävÓ‚¡ + ذà2ͤ5+bW~ïrÇjIK‚1âq bp+R\œ`xûˆ †1BâM Ž¿/Hð2šŒ&ÑÓÌz¥>û¹ÛF@ÚŒ´¬†(ý]ˆàT]f¶ÁÐOMv‚Sq¦y‚±™(±$ábåÓœÈ/ ¢Ä8±z²õO|`(6XÐ~ìúªwÃâÓ2rùÄÆ)Í\|`!^gÙ|`iyÊg@0ÑñÅÙ¦âKvŽ$Á¤Þö4>‚i*Ö€`üS® Ìÿ`Æë" \Æ&ó +÷Y„`þS2WyÓÄòpa‚™ã;„`>!’ë.B0rVÊ™Œ›õÔQ6!X¯Óq'!˜é:$ƒL(-ÊóÌ~Œ‘^ˆ`üª€!§¤´]‚yL†z/B0ZŒf!˜²›hKDšÍ_» Áw½L{Ç Q¡.B0ɺL¯!AQ…™ƒÌ袲Ÿ'!˜ ;}W&3|4}³XÝ7›àF7 , ®Åª’ôÀ£•™ëxàÙ¢×|`nÖ7Ç™ÎÊn80‚A|ÂÁfØKµ%fãR(¨ºÙÀsú»4ðL"..20²©~â#©FsÆ"üÛ¢Àeë 9zì™ ƒÀF+sR>Qè®z[ŸƒÂ`©=h½óºóón 0!¿Êƒ[ŠðçÅž.Ú4‘0&LÆßõ½XÀ0Qc0Žð(~G0ñ¨Ÿ×N¤´HÀŠÍ;½Áò ÌÂ]ž$`mdk ˜÷¾ê¥ÿw ãý…f¿«/&QÀ4 ž(`ŒÞ(`å€Z^(`%iF_(`¥æ¸QÀ8mªÝÌú#V%G³PÔçâk¹XÀljÉC°€1êóÛ3 ˜7†Õ„' ˜VíÍf!ï`ÃÀìÅņ5ÂdÓ€`M°€i`»“L9'A†³% „€cH¡@â¢Kâ™Ç¢s3LnANÙé’‹ +A^JPÑ€‰I½Ý4`Xés ˜D +ƒLÛ4` è$¬ö 3 ˜ ç1Œ]<`XY[@àDÖk LËàO °¬È“̱0Ó@`Hë¿€Àl~e@U.’gÙU–/ô V¸º£w'ö CçMñîE¦úÛdpS5¡ÙD`þÍüDÓ +EC ¥"ÏÊQ‘‰Æß£¼êBK6®/²ö‚šª˜$x Â/"0À–5öIÀŠž ôz‚Œê'}ÚX7D`X<ƒ LKä<78ívFó`ìH`P>z#qòÉ Ì)[)ccóàõÏD`ʵX}D`쨊¿ ãfq¡Ü7¸ßD`¼cüDœšÛŽÞ@`–QÉ@`vjS²Ø@`:ð`S]@à©ø–e〿:þÇ¢£ì#yüÆ‹;‘ £.¥à¦ë˜éÆÓ +Ï-pÀ88õÚÁ†³ÖÅfô…æß˜Å‚,Ã;o0~ÙíÀóûí“Næ cá¶ø‰>Të˜iÒô.Ì/Æ¦ÑÆ Æ8ç<'oôi +øÅ°óŒ› ãcdïÐ6ÄÁˆ ò¸)Àì^øqóüº~ÒÛàO øu¯à Üõ(Øšcò8ù¿$éÎ66nï¢ÿÆß'üwÙÌþž˜ê Ì-k–Nòoo +Q¯Š,þ¿Oîï²ûûqþpšú;ÃNèo ƒù;yüû‰Ä_ìdp/#>ÃR—àýŽGïñ…ûí_æèý"íp OØ/Ù¯e,Öo°`õ‹p÷Çèp~a÷ _üälp~»¸»å·[¶ßî6ÁøeL<¿7â÷µ+ˆ_|ƒuöòøzt‡8 ¿Aî +À/: !»|ß7KZpâ}i+yÑ}±™‘†û¶Ä”ì÷˜¬ô…öEr©p‘}Á$cëºzçØXþ\_$‹©­1Ö·{]yQ}Ù#—¹‚ú¾Z"Ò÷5’ñ"úò\êâù²«ù¦ù¾Œ©ÕæËº7¼–fù¾Æ¬Êwãù¾N4Ç·;aó¬ïÚ_?ÚÄCU:½#º¤œ_ˆÐ¸¸‰¦Ö[ð%pŒdÞƒßK*ì”ÌŸ/ï”è½Ã’Š‹Þ;Œ +x/Dþ¬é2»8b”2žäÞÉ0rYà^,ZÙÚÕÔñ÷‰í]6S{ÐyÅ]ìÖ½q‘r1{§<ìÅRŽ_p {IŒhê&¶‘½°J<­`( Jõ¨ãy5åŸÄ^¢¨º‚šr= £ZÖÈ^nAAí‰ìÅ$Ç!=½pBËâõŽ¢Gáz±Ð8!h½<¡G[©RÅ0`wMÀ«Àå®W…PÇjç–Ü…øÂõÚ«( × G¹ÀõÒÀÒï×K¿Œ'o\/™‚×ûÅ9ùaù-J^/ƒt`']¼^ZÍ ^¯"w%/@/ãqäøŸÄ^F[ ” b/<¼ˆ½³ê͸€½¸t®÷Ø»–”ìE\-c/`¯hÊÁ!±—œv]QÃWNC½‚†Â€°WA»·-`/«‰ä?½Œ[=NªIõJ9Ä^†E˜H?‘½ËŸ4²—/¤µ b Ð †‚àDöžVÆú“Ãîì%/£)Q´‘½”ØCvÈÞDfrÎ Ùk*H¹‘½”;R±`d¯m­,d/%WJ²u*XޱµVÄ`« +xº³ÊÅ녜ʸpzÜpf1:®—‘©ª6‘×Ë(Ê«ÞÙB:oïªÝ5ÁéO8/šu`È 8ï;Ý,ÕlÞ×ñ¼ Í àbRAæ}' ./Q½ÝX^ö‘A‚LT^o[@yÙ{»÷›Éûº`5êÑÅ$ À¢>œ<ð‘—®kY@^V«ç¼x¼àuÁ3¼p¼ð–³N‹i;´™,ºÂx«‹%//–¡]…–tLëX_æð7ü÷ Ä ù ʵƒÃËJ¹, /бÚ\^ÔŠÒ_7„·5m ^q°Ö¾¼0b%^HxšÈ¹\˜Bâc„Þ.ÃoUÙð¶*¥ï±ëª.ü. +ëÉ0$<øÀóìEßÅ¿ðÝ6VÓcN¨ +" ùdïˆO)лͳOwq&ÅྕA†Þñ<ƒw‘ßì[¨ÆB‘.x#qp¹Óõ€ÎbD8™»(±”ëBîN¯¹;ÝÂ)ˆ»P,¼ww¡ƒeÁ§y»,*šsáv¡ÀF”ï¤íJª½X»Ó±ó@íâïøEÚeF~zv#r ];.qqvQÊÈu¬1»Ó˜Å ìNÇ/È.ÒzI"†íÂ÷Pከ•û Ù¥•ŒhK¿±§¹.È.cèðq/È.Ûª#Ä]Lÿ¦7’±›¢-ÅÉØÝÇ2c"‚±Ër„:.Æ.žx5”-ƒ÷Ξífì:]F¡ÌÔ¦êrÍŠ{X]¼ä(Uª®ò¥ÞT];@Šª®ðé]T]d8Ø\T]’Sš ¹(Aª«„‚†²Mեܡ¨ êÒPDÑE”Œ»UÅ…<$]¼å¦ê’˜6ìBï%Ý¥‹ª i¢ŠÕeîol¦.”; ‡\L]°Í˜=_›ÁË ÉÂP]¤^ø¦\P]XÙþWP]˜è9TY"† .¨.ipX½T:yÕ¥‚ð ªK6 †ê +–ôqOªËýXðsBuS³gP]”sYP]õŽú€ê2‡Æ’CuyÞUn¡º ê‘½p2uaÔ¯™©›Èªu1ui@LæbêÂJ\0u¹o‚™ºK2Õódê.ãbêr®¢Ô4˜º¼a£|†ê¬·ËP]=XP]nBÏÕ¥™O* º¢±ucvEXÍo¨.µ€qW¯æÖW£Ç‚ê’ü ÉÁ Õe„˜%ÝÕe‘(õv¦åòൟP]®zÒ6Îè¡Æe¸ˆºÛjºš˜ˆÍbžîÇüO°ø¸%U §«ªü´hºpô¹R ˜.BÇoýÄÒEŠõÈFé¾’‘/’îàé~;y·&âBå¨d€t± G÷¦‹£‹á{îÓ¡·\]ËXo†.Š%Qa„.­ˆù"‚.b£-Õ  q90æç"¼†ã@Ó ÅÊ…Ï…q©+z.bÏXì\ dèBçBˆŽê’@çâɹøÑ9—âo#ȹÚCo±Îb.f¾S2ð§…Í…Œ¼`pµ¨w鄿B3Dr¸†Û25þ2·¼lÉ~òrámd,6ŒËe×¾§,Z.°ƒõŸ`¹¥H¸°X¹¾72u] j©nR.¬Ã(·°£Aޜ܂°])Ÿ0¹eJ#KJ.r´$¡úA*œÝ1NFn5ú/¹Œ³Í¾¹ˆp…|rõ B'¢aÆã¾Ö‰]t\)“2;M%L—}Lr8ѸÍ­ ã6w/ 0n‹ÙèãB*þÁ¸pà¥5eO7aWæÛÌÄíû·³ +òâ"IŸE»%·›«8\ì˜ÃEÃ…@‡ù8Ãp1m.¤d,Ð8Q¸¸FÌæAÂÅ=`nסP*Ù½8¸ïA‹\æÓ…¹dñîàbà¾îâܨ«îkŽÂÀe¯‹2ÿvÇ[XÑnúm5,à·À³"Sgöm+ ø¹Ñ·dsäºÈ·Í§|Û,¼¼¸·0ñk©&¨ãÍ‹zÛŠú +\ÔÛêš‚€ÞÂíb»='òP ÆÆ'ò–úˆ^ñ |HÞâ6@zñna|æ»p· eɆH»-̽¤v°š`Ý–®ç@ÝâÏŒ+;I·¸'dOݼ†ÅP‡PÈ7(7æõO¬…SQIÉš]r‹ú*¢yOÆ-+r[ˆ[QÈæ"Ü"uúö›o›_U¢ÞƒÈt[üýÔyÃm321OÛl[ ÔÞ¼³ùpå·‘m‰Á·`[(Ns °-ÞÜ,>íæÚ6Ð¥žµÅô W2¨¶==‚án¨ídÍ}ÚLÛʲԴÅp¦7ê Ú6…Ñ6yZ5Ð/EM7Îo“ ÙBŠôIÐl1qò’O˜-˜kËQJeM1A +ûg’-d?mƒlÐϯή%ÂØ~¼d x,ЭŰ b ér-Ÿ¶i”º¶˜YÊØ"ëšÞOüZÄ¼çØøZ¼·ìazí‡PU4zÀk‹`×fÏß®e4^¨“\ -ÈÛ· ’ +[‹š¨'}¦Ö‚õ_´I»GU.~¨>™µ’Tô²˜µˆTºÇ·Ä.Ë‚åƒnh-âøÂ€›Z ƒº˜„ôÅ;þþ8Õîåî‚ÖB¾åX0kƒYÈZdÒ†³›X‹Õ=ž¬Eµ8ô-Á«%½¡ÎW‹ +Ž…iµÍhÍ€Õâï>nTms>HµHY"à ZâY W>9µ­ èÁi°©à›@'Ë6¥v¤•›¥ëoÞÕv‚„þ…¨…÷3µÓÍ ¨ÌSÿºñ´ cr :-ê<óFHä!Ëu±iÇPר@Ó“5³}([riŃ7ÆwHæXÚøû¢Ò†1 ´ÝÓpÐfû«5鍅x´H‡FãH +å‘vý}iñf^¤YœÒ|7gÅ7¬T¼0³ˆ@’Ežy·T–Ùuˆ1;"©iÂìpš'x²ñµ_|Yè9ů^v$ݾEíÕ,¸‹.ûè5¬Èöœj¶,eÒ£~BËv÷D_dYGÞ²Á²ýÙźKÁÜŸ]¯+ÐÝã./A•ý0¨€õ‚ʾŽ0/¦ìûD© •—á$Ên£€²¯)8‹dÚ³ªnž,…6õۢɢ¼&°zô@ª+Ân–lQNm”,Eùoôæ’˜>Úí$&rL©(ب£ "šWR›¿!²Í†ÅE~­µEí4¾²ÈhB9üX®¨¼êh ¨4¡ni>PUŒdArÍa-vlÍjmr£c+ë¢Åý†AÕä&ÇV‹/p,š&êÌú‹ŒS`c?»1?|wGé¿Rcÿ㨱ìÚEa†ÜÁØáÒÜ™èÁ7¹›×Ô†|}±2aàž†¥„†ÜlÈÊU3™Éú…¡%˜É0ÏWKM/n’ éàn4u¦‘àŸsÆy¬#3þ‰¹ÏAa€À@,±`¡nMàòGu9›ôVÛ±ëƒÄ2ÉðXêp­j^}êCa»§#‹ëJ[:™Ž9ÒXÍ$¾ðy ë"A ÕÌð)½.uw‰ÌÂ`Ü +ÒŸ»Z«ìµ%¹Hè ¼%ž‡9+f”šKOa!R€ù`2Ì`)騕”?šÛ+–´»™`µ‹‹†…bU„ÀÇêÍÐÜᜅ±¤Æ%0ŽÈÈÃýFWv1^z·*ëËVƒ¤°Ò+©wóÇôÝØÄžMô'\Õ]°røFÇëÂöm(5›\†N¡bÙ«‰êp”ÖÚK=ªÍݽ˜˜‚!Sþ]õw]PLZ‡Z¼7vUzÝš –·E{(D¶iy£FN ÆŠ~’ET|öjÞõâš^Ë´ëJ×q¥’´áÃ)Pÿf¶l¡¿­´P€·¡ŽÀ{¡õq¶|\ž£ù„w˜¬†®¬Ã}äcwªÃšWÞ^u7ëŽÑ"ÌowøÃ¢%­†Ó葆Á߬Ôá/ª ¦XÒÂ1àCfa:½áU^‚šþ|»Ÿ2.¥ gl|m*uδÔɦÞî'†¨˜ßa¦Ô„f€iéü—ô0à˜gÖ—ìv–jÊa& +  c1Ò˜7R•e•ÍOׯÂ,͉´n¯ ‚{\4hY¢‰<¡ýÆÕ¡6žÀpÕ=óÐÏL3ˆ±0óÅáÄ"Vâ“ ä]òÉmžˆs°#;»…v…¼¸¡º;à7_¾&igêãXØFUäl %„Dð*‡Än– /|­…À=6â@! öÔvÃ|>>^~S59~4S‚´ÄÅSrkt"z ÔÐßRîáï´nÑcaq"0Ù;Š);T°ýc<J5ø‰áA¯¾ 8WúKÓJè4¦HW¾ÈäŸÄš™$-À7&!š¬åñûÖš'pX?ʯ½g~ü*rV„êíIzÛu°Ž1(jŠÙÅ• '˜‘‘įª»igÒ½Ð"•º¹v͆”@TÆ.u³¸UØÃìì6Jp@“2©Ìܙˆ¬Kìþ +€˜Ô†¶½ç83Åœ\vü­³À\CÍk¡3-eMâ¨öä‰fH^wä¡”ä¿YãÍJá%ºÝüNÜ¥ {°ÄA4 +!1¼¹DNk@ꯔúìkæD"7=ýCMþ¨^AD# ñôßý‚—ÏnQÎß=FC{ö1¸ú1Ã!°Ó% j¨ºȰ|L +º’jØ@p¾z¨$t,eŽä‡ÿ€áñëðq[«,‰o~aLuÿ¨qî5éHòæ `9]b-. z’'Õ"xÞdfèX²‹QôúÇå€r}3Ëz`IY.éLj⎳—ﺯ-ÓûÈj‡FÌâÏa•Ìæ7Žlˬ¥z¢X÷uGöĖΧ;£Ð0“ÿ K‹¡ç ]å"Ü^ìÚÔu@+ò¤î]"5}¬Ùç[än¸+Ž-v¿®ùØq[¾Î¥š3]2 nh}¹šÍ=QŸö¸ÛI#~žMã²{›A<…\W1$$ž|M!œã³zƒtZÈhÓ®k¢'Zó•æîcÀÓ•Gp S.ƒ£¸&å~ ߸¶…^ ­›Á™©¿zX† }Ë­&_µ¨-ú†c)^Ù¤³¨À…H“±Do¯;Ö -üdÿ5üž3,d¬½î²Å=×GÅ$öÕ,Ê-ÑRd˜|÷^×Hª?ðj®Ö‚Ææ*©F+–8du×c»s¾{ÐÒÔ_3Æ +ü­ ùTv„ÍfÉurÕêÞQ×@8ü£_xÇtS ¡¦°”áÒÒöÚ¡û dQÙ#ŵÏèjTsÕ¥ï¯3^?IJƒòX½fUmgXxÏ6;(ÙÑuJÊú¼=Ü[dWwß›ÄhqÑ•ÕKi¢ÅFbÆ/i®zÛ’>2=ŒOÝy ú@*–}¡¶4ÈX\Ï­¼–X F⓺Kwöe$‡»²L1ôýÉÔOâõªˆ`Z~)ˆùb[³oÜ‹èÖbîG8[—7¾l žLŠA*FÉö²8V¥2ØbMÆy£ú(P¦7é=\kÛ>nûô—…Pý JG m¢®U8œõ}#÷ň€5=0{Õô&%É{Jù ÌMÙ»JRHL×Ãq¼R•<0û¦,\'xW;‹ÐäÇE³,?H"³ŽÆE£x?¸ÜÔÝ¥­¨]SIúbÜ$J¡MVzÓ‰ØC/ áZ4cYA×"çÈÂöÙµ º¤ÊéÕXDÅ5INnÓ…/¦YÛå=_•”- >xÔÅù<‹eA“Ø5móðÂ^mhÇÀ¹ZP9¶ø­ooèµý+$× Å0±gX[‚šÌBþ¾}®š×« & | ?Qdp¾lÞÜ8z©ûÍfH=nŒÀ›Ö6L€¥ºsâþ›â´‡ÄÏ!KÝ€<¾ª‡EX¯@HM˜ +Zêk_qà®ÑE§p¨DÂ=妮ˆŠ«R]}‘±'lº8}hCýl +׬á¸&ñÙàû¤§ÂP*C¹¹CñL‹wýp ô“¹®.ÀXÕp ¯œŠd. õ|Ø“ñ*2]ögÈ ’èáì–ûÚ K³ +^2 8k¹Bõt÷›b—2Ù³E-C㈘=ï#ÖTV ‚ÕT£’&ÆywUò˜&þaKøH’óÖ’=)¼ˆ#ɳYÍþr_‚g˜{µƒÈFÐÅï=ÆG®Žâ°àÑy¤<ôP»U%yg9‡¿‡Âɪ¿v6Þ=-3YTÈ" ñ68Í·­DÆ©¯  ¸E|á`~²ˆnbˆQþ™ôÔ´Þb§„5îÖ¯²îC™u¯,šüY7BÈëÙû‰ï;ïžzj¹½…k¬>¼èx»ÚsÁüКNùðòºFM÷ªÒÉb\éZÖ¢nµéó†+}ÓÞ>,P&ÎwyŸËŒ 4=¤n€ê%ù^~^ìµCFygBC¼ î¥†$ÈÓ¸]ˆ¬å ºe̘۳>ÊÉm8‹+PÙËÅÒ•Œ/n+ÒôÎ~|rr;| +ë+þF)´Ã€v®£ÊT*Q4Ô¸ 0SíI.!éïL± Ü›¥Æ@I%bx×'ãPYRg\0/Êð¦LÉ~ª.TYò$jH?aׂ (Çl¡] „muhØýà Ã Ç¢Svy•ÍôÑ©…õ¼Ðªþ&ƒó¥iÎÀ†ìa¦ÓÅÿWÉ(qÁŒFyO×ýáÁ·DI*üc +Z;4ÓxZ¦àÚ•xq^VÒ»™sžâGô”ÊJ2ëBw„™/™èSÉ> É'ùÈÏ(aˆcg ÙÌŠYÃŒP:, +W£çV00Áe¦½'Ð\݆ÇÂÊgòGÓ´!$d™Š[œeMʪ3jÏÜß7Æ‹»êËq¿Ù0oÅ×wÕ Q (pÒàô*fÃÒÃë‡UñpT%>LOa ¹Ÿ),IèÍuïȘ~S¨1´‡BvÅBcÂ>ÿY`Ž¢Æ +GO A*F»ùŠâQ÷P'"ÀýF:ƒXX6¸F€QÛ–|B4ž-ñÕ«ÏD1“V(=Ùm™À'X8¹CÄDpÜ벸ØÐ1A?’鰳Ͷ5XÜÛ"ùe†÷¿[†‘ö¦öY‹´,8qWŽª@iŠ2ˆ—rŒÑºTÜ¢[€]ªY»J˜ýØubßÞ'+£ÄèäŽEŽ®°,£›ê(ìÔÓ '^}ñ– Ü8Ì‚¡ÂbL¡uŒ!ѹkϼ^#vû˜ Òá­©‘íÂØÃ7…¤(<ª'$*94ÇtBe¸ÄÚ<·ñ™=ž @®™kDûCÙc„sr+ö8.Ú“X8Þª/šÉÉÇÕM¦kãïCò2Û(önK>¾4vfç­Êi:©£³J˜ó„ˆ9¢ýÞ3ÁQJÇ™4ŠÆôè{ÄVµde¯ÖÏøð’;‰gL’þ6e¡6”ßoeR +ZÀÕ €3-u]¾‘©m.Ú h¸ Ã(èºãþËÓžÑbÚÆü¦ƒC’ßG#ûPø‘¢’€ Û›Ð]™¨õî1çÁâÔsçŠù· +–cÐ,ÑÎ!aQuÛ(G,ÌòX†ô<™ªt÷q_?JÎ +{¶¿kþ†4 Yj+ñ®Â7zö\|dÄž2¯Ú`ï‡îIlØUAW©Ùƒaà K{´Í»JdºqìlÁcõWŽ|øÅVô›óøÍ* +rb3áF‰Ã*-åC¼jΉÓç6ö©† ÌaÀíÉ$D:ùD'‹ä•©1&­ÐÌ£¼ƒX?Ë|†“‹Ìêa›Ù<ñ¬wˆàx)X®qb 5§%_¬÷`y_§Ê©Æö®Ö‹ÂÌæ=¸.ÂÔ8ŒU"å²xÊFêÞ£([s +CÔ…N$P2bI­kžxóî4}¥­jøKÁæbvD¡1_<¯ªô¯ëÊ3ÎÍC5NbÖ€üÍL‡…‡øÍf޲–,à¤ÿ(áædö+{=ì"TkÒôÌ\TѳáΞGt°É1ÃonŒw…2F«‚È +^¸ùÀ­‚8Ù÷ÌÐ/ÞkÔ EU¬màqÁ·E¹GfèåMÜΖÎÑ¥â¶LqGÖ†/ÉWC–õ§~ô^Kë Lu­Ð?^l­3PóUÝÑœa!ì )¹ˆP0]ôª\Ò£yrƒØþzÂH¬ÌÂß,S‡Ó·è}îx;47ORÓJÆhPîð=LØ“úÖgSWvzcòüΤº8ÇÞÏ„’!ü¤´8kã‘9¤,~ÈÊ%dyè•ûŽ {„®J¯tÓä¨J©+´ 3o9jã²7PšÄžG–aƽZ€™³±šÀç)¸cC&Ò˜|=QïÚ kÊž¡ò`ý"N§`ø¡œÂbŸ«ÈMÚÎfŠ ¤)|–ËLPZ`¼m~ÜOhÚ `u>Ïè ®½Ãâ;\”ØÛe·±¨Qû¹,ŒÑ/ +Ã6WöáN„4ûä:T±˜4¢mãHW+ÝJ)”ÛDÀÂÖLŒ(Gh*%âÕGÔiDwf„±_oÈÖ°°óå3‡eìG5¨MunbF~ +%ÑÁ +‰ò ëfrH¡ d_‹jîeø|YšF‰³C-ªVŸúxñÑ8YTÝ¡-Â<•VhT.O/±Qt׳Wö´æ@ W+:]µÁÁêBWuù6̱ks¹ˆ[•WŽ)®œß<‘”q•Mp„¹²~ñJ…¹þ,нâµÉëƒyÌ\Õz nHQºæ/¥)Ù…¡œ{*ã3ÂMdM7ññ%G°°_ÚQ9Ö× ·kqh¼““'TH­6Úh +“N½›, ³7ô–‘1Ïg¡±ÀD¦™©<ÄÐ9†ÀÂ"øwš•H¼Ø‘ª)œ}•Àˆ–˜¾¹ç±Òq{# gÑ©Gþ¾H:•°èR™îr¯ž¤ !‰ÑN”Ñpt ‹c÷†³»€˜3œ´Ò ÞÙËYûSBšê$?›ýmƒ¯A³Rǯ¥pŒ€¦daQq°sì¿×RWÊ/HhŸWÿÔÏMq1½/ìähÐMO° ©y?|{ÅÍ´ä~³Vâ™ †W®Ûp.*xbÒr„©ï¶±ÕŽP»±UA. +£ØT?AáJ–‘ôË%8°¼ÏN•"‘ÝIÎ2KCh\Ϫ!:5 s_høÔìËÌ Dr$˜ŽÙ­Ç+âÓØ/’ÍC³-Ls@dÃÚüüX HÙMé{WǸ¨4f›ò£‡”ÆyX—?–§=C“ô)QID"Ê:ò”¿Ï$¶K/’Y¤ÏšQa,•ƒœGý;sOs½Æ:CD¨|Xöb«ë׉4}EŠ)%€Šgš¢ÒÖÆwðq"·xá6ÛˆMGôÍ}é {“ã×Ì]æåxK_kOÆ^»Î…‘VìˤåeL¬›µÁ]×x¢ƒ©³cå5üg®ÏqG¤Xš-:ë¹Á‘¦SÔ\²Ë\‰®Cãu¥ZqÃe•CPr–àf"CíU ¾—º3X‹¦ +öM.$¤aÍþ«B®8¦CY\u‡ªœ“`azv|kW)Xû@UKg91]S5û‹7±SÈ«†;"Õd)<$Ål€D1åòÝáT|CÔó®µÓÃ@ Ûbpýéˆ-,šL{¶ +³I^ÌœLkõ…â7ø¦ÖŽOd”aÙiËÞíá"™­¶e‹$\+`( íÖ.=ë‰BªÇ\)~” +¬¡øõ5³ør³ý(ÌÍ2Kåc‘ñdÈÊ^ Ô¬–²úÈAbÂQ„êËlõ*}Rª-fІêߥ6ÇbØY,éV¤~1?Ö0°î¢×®¼ãkn”‰W@oñ†/ËÅ,'# «§sñôšµ +t%ù0L$œÂépLEC^¯ ¡¾yÃÜšÔuêåwîÊ^i:úì +jžXÈh6L#SÖÒ=ý«SÉZ¯%ÿ&噌¸ÿ ýwÌOŒ¯PÒÖ5üoƒ>RêàqJỏÔÁ#aŽ…ÇkQÞ¡/x_µ©ì}p*§Ød }aé–ì§å­p©¡ Fº¢_—[ uã‚m@syðå.{yÙÝÅ`/%ÈhRS~Î3äùËù„•šÒYµÈgþƒ'A Ù#á:³J²lo9w¡wó#ÜyÎ0þQ’–ÖÍÌ/×ÙL¶D’&1äXU6G“ˆ7Ãïë[HZYíðD×Ô7)<È Œoà;¶.Žª^®wå*Õé!v°O=Nû?ðcdxTyÛ­r„ò4«*í»‚ÞÞôÌòR™Â¬’¹>\í€p%ËfñìXMj†¿ƒ9Ç›k3ù4}“DxÁCÈŠGM Μ¿ˆR˜éá3{?$Í ÷±Iq²ÔkvÀߤºêyþF‰ÉóuÔã«óº#œßAM?¦0ì=ú9ÌCN3\¾®Å6-ouN€À)ìºÔ` V2Å–·g·Ôé0ws- n–޵]ôJwªÇÏ|^wVæÝt¸µ9×D‹Ôøå÷ÜÐkVÀi¸2Žh7—Û +p\³G_ˆu©âqI‰ÉDa`§s¯k¥—ôÎÃLÑ>O¯ÓgîöMîMñi×ÇùÕd%-ìN‚¾ +’ë ;[ïe© »Ôñüg5Öx«]R†ö{ +b‰ôW?ÉJ,&m§ŸjWUWTk=U®ÔYBV³R,|ú04?fÕbÏñ¦½'Òœœœ‘Hä™]¿©LW¾Ðb¾#œD]hq°hDzCÇkŒ1KâCEß#ë« ðŒ©Ô4XC~=E·DX[/þtKX¸š@ä絓´§Q®Ô5ëT€©«ëa: Œ0ÔÌ 7¨ÿa-Þ_•é&æî²»O!3PC£ä¸ µkO±Ð‹é³ìf‰ýØœ¤xlBhpg(Jˆèa拪‹úã‡Ì¤’‚oµ.e¬ b"ÅçCwŽáJŠÁ÷“äthÕOßWZ\ÆmVŸzúňi.¤ƒ¦^r¸tÖR¾I}]‹5-s²þ‡"§R}v|¢ÔþÊçßu ™úãÑ­™ålä=ø‹Y‚HUc=4óyAVˆUÃDÜ ÉÔk£Ü/Ÿå•”«’@ÂqÒ¿s Á$=´ˆÉJ¿Rä‹•õšÄ…›@@öá¿q݈`ô zâ7^|Xv0ñ™‡™’‰v‹ˆÛ’‡bÁÞu™_×¢C”º”z-¿,¾ÿJ„u&¢B ½èª(e·¢&š·˜€6Êí³s£SAmÒZÄf7Gf« ÈÕPU¢"ŠÔ¢Âèµß‘<h¥O¸³Ûj«ô—º}µ„¦‚É ®&ÓLAJˆ8û½cW§‰õ ²1;9^Z¤¦±=8¯²/•,~“¥iø%n$¥Ý>ÕaÅ >ïg÷wxìB”†B’¤€ tWå¬õµH½v¹X%ä¦òˆª±A¯¸Bh”;ú«åJØ¥dØji^ç†éË3fËÄC`X¼kÈw`®]¡\EÐÓ£Ø$·á+åZ:*åÏ"·É.~‚ñXÈ¡©É\7,Bvˆ â<µÒÏ(öJñªûÃÊÕçMy#U@Ï:4IÄXs‰(Zx‰MÖŽ +ÕÒÉÏ9|‡ÀBÅ ,<áÜ•^»ªGÖ5¡*Pn ·À 1lØÿ&-i +b‡zØ=`7Ù¹`Tæ‘8Ô4òãE†ÂqÙª¯ŸW*}†‘Sšáñ÷Z‚¯DÅ«r©Iò HZ0bÇFk\XZ®º@¨Ì!ü6«Þ• ¢s9â9±nª¸½Ðb›fdÕ`ùµç5LÔ îªL¶uOÝOw™l­1™›ŒÒÎÂdu¹àªfh2×W€EÙ^OHÙ´,ÙW*'­GR.žá¦X&ʦÌP4ðŽ(į÷”¸yŸeç –¯M¥cL÷ïi˜VYì%t¡Bkn÷E]+ÊYY ?v»t&Ï×Tßs ðŠ@¯†ªaÙºµž°HðQ)»Rô9ˆv_–‚%‹´§tW³2-Ìê:žK@ ‘&4©ï ýuÜÄÊcïqÑÇ’hñqÙ4­ ©–Måó…~ÌQ›%l¹çi=–qø i@ «S«MÉ»“ÌÂÕ¡¯æÒ41“üImñ8£ã+þG¤LÓò†¤V‚ß[Í7È•à †QJ:-MVVË…ùxÆ|éé,U»ŠîËvKÐД³ú È=Ò¹ +lzCZ8<áðKûÂÛÀÖð׫œæ0Î)±‘ ¡Và‰ ïÒŽ Ùoœ%NÓJ‰eAìíØõ:¾ÇôÉ!_B©â¬´³¢a±·9”«Ø2£Ð”àiõüû9ÔƒËÌ+æÜ;ueÒAë™ùÌÇ€æâª«×Û%Hh ªaÞNu1p Áõ×Jz6“áøÑî]wT¼î’LÄ’ÙuˆU“ A+k¦3VzsÉÒV¸SÈ«@YƒÊÅäÌÆÆ{¿fù¶Á½~õGžšf`ÃÇ”gÿcü¢µSSÞRæwa1ïL*(ìy0ãÂ9šCd%\‹ˆì­œu§”Lc3Š%,Bæ )ì¶*|öÈ~øîNßå ÿÇqУ¸âÆ # —ºòìŒh"œÎ€!舣3¢r1ÐËtZ8è@þÏWm¬%¿ÌÞE¬,3=ú’-þ9€lÇtáÏóT2wÑÏÉä¡·5üÓãÐÅ>ç~Iõ: âðÝÞ©.yª†ïâž×'¸§Æž#þÄtEPϛŀ7ô<Ú-æ9[8÷JiPµ²î&žo«çÕXï H’9.Ü90RµˆmÎÙ»­ì¼Zâp³Î™ͪèæ`RC¤ó3ô :‡ÊW$n؃æ¸0笋¨B2/¢Aë®bÈ9JÌ9ô㜲‹R>!Λ«©á}ø²kЮ¨°ó⛳WŸ!èÔkã(yl¸y³ñf›Â×ÊF›#Î¥FŒ&›c1Ù}ŽèË\uy7לµxJ2±ùŽP½Psô=*–¸q.Iøéª|b ³:éÑœ“ÿ+Î9欖4@žÁ¨ª¼qæQ¸xæC[0sþ9õˆ6jÅvJPe.$¶P$™÷*ÎÌÅ1ïŽÄ,ŒùÇ∩¸E1Ÿî yC̱ê`?Í`˜Oµ› ‚ùLZrÞs +´]3›¯`Ð˧›Vßðòñ:iìrÐ6^Ö.ïS¬³›\>‡zg/p9«ñJVéËì "4åE†gc‘*¥´ˆ÷ÈæŠ>np9,J±\àòD7<…b–ÝM¢QP€Ëi‘Xv\x½×kë—cUþ„0©4¬Ÿ˜½°å¨‚dš/°åhâí[Î&( ô]Ür™‡jƒ•9z’+ºQ€kB/n9Ì]Eæ–³AÌëÂOï¨øìÅ-Ÿ†ó/lyt” +j9ŠUš—†ZŽÉd:dÀX·i‹X>GèïN`9¬LͯA“žó·…+Çù4Iwõ7º‰+.dVùì&¿†{vç?.R9ÐL2¨|4¦UÎ&¦nHùëÖ]‹Qަܽ…(otrhÍrSÊ9៼IezÓÉ›£€Á&oÃø×@“ð~k僑¢¶=ÀäÑ;6¸änêËÚTr&H(¼4”ütn0É[÷Ûu!É‘—R$ÌÉÙÖÃÙ39ózñÈk”Â޼>¡+µ²%£Í%,F^6Z0òõ\Á"‡¡·þíF‘DÎät×WFQ3Ë„8@äX%kæ¸ú@‚SUSÆÃ³#ÈüÂçw—R‘Bž9ÑÉ#” è³ã¸¸V­Ã1!ûd£Lˆ Ò@AÓÌ'Žã€œ¼™G‘|rYZ~¼5g'/ú8Mäÿ|¿Ç\o ÅÙù1}"·rÊk ˃;݉oì8Ò?Ê8›:^gÄå G‚ÑÕ‹9¬9ßÌ㬚1›a6óŽ?_t0Qâï(f:q NØx 9A°Æq½œK5¾ 'iœ5£5mÒx{\Ê ñµ4g¼E#³àŒ·(§ Ìxs÷Ä‹2ΪنNJR9$3Ʊ’Ã'b'Å{„q :Xå€ñVü¼ðâ0êÛ4_Í+Æ‹cl¢4袋“÷Bô²áâ‚2èpqОTäu²Å‘AÖÈn´xmVèY9Ó‡Xœ"—G[yTEV¼Ä\|QÅ¡8™â5D/™¿ˆâ%ô0G?[Õvš'ηÖHlœxF1NÒ~"䨻ãb‰ç©ÐÔE/̵JO¿£0ᨊ%ÆŒK1lùĈƒ8 ø½)ây Ä 4¿Ý ñש¸0>\§fA0¼ºF²ÕM-‚8WxmÄߨq?üqñƇ»ŠwÓÃgÈ<£ÍŸÙá‹þüÅ ‡–>aÃ1O¢)õ†W6úUå€êB«RË3|0þݾmfø# ÙF†Ogwnbøtr2ˆá\ýl\8þì#}šî³ï ÎÍJ>Xáh>jœøÁ +wXp¡Â_ßoRø2\ ðe Nøt¨#èß I¦¾ :Íæ¨ïÚÌþôb„oÃ_Æ „çU€ðx-/>8J )Òƒc©ÅþRAýLõÇÈ­Àƒ øPóƃãg«îþžYÊÆƒÿ†YÀú¦Íï¡cÛ÷8?å¥à ðà&q,:xäøÇ‚ù’`ƒO:¸í[°Á1<òíþq&ƒ?üÑjíœXÞœ¢÷\dp¸PuŒÀ\|Ì–ÐØÐu¡Áå:HÇ´Éà((™rƒÁq¿’õ—> Šëo,x6ÖaQÁKVÕÆ‚‚c0“êd‚Cäòº—†tè +QZ³ºè‚ûZa*±»ªû*X.8ŽVš\.Ô +@LðZg Ñqs„ìbÙ|Ý…ØÖ]/‹$ÉçíùÛ _Öà€CÀÁ +ìÀ€ó>¥ú‰NˆLé^\ŸµàØ‚‘æ +NÀ¡šxúØp\€5» +Á+èßeŠ,½àß”éÑ=Øß5dEþFÁWOôº‰ê üJôU¥õ}Ìó ¤ì2\Ôïm5ô»MËE‚ùýÅß¾:&C Oæ·ú2õw3¿©ùcAc0¿©xdiÀ‰üÆ·ËÐÂB~c;ŸC%þ4CH'ñ›Öt`»õ®ç¹€ß‰Åº­~ãe#áØóU¿ù÷0Xú9ðù]ZÛü†¶S)Î~KLU>¿‰Ð`ém¿)eü2ˆß(1Ï¿iûÙÄo>§þ¶Mü¦ä†©À ùM™M+c!¿©°a +ßÜ$™’~@üPTÀÐt ¿©Â}Z]Èo(ˆ„’¼ß”ñ‹áläw"‘™¥F~ãªøB~S¾ÍXl ¿a!Mb1¿E£2íüè*™Ôgk!¿¡žRB3ßTB3Î}!¿)“c(7ßlÂ0®‘ß4ð¿ßؽ›øMÖ|‹ø k*oä7.KLî@~C‘®{ ¿)§R^øD~³gs|V,RgXLyJ#¿èhÆ +¯ê„å,à÷lRñ.Þ71ªEèÁûž-ê¾ üæV}ã¾q2W/Ú÷ñ€ ûf81æ€}ãJ¨]»aߨ‹Š°>Yß3™€¨o2’U’´@߈»ª_¦9ßÐç¨üÛ˜o +v²BÚ›òžðêjÈ7 ¨šñýª1àñˆ ªºMøfÔ‘JŒ |³¡<әᛗ%S”{Ü,l¾QüÖþí|O—/¾7›¸;ßBú$;Ì‹½½áÞ0×€“íã(ø,´7Ï?’.²w¢Ž"m¡îC« ´·æ÷ÎÜhoùŠ;Ù² ÑS°ü ŽúÛf׌›íM ZüÛ›† ‚o¶7Í,Ô +¶7¢Ž yÇgBmŽo7ÛÁmj Û›%*ƒê”óó¹àÞ,$¡V;àÞ(Ì<-àÞ¼KªC=áÞIà€ùmÁ½ÙÙÿ€{³¦ã1}gýY\³¸à€{ÓÂàRÀ½iQÎîM•­$V¦{³©TsÕ©T$ o¼®±Üxo)oÉÁ7Þ›xoÌUê$á½éÿ¨)¦ñÞ[¢xoXj@º7Þf9'Æ{ÓÀhà½iQ²ïÍ8kgM÷V ˜DHBðŠCÞøæÒŠ’– |'¢šÝÜ@XDg8 ß2ó[6á›S¯ß0¨_ÇEøfW +,‚ð­Åƒ™ßZP—¾‰ø›ð­B²&àP]S±?ˆo®u†™ ñMAºZñMͺ>#¾iÑ×p2¾i¦F$ß* Èf)T¯ß …8ß*е(‡Û2Ý]€ˆï%ð¿ßô!Ù<߸oRGâ[±‘Ï„oHT†lÄ7ƒ#œƒñ­pÉkÊb|§Ý¾ÆŒoG[Æf|3B3‡²õãJåÓã›.£Òí±êÅüñE„´/Áød±‘*e‰ø&/¹5÷F|3¾¬FF|ã#Ë#ß©EÏå“ðÍR2ªƒ‚ðÍö‘’7™ðM÷?§ú‰ð–’!ß²l¾÷×uñ¦À¸üDÃâ{#ÉÜaà½A"°Ròg$uïâ{ÓLé³ùÞø)ìð ‹Tøàf)¶Í÷¦AÙI¾eaÆí|ã7Ù§,øÞÈ2xo¤¤¸ñÞLˆ²b+øÞóµ‚3¨Ýù" ·éÞ½D~ØÖ7ÚUÛûE™½ã¾í ëcô6ç„42Øzñ¡ÈØ^°+Õä¦z¿QŽ›½Õ´‹éýº©úBz÷ä„Y€ºÑ±Ðô&{ÖmeÓõ&!RrêF +^ÚÌéî^éÞ˜n6ŸuSº_-Ü£û ê…èæYÕ èÆ}fñÜø»Ø!nÇN‚)œû r°¹Ãl2÷)Ús÷H_…{ –K•<›Ê¡0îm5/&÷x-¼_›M3øƒÈ b3h{¹‰uó¸ax}+‰ã¡r¹pÜ#àAãFyÓƒãuœ]\O÷dÔ¼l7VÜL»Ľþ¾8ÜÛj 7x9Ñ«š¥l£˜ŸxA¸g0©‚Á娂`p' +ùÝíp3¸aÖâ'z” ‘sº²ýX[™­½{ACŠEX ¸aé¬7·á§0¸1Çjî÷¬Ä8€ë!¾ûã‰kYømžïqà·‰CAËÞ4ð2yåÁß&ae®”):º_üm>Tˆ˜¿Í—£ñ-v²óæo³­h\…Âêð 9ÀÀýÕcúaySJ7#¤‹]nš)Á·’%oà6j r"¸ +£ )ÜxÈþ #¸Êäër¸qT‚î½.·¾ô¡iöˆ³o°}.¥÷r”©¶}í¸´;0*ÐÍ"pà EC¸Yf«Ö'W*i]¸ñŠ“n8ƒÒÂ] îíøƒ›ïk¨IDË â£+‰¶܇٠nö‚f¾!ܰHØv1¸ÉΠF*܉ttÔ­a;ƒ¯°õ"fpSX¨Ra3¸ñœUÂ}1¸Q³GœZ ¸Q»&¾ Ó§»<Ýnã¢sW ð¿9¤/ ×7›#ŽæÁßfàHt"´4ËÅc4»S4%©<k˃¿ÍÍmü6£¡,Ç +ü6ž<㌠¿=G Òú6ªŠDÇ6|{t-œ{›UF<ù½N@By›¼ (YÞîQyq·ûë¡3°Û=*¾ƒºÝãS:©ÛXM#¶ié†rC:q»·àq¸Ý»«ÉÛ ±Ÿƒ¶žA¹ƒ¶Mݱ †m¿pÞ¬m Ò– Ôö[Ü}É m2ÕºªÈ7g›M¯ñ¸yi8_Ç l¿%ší7Ц£&rEó,X8Š ©`± ÕŒAØFºŸV¶A¾£Ûzñµ‘D$Ö:ðÚ@10âtíUº\J¯^BN¡b8’Ö&Ñb†P5¤Ð'‘-`m¶€ËesµA~¦êÂj£ZY Sµ[ófÕÆÂŠ˜SV®_‚© ­U3› p¨±„¯<‘Ú˜CØo ˆÚ­ºùØO¥¿O›Ë9Ò0LÅY‹ŽàiCþÂÙüÂiã*ø{AÓnc·çLƒ:3ÐO˜vëþò‚¥Ýbr ”6Ψ¹Só˜sXS$mLTýЧ¶áæ&F~¿¢ ¦hãì„Ü0Dª¬‘æÍО±Ð †ölѤÑíù:™}´!‘VѱÚóõÏ?[0Í0Œ­~Vk/ó§‹ CüÚFg3ÃÂ…E ³#²ÈÙ¦‘¥r³G¦æfÏ 6{Fàý¤f#Ç£Wè]I€@7„L› (*þ/j6ÍBÃ[—È-¶\Ðg5!æ¢fÃãR]Òt3²ég÷ qàÍx£Éf£õ迱†£eH6'ÀùÖ ÉæƒF÷¦dìw.(Ù°HÞ”lnCÙÖEɦ™,(ÙöwS²©„Tç–³ú +Ož%:#Ž4‹’ÍÜà‹’Í09!AÉf…3U”¿†ÏÁöw7%›K¯tXgHF›º "{[ÿBw$Q‰ Èþ²ø,:x矶v\nÞçômá±ñ¸ËÐóûu/ºŽý‘»ØØ¯ÃÓ =̺¸ÉØÃáÇÅ·viÿ&cx/0ö`°ïÜM$ãEÅ®ª¹¡Ø(Ÿ£dËLl¾/- +FÆ/"và‰º3vA™Î®¾xØ0C²Õ]ãë(`ØÌfÍò‰…]5´XØ0°ÑZ °Y<à ü&Ò‘1Ž5PØè€Òg:ÎqÆBúa£Pƒ(ßà`’ja°K4¿(Ø|1"l +ŸëØ l «æ À.-üNó¯K´zü5Ó\NÉnú5äÊ’~ò‡fH6C‡Åà“ } #ñˆA¾.!W ð5RcˆÒÜÜkTE3fNÂÈq(ê— Å6"ŸÐë¨Í`^3r8ûF^C™ÂìõE¼Fþˆîz¯¡—y½ êµüïÆ]¿OP*M»Æ~ ÆìGfðïb]7kîêºEËÖ ]7Od7éÝ#£AÒ57L<šsÄx׿ï9—ë´Gß–ÑÝü«`\÷¬Zü‹p¥c;nÙâ[c76¹ðÖˆä(£iº5\rõn  jyN¶5.øuí™¶TÓ4ñƒ:‚ñì l­Ú¹úmq­©jpš‰ÉØWøjýF#˜`Z/f@ ­_ÃEn¢5{çðhZï¢nó¬‹ „oœu vgЬÁVfÖ3`Ö­l4ïbY“]ÃH-Úâɺ…÷YÃZH£6Çš8.Œ±Æ¯± É…±®®?Yk¸uj)ê¤(ÓêS‹·Í°F…ùê@XƒÄï.ÖÅZ¡`]V¯Gó«Q”"Ö©ñÕDÊA½éÕ ÷ðêÒcntŠ’u/t5_A Û8ë€óG}z€«¼ýâV£ºN5˜.H*Ù³–¨Õ91S·Ï.SŽ€³‰âæÍÔúñ.õVçW ‹W $W£­êE«þpXq¹aÕÕØÎ`U7Ž´*zܨj6Ð+&KL¬R5^ðlÚôU7”ý=u—Zb<íü¢Œ©FÔê1àzSª's³éÛ‚TW÷Œ_Œê®êØOˆê)uZ²'DuòÔ„jKgo>õàBÌVLk’ +cÍ\Ý “ÙÉõš%M)Æ §^ œ:BóŸÐÔ­m2unSçè˜|s©_–l,µ–‹JÍ܃j7(5.Qª‰e´á°‹H÷#”±Ô(›æbG—Ûë}4µ&Ú4êb+`Ô9<…`Q³¨ßCñBQ£öïU**,Šøz.5*ï Ã>1ÔV­…º1æ6„šë2ñ^j)]zÙjÄi?Özï¦PSú„eɵ(~ Y1K­.›ãüêµÿ•Ææëò P×Ꭵ¡HÜbP·"áA D1”þ8¸!!€š4“jê õP`L%ÎÍ“†Ê”™Oã¤!'å¼hÒ‹Q0i"0™“3KzøË½QÒ¨ØJƹF1¡záI†ìˆýIÓŠÉ*8ÒàgQíbŒô,ö/Šô<»i½!°»§ ‘fbþ„1´ HC^ ¤yoŸñ‰=‚|øèé•Ù¢G³v’8émhøBGãœæ»ÁѳHŽ|s£ñý±|0°Ñ3J‚}g3£Gdˆ=œ[|èn`4d¼bR› bÛÛ t¯d/\ôäæ°"£ÎðzÀ¢)®õ+9¬Ç­>ÁßÉDé!¡ˆkÌOP4’cQh.6å£tÇÂD#ÏÖÜ×pË^×$ú:»`D/Ã…ˆÞV¢_¤˜‹ãd ñD£åÉÇ^Р°+P˜tkª o84(]"˜ %“0¢FCc1•Ó'04d©¼› u[ð£ùÕUën*t³zdA¡Arjm#¡{€Ê"4„XÄ|šë;×ú±œ`Ù2>á é¿¥¶iÐZ¿ÍUsÏŸXÐXaOÃ¥yÇa +Á(èjéM‚¬+ΟKdãú³KôÃwwºþËÅ@ÿÝùWßžoïŸþô/¯Àÿð7¿ûïÿêçßý“ŸþæÇŸ~ÿÇßýÏ?ý¿>zýö÷þÑïÿø ›ãÿþåÿõ×?é¼~û‡Ú¯íôOþæ§ÿç¯~úÛßýÓ?üí¿ûuŠõqBÿ«ŸþÝqèUèñk—ñÏþêãœþÇŸþê_ÿ›?þ‡žÍøë¿ûlþÙþíï>žÂÿð7øýÿÎûÓ¿úã—­Yÿ1zþÿžùÿöWùÇó«Oö~üõ÷ÿQùÝ?üý_zg ¿ûÇøý?ùxûþøñþæ7¶ÿƒŸþõÇiÿòçöÿ-ÿmèßþÁßüû÷oÖ±þ›üÓß~ó_ßÒûçÏ·¿ÿçö|ûûçöïñ'êûùö?}ü×ÿýaûÛoõÛÿòíÿø?Ÿoù±Ç¿ø§þg¿éHÿuÌ£?ï¿_DÄà·0”ù!øëö½{ëã¯ßã‡ÿ×ÿùy˜†{ ¯Ëú¬rQ¤Ð!XŒécYù±¶Ã|Œß/- ¢|áã§€Ù®ƒëÇ)ÀÛùš~–½ ¡µí0VAÈ>ŒŒ*ÕOÆW=Ô¶8Žß¸‹BŸñê>}„®{c‡½îÃnã}Û~œð>ìqi_îÃÇþnro^+°LÛA«T09ÿá¿ÔŒ|,´‘ÁG‘ÖD,noz¾ý/óÃ3î Ôpx»ºÇ=«RgÛa„¢ºâ¶qù˜ÇncR^F×wØ¡8®Ã–ùá‹}¼×9„ñÇýª]çö×¼îø§škÌ-Y£8~9í>Ö,6Ô¾oúd´"jŸ¶í„«½ß®Ã‚φŠëëÂøã¯œÛ:íÿúFÿ]ot5c7ÂùXã „ꊊ—ùãfÛø>Â0ˆxÌã2„Ïwx@’Ú}X³aÍuða¼®î°ï[qvß´ã®;«š{ãAêݧÃnã}Û~œð>ìqi_îÃþ˜w›Á‡¯/po’ž\ç@$õóÞg{¯K;ìû>‡Ýwì8‡ëöö.Pï½1²¯ùÓ |ïsØöã„÷aKûr¾× ‡ûAÛÛò¼6f£‡ùé°Ûx?¦m?žé:ìùô¿Ü‡u‹Ž'xMëÇãÞÓú~1Žiý0^ÓúaßÓú>ì1­ïs¸§õý¸Ï׋qv¯s8ìû„—s_Ú×ûð oÑ}‹ŽÇ}x>ëÅ8=Ÿm¼=Ÿmßײ{\õ>‡ûíÇ}n¼^Œó°Ûx?¦m?žé~9§ÿå>üøÕ]©lhÒ¾¸+a¿<I>ù0¨’³²ä¶[zx–E^óvÂøÙ]97^ÈyØm¼ÏaÛÞ‡=.íË}ø.“鞣ïÛ»Šã¶ûqœía¼.í°ïûpvß±ã®Û»Šsãå~œ‡ÝÆû¶ý8á}ØãҾ܇ï5™îiú¾ÃÛ¯8Nc{ Ç Æëêû¾Ça÷M;ÎáºÃÛ¯87^ÈyØm¼ÏaÛÞ‡=.íË}ø./ðþ.PµØË×ñ!ì×'^zÉÎÃ6¾‚°|µzú=>P–êým†ñóøpn¼>ùó°ÛxŸÃ¶'¼{\Ú—ûðý—3÷Þßòqû«?Nø0^WwØ÷­8»oÚq×Þßò¹ñúêÏÃnã}Û~œð>ìqi_îÃw^ÎÜ·wÈÇ9ìOþ8ÛÃx]Úaß÷á8ì¾cÇ9\·wÈçÆë“?»÷9lûqÂû°Ç¥}¹áTÔž!ËôÉM‚ÊŸÛݲäÿv̶ñöâ¶}ù3Ça·çsœÃå&ý¹ýõ:í/˺|ZAñ$´ö8$Ûx¯^¶}ùñÇa·Çÿ +ƒûŒtžÿÜ¡Þøû¿¼½ÿAàòÀ¾Ÿ£ÀG¬/Þ¯Yc÷ß~=â þÏSb„} ¸§3Mf1ìž< õ2>µOF¬ùk;fÛ èõÛ}Ø&=Ã}6î™föþiã.ü}Øm¼ÏaÛÞ‡=.íË}øž3 6ø|‡1%Cr†º€¶û„ãuu‡}ߊã°û¦çpÝáaÍñ½ñ:ï>ì6Þç°íÇ ï×öå>|¯™†5.Ÿo/¦„ž?½À˜‡û!61Æü´qQYÝ}Øm¼Ó¶Ïtö|ú_îÃ÷Yϯ÷ä]Á¤m²›p¿‘v(îÇfãçWçÜx½ ça·1}ysß3y¶Ö:Ïôx¼û§{wçq£×#9»éËë³Îó{Õ¿øy@ûu§à¹Bùt}ÕŸokõ-ºû)ªsøÕSýÕ<»×9ö}ÂÇ8³/íë}ø…á¾EÇ—»³Òñ‹‡ñ:½Ã¾¯eöS Tçð5ªêS ´~¾E‡ñ~LÛ~<Ó=ÎOÿË}ø>“~’tóóí–±÷íucÄûönã}{·}߇}ØOÉuÃ×äú}nWr½¿k¹²¦ ?åÓî3yGû4Mlã=MlûÏ÷a‘ŸÃ=M|=·ï6\,׺ÚYü¼Äûµj`èÍéŠm´ùy‰Á ^YÁnÖþñ}6~^bœ¯UÃyØm¼ÏaÛÞ‡=.íË}ønÁnùÕ÷íÝ ãö’á8ÛÃx]Úaß÷á8ì¾cÇ9\·w/Î×’á<ì6Þç°íÇ ï×öå>|Ç`·]ëûïµÀq{Õpœða¼®î°ï[qvß´ã®;¼×çÆkÕpvïsØöã„÷aKûr¾[°ûðßèéý2>„ýúäzËŸÆÆéÚø2> ¨‡NT÷aþ»¿L™> {Ãõ±ŸÜÆû×·ý8Õ}Ð㢾Üï|¸ïíþŠÓØßûq‡ñººÃ¾oÅqظeÇ÷vÁ{Ãõ¥ŸÜÆû×·ý8Õ}Ð㢾Üïv¸oìþxsØŸùq¶‡ñº´Ã¾ïÃqظ_Ç7v¸{ÃõŸÜÆû×·ý8Õ}Ð㢾Üÿc¯ÿü÷¿ÿ—?ÿô—ßúç¸ë\èµ4ÔºðŽ!rJ©DùöÓþÛÏöö±Šz»ìçq~;ó{Ÿç÷ç^'…’«9‹@.Œö J¾¿(ãf¹Œí™MÆ„ªúâïS½qEÙ×—Ûà_ü­<Öêâ4|ü•AµPʲì,ãûñ%ùwQ–!c+O¦Ž²N¦£ÞÖ?ŠV©¶vªÆ%¢,IÆÔŸÂLó8ÀôŽNa=„âù°‡ÖÇ©óŸ2zŠÿö \—ì¯4¬=žšF"ö—å>èþ½ñ5ÅÃx>ñ{c½œ°§o¶ay̯hNÿŒO²ñÂöÞ×ÆÞ´b¢Ö1æü¥Øç†¾BzÐèTSKœÀU¶¢u•M@¶Ú8[ݳ¦ ?¬ýæ–ýõ=šâ +Ȭú/žÁȃúð¦|‘l‚±U{K<ª\_?˜ê·›:Æßñ´À4Ÿú'|…m‡hœÓý¡bíkÛ4ØÜF@›7dºÖRޑŗqÔ£^ÉÆŸùùùÃcNÃgÆâØ"õ/b]_EaŠ—²ÒŸ—ýioØÓôM­ÄéúIΤOFTÌÒÈö%6¢é‘ŒI¥U¿ø‹k¨¬h*¯Ï‡öÆÉoüzS`Ìéõ“Äðfcmñ$çºW°¯w>![ïŸC+L³†/Ó/Òäëñp_=úØ8¾Œ‰Gó‹Wq¾M':tŸõx›X*,{ë5¦•©ÒVÙßïÙ 2ƨýåÈû”Ãû|‘ûyÙÁø–½jÄ€5«~j¾"´ƒÍ~d]Ægóœ$«mõ>…8»†v߯^(4v@ÇöêOÑ 0Æ+?;_yÁŸÝleêôh:!¯G_?—#œç°Ooû+@ͦ§žÆã­ÍÓ¿É£ùᴊŤ›9|1–˜”á×÷ñ¢ »øá”TãõyÙým„½óAÐØÓ/s ㌷›MM^oœÑÀÂÆ?ÇéÏa½h¨`1f°‹çÏaÿø¸|ðŠÃ‡<âí«ÙÆæï _dÌl\Åìýø¥DY=؄׬ôõÎoÝl4Œb.]ßÞC›¿¥¼< ö”ÜóÇÛáÄL­…=àjŠ-$èöØxÆa?Àyçîëþù—Ìl??Üàÿ}Ý}@Jeß#6ì³Ä(W5Nâ OÌ7tüÚÝ÷‹`NÌÊœ‚~^öÑÔ·»èÉ1«ß±ÖuG`ìOxÏ·ö\bc¿¥M´8l•ùõöéI„Z ‘-¡¡ÒcW‡®ÈÏaOOò†¦¥øCï}0=®€…ì[JsŠu92VO€zq ÷ §p{“ñƒtÖ×ÄEævmÌýôû~m±½Ä*–­Fl´×ƒ#¬aèWÝÉ×ÍfÞa|íN’[ú‹Wq~t[5“Î^÷G1À K½ß†=¼…Ad½lÿ½·ënëFEç9kå?ð%÷&s[ÌÆ7vgõƒ­|LÎQb¯8éIϬYZ´DÇœP¢E9qÿñó8U…*`“”ÄMË–(3݉È"vm Ô7 +ˆc-bÑPGÞ±&uŽd!¼˜Â¬Ó#76Tó“‘düx±–¬Å\ŠUþÖ TCáˆl³Å@ÑÔ[ÌŒD õˆ€M½¸±ìÁµã¶Pr:#=§^ +X—âðš®Õ»kkæµmªÍQ-y”3«ûà·´­ñþßÅFJœ;ërwQrf ÞçÅ«[· +Äë¯1›BtoòhþTЦ]y>Q‰§…EN BqÄ;}Þ>¡Z\è©zЊÝî}›•ƒêS&X4"¸cÉHj«†‚X7l𨀠GayÆ6ê±ë®yðj6ypp÷fdyšiƒ—tò¢…j=‰×´ä]†Uùs¿LÌÔÅVñÆ1ª-’¡$ÒÛùÜXC¡#šŠÅ´…“ýE¡×CR/X‡Îôµ`ºñ‘ 2óÄ™¼tàÒ·Œ¶52ñPÑ\ˆµ67õšû€ÚK~‘“–ÞÛ‚A+"$,ÎL]K7’Ðëld`ãUCÓÈü¤±ñР|ªÍH"뇥•ª«Q8ȓȘuµ¼&ñ©òµ†™g:ÅÊ1ì7p +ª@†ÀË=/4(ÐÃÝ%ñ µ*½( QV/•|].FìÅ% %]iË7Å[’ ~å–²±Ú+Ì6ÈÆÊ„¸m#T"Qƒ wèé`‰ ’[¶žå”1¾`(ŽÁl׺¦Z¹®3Aè‰TT²1”‘¼ª ¸áÃbN;b™ß¼3fˆH(ñC²± ðÔe‘@†7LãÅA£&qÕÀ5'Ü=CKú b‰ŽE£eQžàÆóöÈŠfÚ©CohÔ‘í~ºÈЏՅnx7 ÓŽ¨ —eƒWö²·GÉÂÆû5 Ãátµ0ñì¤`á.™MkÀA½.gP" A +܉~ÙÚ\ÇæFÍÕjֲϑ(žÀ ÉQÀ†ÅŒÎ—0™×–X&\Œ"’2û ذäh{òñ^Ysà=bxa±Ù¤vxýT”gøuÊòÎi[ºƒ0ðIBDóóÂØ…·–áZ¼‘ð¼DÉZG&(4vlå‡@[lA±€àjy:|Ë›&Š:I^öîZavá°MÆÎO›©¦ÇáA¸yÍù¼÷-W.Ë$&ûn&²6Ýet +øeí1fðWgÚÈĦMøÙ©w%:/̸1Ü5¬Ì[—Ø9[ÇGê"íÓzVÂÎÊH¶H èŒ1Cx•è©­©¤Mμ_ÛÒ1#’-3n|™áùl³+€p‘ +Ñ |±±vŒ¸%÷Yëè>ulŒìƒ€,Ük= ᆬ9¼©TæÓ‰Îú™Åp_xÙÌi\žÖ€¥ð>D¨æHQðäàÂZ­X –Æ7°°vëZñAiLqûÈmÍú1¯¨°*öI´22¨X(BtZQÄ=è‚4 ¯<$xŒEWÙnÉ"ßBíTi”b %ª[!‚‡%ÆeFEÙ°än›4t^MxQÆÐPˆ0o•ÛaØè Î@±ÊM+.ò +1ÒÖª(¨M¨•A`ƒPLŒ„íYkÖ™iD¨Ýdå‚})È«xѳ(Ax‘“°vntÃ&¯òÜ(-*Uvòæþކ2°C,[Ê^h…c¯óô {öÄ«Í^bÛÑnÅIßäxF2^±¥¡ ¨Sm¦‚‘ ž°eÖ‰¥G…Áh:b¸R’G˜^öA1ã·žÌq,»"òñ¸Mˆ_A£ÈB =Šùa¨åÎŒÞ{JÒ€zÆâ‹Ââíàu‰à?­[H¬Á­z>fVar” R„"ïJÃÎÜ@w|æéòâÏ#cHóÁñm¼c¯•-œ½JR°4KZÁQfœc6. $ÙË@@Þ×mvW;¥¢¸C.Œ¯Ó:»»àî2Ò¢|—5ÞØò¬ÖAø…¡­(m¤5-ól\d‚¡1Ìqµ¦z€»É„³å:$wg÷oÖ$óìe2Ò­ò¹±—Æ- ¯oõÍ¢]"g€Á—ukøuMVì`ÊZF«¢¨H^„ ^uÍb¼ms‡Á bi(u­ÇŠº‘ÄHá +jÅ]‘Aa6ô¼x`XÎa¶VöÍF/²¶å€“¼‡b±¢ÓVœÕ€¼ +^¡Y axD\môàÁ¢ÃÇÙ0ÍÚP:1o›·™•F²”0jT6v†€> êkÁrˆ]‡9HÀ9ðšâ&ÞÓ­Dr¶¼ÜF!Y£xE-sŸó¨r‚/Š2áÚQ¢Ë'êàU8LK!bF63U†wžpS¼£ …ÿÛìè $8`‚pÆ $µC|†Ô–í"ÍI´Nü¯JÉŠýKHBÉεâ.Ù#Œ€9M®^ÔÌdMa ¶$Gº‡€Vø©† +Ít¢Éb8%cˆU„½ƒ6HÂ.d°’p„«ÈDŠñÐð.^&'Ù+Ìd$A -%~×e žt!êmkÙ¿pI«Ï9˜žÒ1óº•ÄÛÖòkƒ­rlcN‰ôt‹ÎA'u×s\€Ë6’Ö†¯s|:!ÊëœPA5šVôcÝÁ`ÅtVY6Ú|ûIæ?‚Á´ìÔÃ,uÁÐ8I>É@hlø|€³t<Á:1¾áfw1­¬£ÚØD¸ +æˆáÁ0çd*8èXåK Ug É<$ŸQÌ%‡7c(çA+ù6uB±«¢c è-^eÏ}p­å„âh9=sS2+qs8³A8¸Å.'[dš…êt¼(k +ƒùÎ Fs +ukX?ÕÙ3'#Ō…*‚g•OG X¸Y¼Çi‚—Ýa¬­à,\!àLÜß&m½Äråêã‰pÏ'9<iÉ}‰cå±$û@q·ùü³»6pÉ7UÔÅ´Òå£0õ¼Ç u‡$@fó}ÓYÍ«[SÕ2ÒüÈøÂSô€%r‡ðÀ<”óFmp•m7£Š%/)WVRý³ ‹÷“jaá^€1ÁVJÐt€Á]…âÈ>3Û@`™®–¬ð¦rç+Cš}êÈù¦±áܲ˜%.&0ó¤÷(x<7nMËk¤Ð?¤±èZìi1ù³,ŠH>A¢®5¼c» ¼­•Èki,ÌË•„<kÙ’1À-‚HËA ÃÉ´mÖˆL,|݉â`à‚U>TÆç¸à®6CØoqíY’v76¥œb #Q¨‚çÓ(i[òäÆXu!­hQòåèJ 7š´â­²å(\iĈåPB¨dk¦P…Ix9SÆ."ærmu´}†y9ä|8S;j”—cr­db'­Ü”®)ÇÎ äE¹¿âhQÙ«@_Ôn ¾áÅÁ‘ÏÏæHtîši×Ïq^8š) +‹já°ØÂœG9öa´ðp§«ã ¶áã\ }E)Y쑹$€d±;ÃV)J2¸§›£$™ËÓ]©màóÞŠårÀó"ä³GTþ%Ù·š\VD¶rÌ'ჶ¡Þ¶dA’ý` ”=P¼}à÷ðV¶§.Î>qÕæ“"àK)gÊ•+BË¢ÉÆ6xnt ¼g5µáŧ+§X3+¢V D€·|›Ï’&ÈÎ"~@Å-+¯ë«~hÖ4[mS=XšIgB´buç÷*RZ:ÄsJþÀŒÙnC0× +@_‡øîJÙò(á•ð~MAM¸òÚŠed/@%1ËÕ r:Ud9®)Ð 0Ã:ª*Ñ8p@¶¢ÓPZ$K]€´­B†–]>ÉjŽC9¦Öf8cäÿ&{}Ô„¶¾0ÿ¼`Œtp¦Ø²¿U·LǦö¬¢C‹>¿ÌJb““:ÎVgÓ¢˜¤àó r~´/O®Ó,0ófŸ¯˜¥M>AïÀQêM#˜cä“„¾ +¦8Ézw¤I ?¼pmHƒÎ@Ÿóõ àAqg{ÊÔ 7696á%Õ‰_"2™Uf‚‡^ELŽM4^ŽVæH.,<Ÿ“t±°89ÉÉKô¼"óáæ4ŠÏãB ic¸•>´bÆpö „ƒ,kÈò($LĉIæ—}Õ±>,È>éX󥦩0p^¯“,*YÔys__Xƒƒ<Ž-Påø-SAg§Œ« !Üq¥ Ü +%´ÖxÇí3{ˆßpRƒv|”ÔTAÌ\-ãœòЩÆñÄ,A¡‡ã2ìÆZÊu\SÛÃ[–'œËáÎìºË5¸¥ÌZ™ ߈êí$"¡UÅ| 9SK#uðÌ“`p¾È4Ï‘\vøáºB1/)eµáå8:&•M|Œ–B ⦟”G¬ÂÙ󪆖-Ó½ŠªBz€“}ÄÒ°÷⇠ÍEFB6d”óÖ!HãÈU(¬3’Šàù„·-ùS˜ÁëÒæD:H‡È>5'‚:&ë ak8j‘–Y-{ƒ×–O xˆ¼å8V ùrÜgE2S„Õâž ÅÊãÄWo$wБþL@-;žIn ŸqY&AŒ_'¥à!âY0¦ÊÀ¢}–Ù÷¢ñ4”xé!Ÿ–•èÝà7•åðˆd)ìáË!—•& +†¶¸ÇKh”hB"ªC#®³Rý,”Sê°–Zν®D‡ ¼—9 K°ß7©œŒ3c<± ÁÀ,Xb”¤Ýà¥*‡ÉVq`ÖoãØó«³ô†J -[¸¶P=5æ$nÇݱĬçºë«~˜ÊÚ4’—m%9¬ÉÓ©Ö’ÕPÎ}"\ü/sÇÆR,ÆÀI`ù]ƒ­êÕD3’MFwdއ’%äë<§çd˜R °JA.ôBÐHü¯ ºÊY·9sÒ‘›‹€¼ö`z'âkÇbïCËœä£~%µ4œœrâoN<8\0Àd +±bqXr çÜ;l,å¼À>ø;7¶™AoæHPìØÄÈ ­b#ÛÑC ž—/Ù.”Ä ÔÞ ÈÙpŽ<÷‚¡8SÜCåÇ·MÃ}ðâí´A¾¡*«·¤É™óùà©] !Ê +Gi‚ÏI: +øÈáŒ(š¸Ë†o(n[GG~ ¨c…A€o³0)Ç1£%(â(?%ÞÇ °Zap/c†à “XVO[…œ¼‰ŒÁ-‚–ò'ÄßXÔV5ÄàZ)óÕjËŽMU¨¯á4^±³Êdf’€­xi0„|Èω²6‘xDr5ÌeÈqZ M9šÔŸ>ÃɃh }³Ó/£çɨι@ãV¤œ+£hyÃñ¶X›‡m9b˜¥V)W£Œå<®§J:,u+QµË”òYMz^!N»\Ø0Ë(\„Ä #iƒGK¹sÄr¨lǯråô/T¬ö¢[7\¬¬_—-Wc9¯‡/Jg]nÉ13/a"¨é燽Ñq”øsÄp­™C±‘ŽJ‹>› ¸,…õV“ë…U;©|Äê&uV—pB¸¦%ž“)”XôÑ1§ØH2¹ XôRyl±œ€/‰ UÈèZ±´P/Î@Å2/)§Ô7Líá"€QlSNr2äUp¬ˆÅ\m†Úóé@¨ Ë«Wµrp1H5<÷œ1CýG~#gÄ(yý@LËhù̃#¦œ1€ÞÇsÊ~è¶²1Òj9Ô©•FzÎu +/Ä:G /Ƌ˾˜VI€Öqˆ®UŠË¦OF¬$ÕÇ•£Õ +ªâñÛ²€"5m‘¦­ÕÈIA®1¼ÒŸ-U’iáˆ- +†²]1ZŸ§É£LKÈÉÑ]/†>—Ýl ż‰–^&àâ§ÌµqÄ g²¥g’µT–läxjuVÙÿ8bx̺²~ZÌ¡”uÒðInUìƒê¾¯\¦¡­ÔÂabî[ÎNjKôÐÑîËJex¯ã¶‘ jöK +endstream endobj 63 0 obj <>stream +À!~ñl`f… ±•îÒËZ9kYlæ@°£²àA+'QTð$¸²¬+p(¦m©šdÞ*Ã8¿ÀQÉAË$›(õ"š*ÚÀe¬ è„+|4W4ÓUÑL̲9$ ºr=fu e¸Ìå7tU5ÖK$á†1¥1÷ÍPÚ9Åä’*pz§˜Jj€w&Êꓲ{©%' ¹ê>´×bÂ)—ëMغvt\qÄK`½øs޵c2Çå£P¶Äˆœq¤°mu™:z]bð‘C4˜[”1ƒ!0÷ÜØ±ÃËæºi/t_4@K ^Ã=U¼Kå2aMj3ŽRš2†P¥[JÌ€2¬ïr¢œÕÍQÆ+™ˆ%8^üs±Íu:(¶,—a+I²…±´Ím\ J#-ÙʬÿªŒ±7}kµ-Øû”3CT't#wœdñMò¼•UŠõ.«ÒAR ™2(ØHÐÏîn ¡6Õ3+ +•P/mÉÈism7ðH4¨*‹ÔH5G…QrY$͆¨ÊôNÀ@+*ÂÅŒÌê:c‰äšÉNRÑW)É®¿Õkbm]û\ãNÕIE­Cñ]¶M#£òZ®:Õg@A0”ªŸ%M0¤ú)¥*ag›¢Ïƪ žõÄjXqtÄ[Š>§K%lÌ~4×s[ñcëL ÇXX+mJ]@-Çœ@Í@+Zi.…¥³¸¯>TÏk âaØ#†qá¼fN˜'³¬äÂ. 3µ¶`ÆŠ¾¸1sB—k¦é*`SWÅÓU¸…ù¹2¢²aí[•r³¶,pøðF Tñ€œñCË$9ÁAvjÈÌ ±Ô¼wŠ/Èõ̓¥1Zi¼WGa½¬bgQª; _w1H '‚ëjTu¥éç’98 ¢øF]/V"ö¹T¢ï!W/éá(hUf ¨ã%ƒëx)ãFI4qrJå¢<^dTÎ"‚¢s•g*fh%3+‡TUò‚Çs¹ÁÚ‡•ÃÑ rGIñÂr6G[Å[É‚k¸î£«Ó7J­uÀPœš¼q ïeáIÂPæW”t(oÈ%¿ŠŒ€š‡-³\iPÑKÒŽ<ªÌ&¤V¾ª-<O£Ê”—"¨^*rÁ"+œëɰMê"j•$E^ mÏatU\•¦Š7Žýs˜äšåN 13°îkp²xi£hE~C®8Òtm”ô€¥)ffÀÖJLj$`,y‹ÎÚ‚¡ +‘H*}ú ÉàjbÇn[æ…p?€D0Uv`hɶE8O2ÛElKzI ]ÜOk]{9~žs\3VLòamžø ’ÌF UCš2§/•@ÂådNgîT¢hÙÓmE#Ò¡¢²6yžàЈ„…4©:ÈùLGÞñCÆÐ†ÊÞ¦ÆQNdy©Ÿ +Wh^‚Zèã º\Áƒ¶ ‰pp¿b•«îT™ýëoi0FjÖf)ªã PHG eТÊ‘6‘‹0U¦ƒµ[*éí*ð %u°ú{Ec. ט|EÔ…RäOù©uªÄêÒA"¡¥œ§rGQUBNÅñQ¸Ö—[2àÀ$—À’lbh¨l¦gæ*вK•Ô{Zˆ\ $gÔ †Ri4×N@_Ns]8\Ýr:õƒ l¥N7tÔl(5[h©öà ”2ÑxÆjäY‰Ø¼ÔÝÎ)D°—£ ¶æ$…‡R…890§83?‘“Ë.×µ¼é©¢Åª¯¶“§!S© –ªcxLãyZ›ÙDä£õ¬ÊŒf÷s¡µH…$ +õR1Qå]kè<7u˜99(,e¡Y á†ž —›¶RB•õi> ‹µ®KÒl¥MƒŠ+åv¢e RÞ3Ø +ƒ•ÍŒ^L–º9¤ "*JÌÓÌ”¸öGÐC(÷(‘q\K…Â7$§IÅ»¼öT]‘ב2¨UUäû%ÊYШƒ‘꫌@ñb…ûÃU ¹Ü¼®¥1éBlaé<#öteŠqæ^>ˆ@ËÆwvXuT/52½ú:IPvJÌÜ%:‰þõ¸üòk1˺Fë™À%79{6&î`Jž@ íd{¯\o##_•(éJ7ŒZÔ¹‰"³Ylá Väuf¯ö´¼N¬-[±bºË-€KMn»®Ñp6Ÿ æã:j®?f²æ´H)kÃY] —>Zw(æ»ËKí^PÎ +x]i]]ë‡:éÑz4GÕÅ~Ke9äb?ÓÊFÏ ‡²X??¥8½‘ªù炚¯ùê.R-XW+ƒÈMKõ$ä¦?'Z‰)eO¼”BãÊ`”cþ†«;¬«T‘_ +®#9.ráR;Íp­#–®0¹›JG”ºŠ&'Ì#)°P¥D„¤d¬ví¨¾Üª[$O.·â3×wœ˜[”qN1…ÀžsÞçC„ý*…)¸F³/‡€ä^‡õuúòv\)·uÆð ãäx.È™–@)È(•$Ï.¦¤sʼL +Å`rÌÚÖ·åý)?¸º¢‹kPf/F·q¾Çä¦j•x‰’– +@_5=¸æÚ¢µ=“ù†zi¥vpÚå~ØF. Èµxá$TæÃº×´õ\ß*K}Ä)Ê+MYí€Ô "'eÿ¸k&ó*#V])Ý ÷ä‹iÈKÝqe‹PÕ)—M¬¾°¾Vyé‰Ò)Œ¦bé‹”Œ°¹Ê*ƒ(XùÜÈÚ¾ÈKKs,~ëKƒXâr+Wò_r¹à +ÞÃêÊ0o‹q¬ê+CÅ$ÃzeåÊPÇõ¶œ\ +ë-ó|Ë·J¯ .Œ²¡ +Sô“—›vmC^ +‚G¹1Š1›+÷#rPUhö†^—J\|™£­¯È÷C­é[é6œ¶”ƒÙMé¶’X–÷Re¡5rž—ÑCùñ“墀ÁŠg½QUSŽÿñµ²Jüa¾PZé[-–|ɳr¹"Ô4h•DU)µãzD%ç¬äçØÂøK* %‹,{kºP¼!`ÄÍy&p%ЂŽnJ:£æ"xZ2\¸Ó«ˆË;eÌ’ôåj(è×ÊÎ4Õ9Î(¥n´\³Oá²¾J„pÕ°¼T1wT=] +$–Ô´Ž®ÁsT] X”X,í)WĕӀÕ(ïlJh]ñµˆx€ð›ÀÀ%ÌEäµR›<Ç#În'0rQ%Hï”h¯Ïì)´Tè¼£{çÆ%lÍ·R¶T@#¯QËh—úPÔÞ¦ŠáQ«3†—;“ñœœd¶”ûj1[úèÿólzž~™ÏGËmN^O¦§óñ9¶Ðƒ/¿?_”á?‹·cüñó¤å|öÅàË_Î'' þ"á>ÿ­ÛöÍhz•ÿ19]¼¾¹õù茧îäæÙ…¡½O~{½Ø|lÜþ¾÷äûã'Ó‹×£cµñ'§©émã‚F÷5¦ÙËÿŸ,žÎ®ÎOSŸÎþÜxh¯p¥¶‹Ëͧ°óÐ}¹Ç½…õÐþ܉½Ý|@oed·õú¡1ØÅÕüåÕt|~2Þ˜.ô𦤑WÝÛð6Ø||y5íÁd¹ý½­ådYo<¸—£Ëñ·óñÿ¹JsÝce/=v_CÕóüêìÙÉbôf܃ÕÖÏÜ×Ïg/“ÅÉ-úK5ÐKlþódÚg¤‡6dY×GÝ4žõ¢¼–‰ãŸ7d=Uÿožœ‡Ïa&ç·,䎮ïk9¾˜]ÍOÆßÍG¯''=Æ×gx÷7ºÛúY iv1ž³ùæ+OÜó;œ]Ì.'‹^ûë=u•Ùûñå×ãWƒ¯öÆéÞ8}ƒãÔîÓ½qº<´½qú`ì«ù(©åÓg“˽yºƒæéæÎ¿Ý¶N7—#{ëto>X³·N÷ÖéÞ:½½;bÚÇköÚZ§OÇoÆÓ¯G§³?Sõ@?:‹­×> +›D3úW`Þ\Ï¿\œ~=~3A·úè¿õS÷5Ê—Ó«[dáÝ¥÷©||7ºº¼œŒÎŸÞ:Ö‡­ßo¾"O{pŸÓ°¥O{ˆˆÓ{”½öÓ®°ÂÙ«W—ãÅíÛg÷YÅ3é.3‰)(´ z2›Îæýãõ­FWG’½öð§ææ÷µ,7χ¹¼š¿Œ_œŒz ¯óÔž£Üá ./Æ'Ï®nÙh;ìWÍæk3‘âj:šóçÅì||Þc«OÞÛp{öpv~¹m3ÚòäŽMÉŒLÿlL±nN¢Þ£mìúŒiGì}Õk¢Þ‹Åÿ¾ç³Éù⨗³ì/ï¯7/òÞ>ÊÊË.+`ÛùDv%ÓWpïŠBòáÂ0;1m;j¾mfzh ds‰óû-zW=CÐö¾V_ÝâêŒÈî‚Âû»é1"³#ê!«~ß)Qµ+BøqgDŒæ“Åë³ñ¢ÇÐvQ$O'‹ç£Émð^&o3#M¤oá@ßb·Þç,ÿ0žÿ6ºî²æÕ{K~ “ô^;ó:ò(ÓÁÔ>ì/»™v8›MŸÎÇãnµ{ð¹`ãy¥·ù2ÝwxŸ÷Q¤¿©áæ¥ +æ£ÓÉUEÌíïׯ|œ©}§“é¨GVÄ.Z—›OÚ®…Ö{,ÇÓËñôþµóÙüâõl:ûmsÞùm¨ÇÌ÷œp9áã=sÛã°ßžÞ‡¾üèòµû/Ý øró¸×α‡ž§Év‡?ì~–ö£/vÑgñí +«è¡Øî«hz(í»]½có3ûê7ýèVïxè;rÇ$Üã(HrKêS½{žÌ¹ç#9=ÖÝÎ$=F‰½ùÜ5‰Ých[°¾û ~n\:|=:?O_Œ§ã“^î¨Õ'ïk´?mÜz´«OÞ³Xûzry1ŒÏÆç‹F»,ÛÎF Ýæì]²Ýšÿo°òQu>n<|üØC½äö»À^wEnîŽÜ9aس¶ïîØ‡pˆÿ‡ XÍÃf–}&hG¶S#Ï»\hsÉÎ1͇öž˜ÆCÛ¥¯ú¥¾šL§½’ò¦÷7Ù›ïÁj€Ò‡q›Žté±ûòùì|ó¹œ\]Ýž ÐgõÌ} r>F{bóqžžN“7}F)OÜ×§“óñhóƒ#'£éɳ9þÕ÷fqÜbÔá¸Ò²GØšß×ÀÜæ;íQœŽ?|ÕçÕ|vÖCD`ëûÕhúÇèíæÓ•Ô—ÅhÞOß¡îm-nõpUÌîÙHOÎúÈ­¿¼¯Ž<žB“qŸ¹ôà ГǛ¹Ôch;æÏÙg.m"RîÕûÝgñí +«xÌ™K͵¸=jJîs—|îR=¹c2îqä.m®ïVîRŸu·3¹KQf?ÞÜ¥CÛç.ís—ö¹KûÜ¥ís—ÔG—»Ô‡½îŠ0|¼¹K=†¶cvÀ#É]ê3A;²>ŽÜ¥“Ç›»Ôch;Æ4ÞCmS±úLp¦sŸü( +…öÉÜOÏŸž÷Z§gçfç½vætä1p}òýñ×Xšé¸§¯ì§'÷pˆîX]±Ç]ÏÿÃÖ»Wö¼Uݪ=[Ü‚-ú=[ÌãÛœ{¶¸g‹{¶ø8Ùâ7óÙ+‹{eqǹâÖñž)î™âÝ1Žª¸W÷LqÏ÷L™ba;î™|ðˆyãæ”¸£˜ø.FY÷;mëö;-osJìwÚ~§Ý¾ž\3p›gs ~ê“ÐY=r_`â&Ï'Ž§Ï§£·Ç=OÇ>ä¼ù{¾pÙç||6»­€ÍŽVišœŸŽ_MÎo½+º“¹w1-¾îS;¥z侺!Ú×¢ÚxœûZT¦ŽÚT£ÚxˆûZT¨•ê1²Ý)FõèË6©úJ7åÒ›Aú÷«ô9ýý*ý0ø‡˜îÏ|Ú¢´ÓCÓÖó5ºÜ¿Ÿ\ï[-÷>HÒkpû£$;ÛÚ•â ýÖàŽðÆÛúywñºû9Ÿ4;»˜]&CýÙÕ-Üîn˜ã}ò‘Cë.3‘ͤ¿ßâ^¬gÚÞ›¶ùˆn‰íuFdïQÓß|D·¤·uFdvbD=¤Õï÷(¬¶ÓçwEoÅÖwE$æ“Åë³ñ¢‡µë¢ùƒ”ˆ}L²yBÛMøþäë;vætdÍÑüžu@÷Ñü¥™ÜGóo"Ð>š¿æï£ù[mÌÇÍßß,µæ¯ŒkÍïê-ÄóuóU?UwÁß%ßn¸Äöü}ÿCrÁÿaÓÉ«WW—ãÃÙy’Sç=–áʃ÷µߎ§ÓÙx:ùíõ"588jÁ›wù¹{SÃz2–ý. é:¿-uaïs¼wýÍoîOÓ·~^¹ê‘{c1qóŽþ99»ZÜr'lGúñ÷ì¾úz‚¾˜#Pä@¶PêKGY±Üå ’xÙÇãbÚû_vÖÿry1>IÖÆü“yðë3“ã›?/’¡×Ç¿½úä½ wsÉÅîïÎ_}rï‰Ú{¢öž¨½'jï‰ê½z÷ž¨½'j¶÷D}PÉ~'òDe·:¤öž¨]3´÷ž¨»òDÝŸêvßÑñÅ¿ö"mÁÁö¸Ï¹oã–Ù—Ó#¯<ó=j÷ÉßEá™%@ö…gþˆv¤ðLíHá™Þ™Ž;#Œ÷ÝMIÕ™édñ|4¹-ı—ÉB&ï‹Á=|™¼/÷ðeòvfä®ÈåÞ,}/’¤HÞë)“w1Ï¢ÿdï À½cg@Gc¸'ß¿x=:ý±¿ç¬Ìñ/_e´Ç\wcóšûº[÷x,%*6¿þøtó»¹±í}­¾#º…wFôçŽì§]a…³W¯.Ç Ø>óñi?n¿£,ãŽø#¶UÞaÊ?£å¡M׋ÏìÜLíÍËÝ3/•m>Ûxÿ19í“ߗ(U¦ÇÐ^{¥ÍIûû\q ì ¦ß•[à^Æ| Üæ«´‡f~Šy¯!õ0ŸÞî7Ðbñ{çÍ#±Ä‹ó&>:çMí7{çÍÞy³ Sþ1¸Útí7{çÍãqÞ€`1ꓸµw<¾Ì€WóÑÉb4ýq6éq‚ß”Lò²{àÉ{Í⺟!mîµÛµúWÍpóX/G—ãoçãÿs5>?éaŠ-=v_#íQúêüêìYÚ¤oúÔl¨Ÿ¹¯!žÏ^,&‹“[œþ4ÿy2í3ÒÎC;°%÷eó¯Àûbe­XY»¯U¶ñ8÷µÊöµÊîfˆ²¢WðÕ|vÖCj`ëû×£¯TÖ 7¿q1ëa?Î6V‚Þûg‹ÒcïË!öóÕüåÕ4‰ãGàH}¬‘úØ;âqøpuîÓõ½ÕÙǽǹ‡Ëãñ¦ öÚ¦ ¹s|K…„}¼à&¯Åý§ öX§»‘0Øc@EºàbCqGã90¼Gþh>–øÇæYiûðGŸðÇ}*Ð{ëôá[§½øçÞ>ÝÛ§{ûtoŸî’}º¹µ·O÷öéƒÐGaŸ>úŒÃGn¡n^ f· ÔÍǹ7P÷êÞ@ݨ{uo ¾_+Î=^µÏÐvÐ@ý÷Ùìô·ù¨Ø[§Ð:=PÎ>í5¤ÂB}Ü—èln×ìK®çàñÕÏùPÞ·{ܳ{9«~ŸÌc÷ μÜíN”ª¿¹+[î‘'rBØÖæÏè‚€Ç¢Ú ەͦ†=éí°ú_OâæwwtÛ=ýÿñÊ8XŽ¿¾Ï¿ÌŒ è¡Íþbô²ÇÌï’cW6§ þÞÓsÛy螙ѷWç'?í2z¼ëpÍàãZ‰ßíWâƒ\‰êcc‰OBŠÚgP•àçùèüòU«ràîØö<Í®x|¶ÒwE!þœ>´>’Æ¿wûÜ0e˜>ùd:}(“õÐè³å’Þgô¾cg@G¶»Uï³'ß«æø›óS¹]a@Ç?ÎΟ',Xµì ߎ›œ×¿|úÉ„ÇÒ/Þž½œMS—žœž¾½™Íé|Ú ž|úI3øõO?¹Âÿ7ƒgé?C߆dz•6PöÔPù&D›>øÐ¸Ó‡½nðëãt«_ß·ÿ•>ýw‚ý1PÍà‡ÁþW38M/ûõ§O?9h†ÖzÛVÃ謜% òCÕ665*§ìà@Û¡kM@s­bzÏvð¤´C¯¢òƒÃô •úØ„Áí0¸6=¬›aÓØ?hçàƒ6ѧ¨04^„ߪÁ uÃ… ÌhÝ0j¯ ’º‹e­+|°¶QÛªY;ÔÖ7ðF=Ôjpð4z âP)k°÷B‹¥†éźo‡­ò®4L 84€“P¥w5mcÊ»”Mƒ«_žz”`­÷J#—f.ê2´4Vë[Ý!€jÓG :“)ý>„BI˜gt¡w†ÀxbŽf[œ,ç•Óø qM &©MýÚ¦¶‰ðº¡iœ'Lí°m­ïÀ ¬>“°ÃDÇÐŒšÐ&„Dï#¸OFkýXê{͘҂&Ú! È£ÐÒŒ¤…¢LdjjLšA SZ®ªõ³&M, +ç:s€ôTê[ã+0“H¢¼+À»Aµ Ò\{eh™ØÔ%¹ ²mÓDeQV¯ƒÕŒ”®š¥.(J¿a‘5iÕƒƒíc”v…@9¯]¡ÒÑeß!ú)@&:lÆô¬O„PCÝø†Pø4i@!Õ…dÌÜMX©µsa czØìÐÛ˜V“öi%ºû´E¬sƒ´ûc515(mSÕ¶Z,ª„ø‚Ìi™º3ÌêWŸ~ò pµÄÀNÓ‹Ÿ1øõß{=^ËËx[n–]Çϼ%G£ÎlÅÓàÑ­¸ZM—š¯}v¼†³}vÜŸ·}v¼wKÏmÅß>;^ÇáÚŸÇás+\.A×ð¹ÏŽ·ãté¹5¼±mÁíݶâwŸoËñÒÚŽçÑz߆ëÑ&ÛŠï¥G×q>oÃûÒRèÍý>;^ÃÿÒ¼­rÀÏŽ·âŸŸƒ6üù“óÙù ÕžX hŒ GÛš6‘]Iî=(†ˆ20­[ä J3ÜZC¬!q‰´×ÔZ?zDŠiZ?f- X@KL…]BR,rGÖ€ªqfaÊVAU/–ÇytƒÔXC“¬)æo ] +´zÌê*m*hÕý‚`-°"GéÖZ`çñ5t*ÀNŸÖЪ^]D¦_˜¬ÖE×JÿìØe‹,Ù6æy²rÇóóŸ’…s¹˜câÄÏlœ!ÓJ[±Ø´‹|b·Ö¥]ÔV“YóåOãÑ”’îá‰ÖöÅtB%““AõÝ|rú¿Ço3æôàÓÙlÚiþÍ9øÍ¿»šœf“; tµ«PÜv¾¨: æÞñ§Ÿ´²<ÄöËÛ:#îéÕb1;?ž½IÆå’ ÷¯W@ȯe_^g—Ù%³¬$£1ñ›¦Q ´q£Fü„Uù˜•¦&$ttAÂÁ—µÀAÖüô”ô(-°ú4 +õ<üp$¯¦/Ð8É ô…Q¸b%ßsDà·6™¨ùèU5RÝ †Qéé3ü›VƒKšBâñÞ¢Ðð#éSîQÃæOÐ6@WRï rÑxdˆÇ­rÏðüîtÈÃI›!ù=„^zÜdsû_¼‡°桤†O_â–ùå<§ƒßæ£ÓÉ8-7óNøA “¯ª³Pjðô7´9ø”§Ô)–<Ò+ƒI"=@g=ë¶të[¶aðôdSœO7Ãéĉ3÷ôiZÑ¿ÀöH¢ÊUK¹¢ÙY—–üéàšõltæI|ÀîLóÊ åqX/”uxiMËÔÒÌæuÈËGVO=éõb¨†|rýìëÍg?µJZf‡þfJ­Ì¾Yß2i¡Ë³=ÎåÙ¿§SÝÙ¿9`> ?)ÊïÂòÕ=³üÃùøt²Žæ§·°ü÷é¼Ów8Leþ˜÷”nÑ8Õ$ð‹g©Æ !S„¾¦oIgäïdVá'A˜?âôBº.} VÉ¿V¦,)ªWt;{ÆŸS5’<ÀJˆ$]"=rFBÚ™IÍÑù¯jáôßC¢Mú„¤)?TO*lÛvz¹ú•zùŠ›ÒÎø«Ï3€VNÆÍð¥ÿÙ¨WuƒúÉŒð0÷¢LV÷ë+âÉw¢¡%ålì¥vYûz´;OO×jdyW:å-îKk”MZoõ¡ Î&™Ú4ÉÈ^÷¶iÚµ›nÔ@êÎÏ’,Í=®” CžÊ„48ã98í­“sÓIsO†Câ Ã`‚vëxE2Eñ-a@Ë0dæå/¯Ý¤n~ +ò>wŠ:Pýw寿Iµq7 ·ô ÈG7(b&˜$¤x*@¦5`H¹õMB²•Qô܈åé-X’Hëˆ/ÙY5Tø`óXm=ö-Õ¹zëossû˜ýícvÝ1_Ñ(ц8÷ Ž4e&€|P7Ü·eèvýÐ#,˜ô7ؤB¤žX2hwõ/Áò8Wyºþ·4•éG‡¤óˆš<þ«oÎ,²-FT)NÊ,,Ü<²]3B—Gèòy¦øïKGhÞu|¾Û"6›Ïß2>ëRñªT¼MõáWeÓY•¡ûCPk†ÖtåÒkF¤ó€tO“GÁïvM6×î²æº]Ö\»Ë®QŽç5¨òó«ÙüŒË|Ñ2M«øtör|üäûö8õùÅâít|\ÞÞ]ÍðZˆ'›ÒÛ¸ `ÓK0šX,ÏC, Ö@ãZ/°´L¨QzüAÝV/Ú„Gqêô!¯™“€pÑx?”ײÉàä]¦ò.ÏïwUv^– ¶œ®{êèF­2¯‚æÖIÌD»‹¬†a IóŸbuùÏç9|;™ž­1»jãëF‹k%Š&—2Sèª Åð“5=Ô2#3쨂Á̲>*Ï®ƒUϾÊ!$7mDY{MaX†ç´ŠP¨a„lý5 ~òÓæ]e×ï*‡ïÍŠ’Ðü0˜ˆÙjé¢l“:¥ð F&ºEvj¡«oÜÐh«×?k@l@JžW¿ï[dvs!ŸÂ ­ný{M›Ölë¼× £)ª† W‹ÒÐ)ÓÄõÏÆ˜5úäAá£uÙÄÄ@¼£HoÓ&2C¿­³Ìjæsíýò‡ÑåïôQ|ߟ¿ÏãÓ¼ðýü÷ +þƒÇóÒšÿU¾ázÿitIÇúŽÓûýŽ8üøÍæ¿üú#@þSfdK PÄAŠ‹oû¯¯oh jHÿÕ:±taŸ>Ã}=ZŒþšvŽŸ~òë÷ŸüË;ÿóÿçÚþ/ü~ýÏÿó?æ÷k:¾ÿ}ÿû¿<„õyóï·í¯wûøB’ÔÀ£ý›°¯-ÌëÇë¸d¥F´ƒo¯þùÏ·à›]Íà³cä²EA8þõÿ˺Ê|±ìþzr ZÈé2üp:¹¸Hj̲þr49ÿ]Z…9^í±C ,øvEbé$Ç/«zÈÊYÿzE=¯1ôüýù ¡«š œaZÕM*h­‰ ë¡ ¯ͪ‚RA+}„΄,))X©)Ÿƒ¢cì­ª$]r{e%©Áï ®À¡©í8ݶµÊ²aÇ×+-ŸK+ˆìJò]¯°H釤l<ù~ðäj1Оüs\,–UÛïÙËËñüÍøô8™ÇÔê²»}ʰV„u‚$M•—Ü$KÜ¢Á­]}õB‡’ê—ÿö­- ÀV„“•éƒÖmÎ$©€ äĦ¿±¡ mÄôzE¿0à0ëì±xD@­¬­ÕÃ4i±Â^°Yê¡‚=Zš€FŸ>8õ‚!ˆMÉ«–Ã-4¨ò¨Œ[ÐWìÅá:š±1#A®ƒ¹ªÞ–çΖ€„–·ruÂ0âʺói··>ÆnïaOûX¼ª‚©Ð×é}–Þw€y^3z™6éE=åÜÝzÆePòhxÆ^dÆWhFd=°©‰õªKËHƒµ‰m[g*‚X`6t‰é†‰Öt;B`lšPQ8AÚÐÔ+¡)VQ²‚áPµPCzPRúZSR†$Ï–agô5@(¹B±LIØp˜¶CɘýPEÞeyc¤ŽD»´§`/&éÚ¥¤†cû¡ZÀ гVðסeVĬ8\A/‘^t8÷·Ã‰xX…ÉЙU€Â‰–©FÔÔ•˜˜5 Ç +28ºŠJŽÿJ&>”ÄÙ{¬éò˵‰Õï@˜’°P²„¡ôLÒ‹Š’ÒÝŠ2&†•Qîú;Sq…ZDÄ$É[¿DĆÃt ‹«iæÒk¬ïrI›¤e£C‡†& ©1 ÍÐÛ¤–Ô5€ X`…~5 †(˜™òúŠxÒÍŠx2†•Ñæú;o…JD¼˜x†v]!SÃp„±âªHƒ˜Ð*;Ä Cm‚éÐ.$]#ÔbÔ£óÖÌ5€iW`…v5 F(˜™üöŠtÒÉŠt2†•±âú;“n…FYV+* P“®†á•*Ÿ6¯JŠiì +[Ëviï75»„bUA]˜vVhWÃ`ˆ‚™i ¯¯7-w³"žŒE”ÑfÌÕw&Þ +•XŽd«µÄÐÑÛ¤ˆÆ¬I zÕ“f‹ÊÈßk‘aµÂXžËJ_ÁœüúZ]D£Ì‡Ž¶¨4Û{uúkCRø~Tª"ƒjM±<ÇÌ€¯?\C¥LWQ‹A<®(‚‚ÆÍzRE­¬MUÄb…‹A¬1Rþ^K@…X‡ÅXyØù½­¸s­baõ’!g¤Õw¦Õ2Uº +\E+ñ°Xå‘ý˜Õ¢ŠV¬=UÄb KžÊ˜`Íß+b ¨«‘S9cåqó‹ë}˜»WQ‹G Oñ kùÎÔZ¦ËÑí§ÏûÅg›ì”¿Ó8­­ü¨7Í5qZi jHÿÝ$Nƒ}ç0m%ñÿÿ§|×ÿ¥ûþ´ÿgÿü³f ýËݬ¾ëÜöŸ}0ôn‚¡]¤Yo¦É‘Ëå@ · ÕГ+Áš%pŸp <º°¡o²YGCÄxN‹cr‘ Ï¡gŒæ¤§×Ås–À=":éÉu1Þ6ªƒ®Æu–À=";8¸•ØB·Šî¬£á3°6ì³îøI® ý x›à>¸þéB{€pd«! oZGÁ› ¾.:´î‚ò°k"DÞ.F„®F‰–À=âD8ºÕH‚·Š­£âD_DêB7#AíÒ5$,iº]( ]LZ÷'A}ÝÕ€ x‹ÒêÝHëu±¦.tóhd“¯Æ›àdï6'xn5æÔ…nu‚!­ÆºEäi Õn¤ñºTºyP +Ò…VÂRX!{‹Àd.­†¦ºÐMƒS0 Õð@·P­¡Ù͚ɚÈUºyì*=·&z…Ð-âWøÜJ« Ý8†…CZ‰b!´k Õn…«® +Ú'ÄUiÛ•“©R¶{…¹*ºr6u¡›‡ºŠš]ùœ*-[õ w­¡ÚÍ4^« }"a•:Ý¥ñVѰJgîÒx«ˆXÑ£»4Þ**¶†j›éÐ]o0«ôç.‘·š-¹Kámg•âÜ¥ðVÁ³54ÛLi^âÛÄÕ*…¹Ká­bk•VÜ%òVñµJS^âÛÄØÖÐm#-¹Cä-Âo•†Ü¡ðv!¸J îPx»0\Q;Þ"·J¯Ôâq·ˆÒ•¸CÛ-"uEñíÐu‹h]Ñ…;DÝ"b·J§ôàQ·æ‰Ü¡é½¢évhÚ?¨W”ßI·ì­Ri#Å·CÒ-b~EéíÐt‹¸_Qm;4Ý"öW´ÝQ·ˆÿ­ÒéF¢^_I㈷œÝêDô¿ÍÎVnj\Àâ=~7v Þ÷eTKõÇuâËn¦Â˸¥Z0 ®­²K˜+s njå}€5ÝGЯ‘ui ò[õHÌŠ7xÜüÞEDtj+b™àfåæµ¾e«Vj;^sùæ”kp:½þÞœP-B$T.Gßœ‚Bf&ÚA¦ZõW橚½¥‰íþ)íÊÃyŽ3VžéªUÇxšßýΨ®›.í ÆoW*s¶ë[Ƹ2s×ã\®Êy Ng®¯¯š šÞE)=Œx|8IÐn9ÛØjpýò(cÒçÔ1ú‘® áé'“&Ò*»èŽn©¢K¢nÓ +9Œ–_sVÞ¸®cëP5[Awso5V­}çz>ªG=‡µó샭¢z'¥‹vc¨›©³‹_.n¹o›‚±Uõ"ƒ…ÖÀEÕ«¨¸/ét¦ú¬Ë烺щÃ@WâX¨Ñ{ ×òÑלiŸ)k?–«ýðq¼ñ°ÒÍzüñ¨ô/K­á¾ô­ƒ&£‡ èüÒ#þÈMøQèi=èJ¹@‚˜qñG¾w?—Ý D¬ÜõF¡»÷tþÌTË—Ãј¦>ŒÏÞÈzO~9uªôDÁ¥nXœ–nzcâ4…jL]õ1÷GúyTO|“)«äj@*ô‰‰p(ºE®ÝŠrã (_ÆÅ¡»öŠÀõm×_x-Þ5×®o{ÝEµÂSSð¬KÜšèÕ\T3TM]E}&>Oµ¬†j%.ÍN=oU‡îD¥+÷–” +×-»ùÁMx‡ÏÚÖ¾q«ÇoÄýtcÜ+—ú•ÍxVí´ÙjÕ. û ¬ìå YoÕ<}‡]oøƒz\Gõ.×(¿ŽþŠ®“¾¦µoôzú_‹û鯏WèÿŽê¤Ž8Õ¸¡hÖqÍ+ZÙ¯ºŒ—ZMF¡ð|¥™®Û²,®ÙžØ¤ú˜[¼ªæø ¯c.«î2X]¯î¨ ~¬x wMÚ]®Áø‚ó*¯"OQƒCYVIK hqØ´Ž–­Ù‰V!Œ!˯:XîÌÁr‡ñ€áê¸ê¡g×h—65åjª³ïÉ&rhÐÃÕ™nh‚üƒ~JCÅûê+Ô¿Å„FÏy€ù» ¸¢ÀÚï¥}AFž×úMU'Jïi9p¿ë1½)ªb"8Þ·{oèZc1.ƒŽ +HŠ4­yò(Ÿÿ“–8’³ÂÉÍgÓƒÌv ¨çè:#>Z}Wf¤Ð¬zýA ˆVååËß»Há¶RteΙ¿òLxš=ïk僂¾ 5-ƒÀ©.áØògYCànwÚZ…òc囓.KØË«ïþ–R›hæ½;šöhÿôâÅ2wg ý¾™:Ü"™¶)º÷Z¹úÁÒ>· B·Jª#F+#†|À)Ø* ³àã%NÑI›6Ð øU'X€`é ÖÒiÄ]ˆJ•71àOÀSw¤wX°,êäïÒ—¿þpôË÷_þ:øüd2?™ŽÍñ<”“¦.=~\>—““8\To÷Áº©š¨’Ê&À#Z 3$³Ú5ز ¨ÓPÇN;7ir!úop’-Ž~lÀ¾I“‰n (”Vµ–²H½ƒŸØdNé\n€À‚ƒ÷9î–ú£"ú[ÈÀßÀèQà-æpu€ÄÒŒ©„¢vÚãiŠ]Ý0q[ß6°@£Çù;€›(i>ý¼Á 7o!PyLB¹ÈÝ' , Må Ub¾Þàš +œ(BR9ýb t¦Û©ÃÕ~Þ™^© Z¹Ø$>85P}gmëâ.ó¡ãÑüäõµÕ¾?7JÒø3q\A,&ÉÝbBCëŒG}C¨„ŠÉðIpCeHMPÊef¤¬m ¾iuXC>¤¥I$°àêì´ìZß´ /H/¨™va’ÎÄÕÒg•¶/\IɈ(!H=FfuÞTÁ4DÉo…§ZÈ·HVWZ·¤Ù¥î†¼ª†R— ‚¨£{ÈC£¨fhÒ á +p§ ÑP# &cZ¢Ò”—öºS€mçDàú‚¨ùèõ³œ­Ös‚!ßnuÞºÅÌa¶íÊÜQJkïÙK­™?ÌRÜb)zysØÞ³¸†jˆ åÔ/4!4[ŸWóõN³”“8"¤Ý[R¢ÁòQ0kZWQGQ?Ê‘=âzÓ´`$mØ2´‹özà+2¦e,¿Ô¹:A +–þëá5n¨07f!­C‚Ì9(e+°¤c¼0FAÁZ¼M·(‰àF¿¤cQ°-™ŠòÍ’Åd4›’/6È©I"ÐYmc~Fû$†“ÉG `•Ì΀Ã2iUVß©& HséaÒ´á:ÈD$LíJÒæ/õ\kÅÕƒ ±Ë¦·ÀþÃûtZGfLZ‡Zá®!ùÙå.!Ê5~Mј2Ü'~€§<Ê‘I³B¿C¬ÞΈò›¡ìt¨Ÿ‘v ܌Ǡԅ„±Õx¬!mh°Ñ‡Ö{´”½õ\l(M3s4˜˜“ JEç£s‰MXø%­a“b™6Â~NFK2<üŠÏéÄé¬ÂÅ"õE +§Mè €jlÒ*Ò_…œ&)“Ji#“ÂßQÉhbZ!‚åî=L”%V°³£Åœ¬|×L½ <„`ôÑe!¶Ù­3Te:±,R†1¹žÂ( +q”(HÁ+< ”&Aá­””¾wˆ%e<¨Îi]0[ÊÌg–¤Ê̬ÌÞáš=ºÝ¢ƒ sš5µˆ7 ÛZ¼tU†½³Ê– ГÍhÚ´*,pä¾ÐNí´Îöz†‡£ù5>ÂãTCJ>ç7{BE·A6Z|!p…SñVè@É„ +Ý …+¡-€Èȼ@®Šä<ÏHD/†p{ DS.â”@sAÒûÒdë6‘” ‚ônƒ€+RtTƒ<]ŸÉ0…•Ñ[°LÈÕ:Mnÿ|"Ø %Ïaĉ$ ~¤]ÁgÈ@¨?®!Ï&án ¢d^Eú­ÀR¯€á<à…'<ô2þžý•4[:aà’âïtòÍòééÄÌPDy0t ŽF†"±ÍÄŽ¿ås_2$÷5m¶d‡yùjð½i0 H=€óNò4­¥ÎÂ:äji­6ÈòRO0…*ÙÉ÷´7—²N¹¤`¸ý²Á5z—eëÏ£—OGóƒÅèåÚL¢ž©C˜9ñß³ü³P6˜ î-GÉðâ[Èññ;IQÉwxÐEúžæ—3^øŒ-Oû—¹¿vׂð©ú{$ù h5%A®t ¿Õ}FJ]IO«üceŒ¿äžû/2Ê-åÞ]—/àz$Õ¨<—GZr(‚ †~Ä ?ÜJŽ ^Ko{´u¸}—“ z¼w9g³÷®½÷r9#§³JΪﲌ:‹¬^kV¨¬ÞU­×ugÉ»j²»ëoÍ*µÝ%yI"L{³†€Vh߬™s$o¸íÑÖ¬óï]žóÍÞ»vÎ9i²B]¿õx5)ýs×Û|kyUäL¦]³LxZÎÖnËêšx~` ¨zèU~•Yó*~òl7|«x×€ª‡î*«$(åð/¸và†O½ó}þ<þsñd>¿š\]®Ê:ŠGþ„fdô^¡íá\’˜½”(‹£6Î ~}r€L+®U&q•U9 "n]”åÛ;à¯k¾ñ—KZW¾z5°Û˜ùŸH†²,ŠË·#þvÀ_×|ã/—w£=Aà<éJ@´`Å6X)6ïÒþÀ« +/ÿ8;ÇT¥Ô›ƒƒ ÇEVÿòé'?^ào‘~{>½Jÿ}öò¿Ç'‹´ ñ çàéüêòõà‡Ñùè·ñ|ðl~ +Ú×-?è×ÃÑt:I"áâõä$7ý9QâË\,†ƒŸfWç§_®¶ýbzüy÷ ÕÜøH·±\ŽôÄ·ÓÑ‚HËãÙy¢íëNëÃ×£ùÉl4 žÏO&SnN8N©mç‰Ñâÿ½LŸÏ»sãPݯfå+üv¢5I¡í{Ò¥oRNTlL«‰͵ÄxSÜÒo|ï}»_þïóÙçø ÄíçO¦o//GÇß½øbðåiAl}ù$Iä7ciôåáìì¶Æ·“i2>—Âä|@MLö×¹Í_@qþòï“ËI›ˆt ’‹ÑÉï½<]NN:æ³ßÇ}Phüiúlž¬µ +’È0[ü4>™%ÑxŠ¿RÃLA·>Gc¾üzüjðÕàÓOŸW¸PCøj€/$=aðåóÑ|±v”‡³óÓ«Éb³ÞŒ +ÆÞ‹â7ÒFœL¿\Ž¿y3>vJu™‘Ä…bÏd¡}±ºêÿ©ÀåF?à§d‡%í³2¬®i1ÙÊü×à¢WHš.Ñ^úÔƒò÷E.ê‰x"Y›-X Šîõª'KA9wÆÖª¤÷ ;mG£› öt:>?½;Š}‰ø¶Ø{Õ˜ +Š•žùæÏñÉt†~DkXæ9„^w[ÞIO–g˜DiæžÏ^½º/¾Ày¹ÅçßO§Wh¿ÍæÃñŸP¡†¤ÜQÁdü¼ƒqp”H:øæÕ«$ýRóŸ'‹-¹÷çÏ®—Éh«¢è_O./¦£·ôõ‹÷ÎâeÓÓ4¾ïÏ©S3¢ÝÝWïG®½—¥}oÜ]:¦±R?3”ë챎°—„è¶ik1õbrv1-bŠž(djë÷<í»Å&RÍnÈÍ;y5³Ž&_æý´²VÐ*-uÝrPJ>k¨Úhc@­>iîPS RdƒÆ(È0}pcNCYÍ뽘°Wð?$ûTj7¸Õ{Q…îñ҃é-9ÐÇ£=žeñáýmbþ÷ÆÖÊÞG¹ë{+z7ŠÑã·¡îqíêÙ[?„ï™UfVf7™ÕÇ¡¡î:xнó&&yf¾i³$Ëš-dY…­È®›Ie)?qðùËñ›ñô߯“ß^/XP`báùÕÙ“ùâ‡Ñej'Жç$_qüçb~u:>]¬Ò\çmšÖ4;n£²bÇmâ²!—àŽXœ²Íün5Àä2EŒøÝùïåëQêÞl:›ó@i@óñ›Ùô͘u‹ô“É4À'~˜e)#E’}óçb|ž$(þdÙåÕüÕèdüäç.¿ü¢'ç¿¡Œïáþœ\ÊÛd-OÎßÐzøn<ëþr1ã/.f‹Àƒ°ƒUü4­íüÐð#êEÔ¿èÕ˜†ÇUÁè¥V6Ö|¶ø•–L ú½Ç4ì?¾¸}ƒÈ˦@Øç³ËÿàG×ùéëÉü?º]æ'~íöÁiºÆIm\¼Í„I{t Ù?ø—vù—_׿æ™—`Íüµ¦y8M£Mý‹^ƒAÉ ÇÄO:­¯[AzÍYLFÓÉ?óEõÆØ×A»lµß årŸ@³O ¹wËmïÓÝÀ£ð«sì=¹{çÈ’ø +ï]|­x@ep8›Ÿ'EåN„ÆÆMmW•ŒÃ¢ÄÁâ«ËöÂÞÓ³÷ô܇§çãáHq7êýÞÅ=LžCt 6Ú5xê„?€ËÐB²å¿ `CróÛ«þóíà‡Ñåï· MlIfÓõi›ßŽG‹×@úMÅ%Ô•pâûé6qùñ²±vÏÆölìQª"…E(ŽºgD×2¢§Ó«ñàÇñ®ñ{œëÚÝ„ÑCthsI¢RÔFr9ø¨êµ©½p¼uMe›;Kî½7 +¹Æ(s4ÔAGOWÕ´Xªê+º½Œr]¡L«•¿éÆc%”÷‰@ ã\P1/%“„kÇ~½Ð§›²Ä‡“@!z\7C«uh\&ÂÂQ@ pwÂú +ž7jï?J +Å`LTXƒ£i×bKË'çÓFÔÎÝ@{—dy4©ø´=wë9¸ G2ÇZqÊõ3ü°ô‰¾Òïu¾g…% øý©,v9ob ‹Ä4®’Í[“ä”}VPTU7ƒ\¿tüN/íök§÷Ú±6F| +*ÑÂq¬x¸Ç Ö#ïÓµë&ìöºù Ëfoüïã}ìæÃ×óY²–ÿmòÛë)e²î¢ùüÐ*n®x‹ éšÇ®w'­>ðN©Cœ|‡Ù¶_/Ò‚»|vÞMéÃøóù8ç® +ùûh>)ÝHÆäדÔ_¤e‚¶ÝGhç÷ìåÿ”–é_umÅÁmÔü²®¹—Xfij<_þr>9™Ž{/Ú´‚ô umU‹;{«ãGe6~§‘¤=ùó¬ó›ÌÆÊláÏLùÛæ²;qÍòÄu~ R5ß>ù¡Åê=*áN7èCpö +?¸Faº¿· +èZÙµüá¦% +¢l·@? íLŒ gJB1Ð;É¥éàÛÔ#Ï©ÿÿ}¾  û’ã>œqÊ´o3|öêrÑcçìEˆ°½ë"$ï¸ëN¨–]h¼Ž~/(îZPhôÔï®Ù~/–×ý\›÷”èu÷”À±ÀtÝM%tkÇCNÖÕK·Èìч_Dš:½ÓkÈÝÏ¡ƒG0ÿ&Þùôô ¯ç³‹Á‹×£ÓÙ»éûÙ'qÝâázŒà$quVúØÝ³é &×Õåøù‹£§Ó+²fÄL|=›ÿ³sÀûåôüúìÞ>·›½S€“éœÏs‹Gov1:Y>O;YΛñ|ÑÎÉåüdé˜üéhþ{×Wø’É¢<[58…”X7øæÏ‹QâËOǯfóñàïÕÙû â[ÿ_‰{ï¯Ù³ô÷«Ûá2[{9\ +báêã!ì4VaŽœ¨¨Z;L_õGw7HâÈ-&È5­¦\œ¶õpƒ:a½‡[Šï‚]ïßÛ9ä³+ÈwÓÙpÝŽ>÷œr8åP~Ëj¿›˜I…î]U_½;Šî^A½3öûŸ >ºš.þk›Ë.î$.MAÐkoÇÀ‹ù¾9?­®å»ý~¿ç£éx±Ó0ž¿Ü¼ßŸÿg}}î}øõŸ@¹îŸ~òüd•>ÿ÷דŘî±ÒT'±Tð®¿ãæóŸ¾{:øi|*/h¼j#&¹ “V£l¥Pšÿc<ŽÁOx<†eŠ+Oš~7Ï¥¥S¡¥«¦‡J;C‡/ÊHá÷£Ò>Fã15øVù¢˜VíáÀ´×¾¥°1‘"_Ì­ºíý6>_Œä‘¤Ë¥Ã`Cl*s:heñê·`óé}U‰NÙ`~5aý›jÍ໿™vðôoÖB6éiO×E[mñFO)Û-Þ.×>¬œÒ´±±ýÇtÊŒY'j}÷7fã«© ©µÁI÷1бà¦Q´ 8ÉÞHg»(컿µM%<žH§ï±³Ñy—¯¤•+$@A ½Té¿ gSã$B(8‹åeèÀDBo þèÓºm=æ”*“&€q:è&ôûéß\[pZ§Lî•Q1ÚŒ,Ÿ½h¥f"Vi £A:š2÷1¦¡ñ ¦D§•o(•>ò%:ºŠQáĤií`tp¤HÑÙ"C«©mLÌ•uóéìÀTLtk\+«È60â:é Ê`½¢PCÂp4°~“¦m,ÎGËG53J‡óUÂlÙUÞD‡&ƒƒ£<Ø_“FNg¡¤°¦Â=vÎÂtø2i@¸yŒ±Ááê‹x™dÚ‰w4ÓÎbšîK¬ñ5@?WöLH{ÑQ7Ò²‘æB*aÊ0igLÆÊ(•ªpEkñ˜WÛDì›uÁaª ,Ì@“r~µs6´r¡0ºžUŽ"K«ú¦uÙn18ƒtrÚ[ $U©>|B¦êŽ2Ð ñÛ´›ˆ 8‹hŒm- IûÒÝ·éC›ÈÊôrÿ|Bmq –»‡Ü>Í`Ú‚¸/­ÓˆTñÁ¦†÷„!¤¼'pKc(qY¿NcWCQy·µ´ŠµÆdr[*$FÑ¡©¼'ظi‚ ejmëö$‘ Å¤)Øn œõU¼Šù`>¹&Û-0ÓV¶l·Ä«#Ž.è׆jàªO\$­o0Sm˜¦/4²^”‹  ½­Ø‹J+ˆi[8n:ƒÆEb2{(¤,E^‘½h¦eÛÔ"<Ÿ‡Ii,o”"Cˆ)C*¬©Ž18-ZQ©#ìÏ´É­FÆŸ¤±%±xÍx2@Ë2ÎDZXÏwFEµÄÎ-nÌ„ÖÐÂNÂÅâ#Õ«ðEÖba%•©p ?•±¸ƒCÅM Me¢ª‰ø´ßk‘á‹°c `:Â.ñv0ɱª8 ŸUˆ7MÖÞµI”[Ä'<0ÏvRS#áÐaÜÕÞU$õ¸a4-N„O25ÒòTxNX¿œ²±ºž,àþ‰Îã&*|Ö(×¢§É¶*Ç7Iþášjc‹™„|-­%cHˆŠxñ°ÕJ¬¨ f¯ íŽ`Äm“>£tñ +«Ã³à2,³³Üé.”[³4IcÃÙó6±y®&m0s‡õ¦a!WÊ…o-q7CGÚ@Ná’5…k¶üËz"h)Ø™+Â;PF¹dm  N²3“W£îîÕò‡Œ7àþ³ TÜ7±pÔVœ6šŸNb壕;Šüca_I¥°(€3µ®þЗU +îÜòÆ­‘颕•þ[‚NüÇkC$Žš$‘#Až´™…šïHH’eÎ,KÈdM"{ÖÉô¤W¥Ù'û%pÇ–?0Ò@b••PXV’V{¨@Ý øÁ™laGù—KcQ© þ[lªh]Kw+ƒë/éîÁg+‹{´üAÔ‹M+XÚº6þ¶«W…Ö$ê>¦:ý·ì¾¿`õúÁwóÙÕEÙ‡y¡'^oùT'ÛV•†ßvÔ?oDÅוf™ÄGØùÛõ©¬Ö24!•DÚê¡R×Ò€ Ê£D0o²‹äZ+Ú¹5V4õ„&·…IÖK² +'Õ1†‹†q™º+iÇ +Zà¼&é¥0â\µÊH=Ѹ†CÙl:q‡ËMÒ ”òÁg­‘ÏVú-Ó'¶eá)Æ÷üiq¼‰{­xÜj_ܧŸüx‘wø»îŽ&—‹Žr)cMxèÓºÆÌ§kÎUAw‘ôeÙqHo¿Ýw¸v$ª¡_¼={9›ª®]-³óãÙœŸÿ>,‡£ù)þðzvqéó €dû·DH¤ÙééàÛћٜü–ŸãØ¿àQ'RuÆ|ýòlFz6>_¤®¦õôÙñ— ß2|­|æøõ‡£g§ãk~þjðùŸgÓóÔà`´XÌ'/Ó +¡Ã ©ñ“yñͽ¥j—Ô·éé||ž[qX††ÿ,Þ^ŒóÏŸÿ?ç—ÇoFó˯ªãuÛ7#ð°æÆðÃå5 !É3·Ë½¹ì~ÝyR½œœŸ¦a«M(•Húb¼øi²¹êæyƒ=Ÿ_×õÎ@§³“ßáš… ÉMïrQ¼;!ÔÍ„Øl®'£—ÓñF;c“Ù½÷ÉïÏþúfs¶mÆ"‡q&1º˜=ö÷^—è_/G“šÍæ+õCì›pÇÃêÏãÚÊ—¯þxë{8ùåtròxظñÚ'³[I÷µãþcrЧ¦oŸøÜòA°ïV…¡rÞß:¼×ùv¿ Æ÷º\xÿ<ˆÒIõ­üs³MûP†Õš0 .½m\o7×Û2.ÉŒ»v;¿Züÿ̽Wšó0®(ø~¾¯öPrÎ9çœ]αœ³Ë9õ=Ýw³ƒy™…ÌjfCRY–d9ôéû?Ôo[@‚ €Q:¯i+ix÷/ý£V yY;ÜÎÓy ÅþŸ¡W€íîÿˆ~ìæ×ñ (\èŒ÷íÎÈg„×DÏ1Z£Ÿ¨$ŸØv>ŸA^l2€[D÷âçÃz§¢t?ŽÀ]”n‡Åúívºˆ‹åÃzE#ÒToÛù™Åñôý躆"™oF=_'‡ñyöm½¿ÝaUS•ËÑ*¹IZ,ßF;YŠá¯Î·õCG÷¥|¸¬QCøØFu牗¬\‘½}&¼—?÷êűܶËö,±\¶W‰e·ýÏ“Ëcq|”\ögÉåu¼J.—ã?@.»ë£ärÎÏß—õî¶¥¯¥á°Éõ<Þ_Žãó|?ý'@»žæÿbœj8&gk +ƒ8‰N›Ãælôm½£ÜŒÛ.Q¶©ÄÆg*ÅåtÚÂM­Ì>qzØzÂDÀ"z±àZLÄ]msá¬q(¼Ñ—Eå6†bö»0ÿÇ|ûP'Øì@NkÕ$w“ù¬|>,ÖÛy~N6µñ5m­ÖÓÕ]S‡àL@ò¦ÆÓ9}ǺÐÒ-'RpõÑÌÚJ„A£Ñqa;„§¤¹žÿ/@C Î]Çû)ù‚VÖ@ù²\û~í:¦*’D´Ï€ >ì3̰áÖ¸aÍÔ}Tûl½6ßfÆW  ‡éx wË SOj ¦t~Î&Xm™Ïë0 ¢æp·ÇuúŠ8‘ÕM¯˜ööÊ`0 ™Ì hÚüçÃ1±ÀÚ¢h=€ÅmµÛôÔa½Tá´Ò¼,´N¤ÎóŽ0a€\«(IÇc·º±ly;ÞÏ¡„b‰7­¯±ÐžÑvnü€47°3xW¨«ÓíúT=wùß@Õ[.¢úêrƒ¾Bž—Ô׿x¿¾¬Àªar½à–J›PÙýlþß©õùr}z™Ñ4Âg“‰ÙíuJ¤4d<~BKï ã¾#RIP›Oû³Ûû €ÆÅ"€Û*qúðP žÙ“Þ jüœNX¾NÖÙŸÀ ˆH¶=ÇHÔðÑUh;€Ò÷‘\ :üÜk¨ƒ"ïùáPéÛ°8¢ùî¶,èÞ 0Àâ%èlâ^k¶~'˵ïW °ÕfØ$ +æ(T˜i{™)1lß@ýÇ5s1–¨`ƒ„¶D¦NÀDn8<Ìmw +áù2‡].8ÏD;±¹ˆ–„×i²ñÎ:hÊ •÷8¬&¯G¨%+蜟ë@«õÈ4Ól®ÒZ^GF7-‚ýÄ[Ÿ]€½õðs3ÕžÅÉÀ“`åξ'ÿüNœ×0“XtZ ˜=KÜ£šri(Üê1ýp`¦ûH·Ý' fÈñý@ÈÏæ—õrÏç:ç•Ø"ˆZ&j‰,) Ç\ºIßgØs?öíÙ´cùy›… €~U±Á¦”%7ÁoÇ!<®¼ÍÏ3°èáŽ<cnËP…¨B ÈËÛìHœÑˆ2B¼4‰3#шÌodX½Üfh_SÐ6üǃ‘^¦Çí”ë\ºo4Ý_DÙ4º½›y$0J0eÛñQ9ˆ†b@{Þ|=¢26»PW×>äeÔêŒÅ"å%° +®ð2d²3°X¼ÐÖ6¨´p•Ⱦþ¨Ñô|8>jµÛ5Ðܵ;3®˜}ˆLÆç‹Ø”²Õ“‡{«õ•9®G™Û‘½ŠÑ ­éžHhÌì ßÊZ쯦ÙöDÄÏ‹Ã^TÂv—Û„Z¥v¾Ùº€áÒ~gÞ ½ªÁâmöó嘑¨!Ðj*x˜s×ìKûжÖ)r/“ä—| áe5FÔ\ŒZ°Õü +nTRÆ)?§%§™›o7øï£‰íÚCÝãkv¾³Ðé(_Ó%ŸaÁר2GA|üF7Ä*4ݮŤ hÇl„@ËÃq*&qP‹‹Øô£³›¸ )"œÁû”`_$l%¨Ùâ¶ŸŠñ Þˆ0`)¾y° —Æû=ušÌï¢@ÍÓSÓÒ4L5Ó7~ Öø +”힦Ö*•{Úïð qàÏL‘O  í¶Þ‹1‚„;à§»ŠyC-×ÕœuBN9 ¢d{!„“>ÿ/¯ÿ{¾-ÏÏðf~æ’#£ pBš,2/îÇ#Dcð· +Ðí=ão¡`Š»·Ø¸p_ÄÓÈð×$`{:ÂÊŒÚÙèÓ‘ïõA@÷Îórwê³:ü¯ÌzÆ•)&§Gx¡”D·‹æ—QŒâ›Q0àÞ +8…åD + îgðj*R¶¥’Eø—l[?¯w0æŒëå´uÀ¶¤¯FX¢£µ-°¨-å~•ÐÚšé¨|@‡º¨ºI6-†ËŠkœäLÔÏããQRãËÈ3x",¹»U¶©/»:_2§MS_aô=>Ï¿4ú&Ü8ß@}€Ž]¾ÿ×j¾ÿ¾Œÿq¼ÿf2,”›ßã ü¯ÀSQt¦ïÆÙÀþy¸}.ñ}ØÃ‹Ó dˆ·„u‡Ö,D†o€ŒzuÆú}=@Óù÷­ãñ÷vüOݼ]Oñð©Ëmº‚ÝËîÈÙ@ƒÁ±í9o w‡~}ù¾í7°’‡I|’s +@OÏë#SŠ27®1FÏ¢æk^cL¿ÚE¶/ö‡)º·/F€_ls/¯Å˜™Ø˜ÄOâ3ñºõÝaYðx6x–¿¿ÑP\•`vHÝ›WÑ|ætY”ô::?'÷w§Käxmt•Ê$¶žƒ£ÝºÎñ /k|\uF`¨„IICJ½¦¾ºí&ûñzKNÀ£¡0‚Íòkê”WÈhçÊõÓwø@¹cO;,gÅôI|,%Àiã'¶6Æ,Î’ˆ¨3óÏqÕùQl ¯©LmQÈcšk¬ùÿu8o»«ØÐÐ6GæÌ…;<¯AÅôòÏBŸttr lY†ºÆ~[ZÜêó¶ ‡ùá;:ñbP]Œ‘ Bðq2¿aÉ\Ï‹A‰a*¯­‡ì ˆÃõbM)ýϱNõÃEˆdDP)mr—‡jwÜã´ûL—„':=&ãkaüÏùùµõEkmâEDéS3|·ÑIXáDëì~ +öZî—Àüq™Ï+öèÔU`;as”€«Jz\»øBæÌÔS + ŸFÄÜ EYØÂ­°ÎºÊHjGxÄÕôž4½ãQ„ôÝ“¼úhÊyãæq"… ñ8er-èh¶6þǼl‰5x=Ê ·p»½¬XšÜaò]BZôå›A mWàøà Äoǘa‚x"R†ÐÀJÜ^®¦)#B[óÿý?ÿ×ÿû‹Ëâ5`,Î'Ž['»ß|Ëyý9wÞ†=u,iŽ­É®GkñlÖãLÌ!~ôÔ.©~õVPí· 9»ªdŒEÎéÝÊ·Üc¹fШãë±é¢p52I—Üi¤CEGØWè©‹‘ómêN%mEÒêpÈ-–Kâ/±4XÿÀ¤‹ ÇKä’·™šˆ¿€ÉV¹kl™©"Ǽ_Cӄɤ^Þá*Ì:¡;‘RúÜÝô5ñ×9ºFCtw(\k\WúK~K%ŠVìo«n4‰…%7á…¦p{îfå·­ÇMMa¬Ìv¾~$°Iõ#¾‹i§O”·”&=[4ˆ^©܉E¿åŽm#Û¶o[]ã+w×Ê¢ÈH•˜Z §H ¬ná€@§/ñÁrpŸT§Dv–ÅbFÏŸ"Z3Ê÷x'ÚãÙ  ñþiôÓäÔYÑÄWŽ¡?UÚUúØa¤ÄÕT|~Ó…š9ùÊ?Ž7ðÓZŸ\V8j«ÅJl‰ð2HjþÙßÏÍ&Õc¯s’h@«XŽêBŸî‚U¬ÂVsú͉ÅCDn`i„®®ëo­'þô‰…9JŽÇjEÌ5iT™Ä0­¯¦×hY1-Fë6;d¨»ß‘ƒ—fÝd{¾QT™—Å­ƒ ͳ53ä¤u‰E-9C$pÇZ}Hîoá³!4É¡Uߌ9Ú¹Tä|^5¾b+ŒfÉã\Ÿ]`u}ìàp©É:“ô$©ðÉ… ¿>xÓ¤[kÌ’súÀŸ´e +¹&‡ˆ¿~•Eë¹ëížšœÙdžœýöƒ¿Õ¡L;™ÖQ.©nUï<¥Qµñ•«ÚMN,]b~>,órÐOõ§EŽB::ÌYÏŒ£\²yS"ûçRŸUOí´ËGKƒX1_ä<k~2KÅg»’¤<óŽm]Á Üu-»±L]ät ý˜—érpUPØØ- _ëpß_n»)ød¸¦²‰×«÷;~84ñg/‡E|}Y»è4þ–mZy6CË?÷©v`MWµÉŠú`®›#±.{@¦ÙÁSeA—¾g»hm”K˜×AM +°Pg\Ñzñ°Œ4ëÙq*é©´š€Þ’ìQ9& ‡[JåòµÁÄß¼É鿤"1 …²ãbZõ«.YTG«Û£ŽÙ®2ÎQ¨v¸«+)šïÔ`v0C¢“ †‘º[UŠNu+k Ñ©‹¨zÀÚª©ÔP‹­Ð@€ÞÏÁÒrN8OI€ 6¬‡ñºl«éCÒPŸ!+-°ÄÛ +}(è²£§Ñš!²¯×•›Ôù|Ƙ +$Zôf©Ûãíëň2¶ÍYLp¾~é…êö„×:G¤91»Ë™bÕ:4¢v¦HÚ´ŠAÜšŽ"ðSpº5h™O|a«AS¿…öKxSôüƒ2ŽÞD_]µ‚­ŸÑë†8ü-†ƒŠŒ)·Ó˜¨Ú†Ýc6 @ ÛÃ_®lõCÂÑ@„lªû!ê ?j»SF}B€£€¢xgàHñ1ÃnAÕáo~Fƒ`p©;͇}%‰AÖØE/ùáS40MM¼1ìNÈýÒ_¡ˆPC$¥Ð˜£¡g0$:¿’'ƒ3 g2ð— ½hàh ˆTlŠѸ诅:Mw aOhˆñD§ï4úD ÇJ%8—=$ðl\ ÆEó —s‰ÑÒ+ˆ­ ’"AzÔ°q‰®œ% ÐPd rFJ‘Ådžfw'N¿‹žr°’sC/@ß°¦6D3/j ‰åY2~ª‹eJŒà¬JŒ&…h‰àJ%7£¢Lƒ¨YÒ’ⓆhpÔ}ŽÑœD PP/«.U[BŸð) Æêv5M ÎÿìÄFèî£ÕÅ2Îü‘³DëÍü>±Z7MZ™²85.†Ær«(©áµ®‹ø-eŒ6TÐ뉥QÆ5«RangÂàYÅ`Wý´*ÄÓƒÊâÞÜ&eK!?9!f´ ®/¿%ìŶûfܲðƳ4 Ü:@°c™˜ã³X F.”¾ ÌÍï êõçÔŠçC#·»®›ƒ©Ú8åõhªèÃÍñ‰„Rw#GW¾#«`…QüåƒÎ—R´–žý­>x¶E˜u5`P˜ƒš›ml?Õ^]nˆÌȈ‡¡ÜyÙWc5ôÙð`ÿ4j¸­QØIÎtÅ ž‰ÂàN ú:y*¹¿lJïÎC÷¸§…\¬RŽ€í²³û!œ.p*?µ&b<ô7£È½ÐfôâÙĶ x¤bŒÖãFr½†³Ÿ³ä’§8쎖ՄM]ÛöÉåi±¹¢ªÄÄ1¯ññ×ZDØ>&4‰Ëºíè]Qt%ƒdŒ‰ÜY7z¼Œ=ËZÀœé y±ÂpeIõ"v6HèeXþÒ+ŽvÖùr6£†—¹Œ¿UDRÂÄuQ½$õ:ׂ޳ŒÇali*®Wœƒùú)aNÙÍ&k¦i€Mê€6&3ËÇWœ{§7³ ‘ +ßùͲ”luÄ™J\zŸÕƒý¤´ò•¹…µffÆ`¹tZÑj]ßKŽ\Ç+üôÇ…ËoÜF‡ë†r&dW-ÎÌýœhªON+Ú t?ŒÁKŸÅ)•ùýÛzÔZ~äêI&´vÀª‘z"w©@¯º‘™,#¾–Øû‰¥.êî/µ ß`\MälôÞ€²mÁ&å䤮Öñtß 4•€Ò+ÖéNd‘ÈçëVè2úæGJëqáêE]¥¨¥†rÕÌeÔy5wK˜ª3cÄ÷ó·aìwp¾\²Ô>N8ˆ‰ß è4žjþ$`·Ê-ÏÈ•ô3ã!P¶RÓ] ·\4‡`jµËør¹œDíW¬ Hö…ûÁáí ž†š:¼½`+¼‰3Ýñ4ñƶfÌ Õ&ГûN@ͤ 8)‹9œ¾)hasÏKðüB?]ÃÅHNÌÝ#ƒ5ðo@oq•£%_2ñÇŽ µ‘Úo¬qƒ6âï7Êšñp?^ à–ò pa¿þ´Ç^§db"=ëØ892.·`ÓÉ›’ƒq­ ­#‘ê ä% ñžÇyö·ÐÑ+ìj§ã?ñ¦•VË –]*7€7¼2 ¡aÀ·îNb±¨ØxHjŒØé¥MÊ[/›ez4\Ð>œ¥º_ |\$«àâéžKÀºi†7‘@è˜h€8ó{’Ýé¤Ëè¯Í%—µ4_FÜWK+])L»ùåmâYùÛqkcw¡œ•85½›h²u{«ÓÀþ”þ‹æ[±"`ù/œýblW +9¥•ÐÿØPFh¹ Ícq:`Ó,û6äTeŒ‘f¾½¦}¨ðt'΄:íÀr[b‘Sx:gaUߢžÉqI¯9‚êîsQãI+“:;c +‚y»Ò’ýMˆ× m§ˆïDz†Tµà9`è ÞUO~Läs‹M&ØsØ8LƒvÏŠf-ÿ†zÑÚ­~#t8WÅ’œNCÖØöo¶¡fÕ­m#æhÉ»ôÄ‹¦_°Mi†Žû%Ð5À5j@‚u@`¯$ 1\Õ‘@pS« ìq)df¥÷ï4®Â]v Ÿ9rU'¯ª,FÂy£¥F&­‚è3럠Ó-ÚFhh:À“—X@«PNÒhQ¹ò‰=ö—©xØïb,JR;r1ô.H͘C·eéý;«Ûh`«=~Lí<‹Mu×T¹Ä"šêÅb¼§—|ufúYxBTJô×9/š¢&Zs Ó0T×hMÏE÷Ý)HM/R–,ä~Ú(]VKçů?™˜¶ÂMŸmT$òýº=¥9T¬ÌÆÞè0RKAè'ƒÜ nk@im•£r3î uʰCÞï‹1‘ͶÐÒØ&æ,ZÑ™›@.®äPw²:÷zs‚+ÓWaY$"ŽTdl#;Ÿ‡Ó˜[ycp¥´ì™† +vôÀô˜&aPº2ò¨ÇhU³(lÃ8)¤öÍVžÐ›=`C¬6 <Œ, îc]ØEW*YlzÄ´-ô@%æ¶›ÀœSŠÆI ÏTŠD®ä÷ +·üÕíì+0- ç蛋=ÏÈr?CAçB›%¦ääŽn0&­¯¨·ÿFëue…Þ¤ÑÚwnNñŸdeÛõ +hº«¡{-À’·5èe]õ²q¸ßná!ŠÞb×i´D”µÝóêtÇ\úÚ¬µ{½–W¹%Äij˜¿Ç´2U?ƶ»ƒ‡-œæÕ|0â, z4e•>-©ûI£Ë}ÀOy¢UìŒhÃb¨\ƒ9B$v3õjü'qé½"æÏ+½D*ªÊE™¸‰ƒ¦Ò“ƒ:æ2И€«Kw?7#q‹c´º7«‚½„ïÈÎ*×DN£I¡“èÄ; Hž‘ñÊ!ƒ¡ƒ~ÐýЫ:’{××¥¾ŽÞMi²ãvä¢mËÀ~cïy;2#X/¤°!í†r×]ÞöPtK§K0ÜzkWè¤Kr%%Ä(ùEn܄Ⱥ–&˜€&qË(Ft¦w×f‡@ú¨io¢o6›Ö}¶±®Û­õt»ÛÞ'•kŒviâM~“[jÔ¿­`T‡yM#ˆær¬ÞÐqj©TÄr©a’IflR54ÑýdI«-,Û._„íŒX\2@›ÑšspÃeZGÉD`‡4Üuš|ÞMä¯F¾k± kHæQ hŒGË%j ü.]ľ1už°'tkó¨ ù\v¤j=¬J:z QŸœ BIe56–ò™1Tˆ:6Ô'hâݪȒÓÎü×?nþæä¦÷°NÚ«0wŒÖðÆ#W£ôû‡ïõBªÇN7†DÓ^ý‡äÔ¥uÆŠZíÚ½ÏVô÷Žo\ò«ÁÚWt“ÆŽgs´ìF ¬†%šë”‡ÁªškÀn°Þ†¤ ú'¾MÞÊ9€ÜÍm,­ÝÎÊî4À^‰¯"3°%nã­è!ºÐ°C­hQPî °Œmtf¨“Ó›lMÛMôÑ? u×vnÒȪ!}¹]o¤UÑ«PHÛGîvöŸ!ºce ömpQô9laaôŽ>ø³¥LÕåk7&`4sxF6Õþ( Ž9ËjQZ€¡gdŒÕå“÷%E29½C}²¨÷‚Õ§7€µT‡ +Trj¹¿¡:*¼ä¯Â»lAß2h ð¸ÐËÿ¢òØá‚ T‹ðq¼†aÉ›·œ‹ ±N(dO˜K¯?5Vžƒ±Ú¢(/Øý?vnY0•#SøJ‘«w*öþå)un«”*]8þë_ÿÂ0í(a:µ Ã49ÈÂg!Yúý Ál‘s%kgøµ] [ðAYdžt,2Oã=R­`g¤Ù?iÁµ}MަÙüêG_cv? ¿–ðÆõîÔ¿NÑר§b?‚ˆzÊ ðI„_¡ÈH«MQø¢ƒ­dÕ´rócŸ ?ðõ$X(u3üŠºêª‘ñ>­èi*>?Ÿà×üjLŽB' ü0¼Î˜m59£¯øh¼ o.çŽnDg?ø/ÀþÇàm‹,HÜ¢&{!¬³ÇÌÆr´~º‰ÓÙ½5ýäDáû…Ñ+ÊDþf ª!zÂM Í€>*ÇV¶DÖ^´%¿>˨i­þë_€uΗ+·^ºêÆN×–ÄŒ1ójÒ“s^‡ÿ¡‰†SØXS¨ÛtñOg@¹ ÒZ?D?Â×Áï90Tu~~߬ɯ2œ¢Ò<ÉVé»ÓÄ*µ°ÇÞû1YÓ±N·­ÎªXÒ,w iLËÓ@Ÿm‚IÕ¡­KÇz®Qlã›"§Î:Æà(,<@$˜©6' -—7°gK.W~ +c,3>°Ò +VhƺõÉBêÇeWܦÿú—y“ËcúÐõì&¨´ÏùˆH˜å ^µVnÈ—¹;Ù]¤bÈWeÎ/ô÷î×Úàô§dD¦„˜áÍwä@s?ýécFoåmÃÈ ;qlëTNXÒÀÛ‡ EVÉÜ…Œ@dÅ’¶E:j=aŒå„Ø¡={"V,†¸KÌè¿3ÿ “k­FLnžî0Ù,ó‡a‰–0ï9ŽaáÜöTFL˜V×—aÚŸö Óù¼:Äìøì‚&ÄêÕôá7 Ë¿\-ãV¦¥>2B&ÇT˜LÕ÷arCâSØôLé«X,ÁCBLí³¤1Mxû‹i“µ¦ËûM˜¾"‹a†æ ‰{É?Ì41j1órÄ,»r³^ÜsÌ.¿*0û­áœª@säÌmž1O¤hǼ)Gó5°æŸNá4aAUË…B¹n—XdoÕc1Ÿ.ÅåC,©:+°TùÁ2ÊcË–Žr,o¼E±ÂX9Ä~Âz-VV¹²Xe]cµlÑ5,íÖ¼ýɰöÁĺà ôqa½và *Û6ª; ؤY­a³öQ-f¡¶:Œ¯ØFeÉ`;_ç„J¦4vš¶NØÕ`ËȰìø&“cE™*&WÉ4«vC¦‡-2ãE9’YŠc¿Ìn-î™óÏ—“y~ԙ߷ïÉBêq@9wN²øªZ“¥y‡,ÛÏne…^¦$+ÍŠYu[ÙË×f]Ö±@½èV&Ö°¡l²¨þ¬M¶n;ù±/;–=Yˆæªn¸ä²ÚY!W9Â+¹v=iÉ5`EZíÜ©²ëåžÝø"Œü y¤úו'~r%y¦fIÉ ­MP^îUòú_Ð(ïȵjyß{”ÉÇåñY>_Övò?[þ ‘ï«ñ•ü¢Š.²Rx¡PâK…~^),þüŸÂ‰5v +ooxR„òGLOXÕŠŒ=jTõ-§¢j¸-“/­è™›eÅØ'ÿU,Šù•b3ºÜÇkÚ¤Äü7”¢Tµ +JýM Ô¼Ÿñ^éºFõÊÀ*¤ŒY5ezUY)‹ù VYs›"ÊŽìÚV¶›“rö·v)ÿ†£²ò¸˜îTØlìP©7³ŠÊ¤ÚU·Ì¯ò•­¿ªÈ: +•UÚÕÌ«ŠíÍ^UW‚ªn%=Q-k‡j9wþªö‰–Iu3j[jÕ¥eTçæ¶ÚÑì›ÔþŠ¿§Žåu¶T›©Ë½PXÝZkŽêÁmUT/\½zWÈÕ×M$ ¥¡:Ä4¦…·­qy]>MðÏsÕ$Sþ¶¦d¤¦¾¯©4½Þxª™åŽÍ6fqi®±¼L«ŽÍ§Zs\_Öº …6<¸˜´éSâ¢-›63m;oiG,¯]‡êö´õ8uÊÄI¯3©~å:W?qÒ…3Ž.cWÌuÕa¬ëæÝd;îé6ëþ¯îzþêµÚe_oó†zF6Ñ'F–…þÇØê[ÅöY?–]”ú¿¢Ç¤¿Êªð,Ò Êc[*ûc¿†ä%µ6”¦¹¡Ó/Û Ó‘=iØM6-£l_ßÊÞèö£ÆèÏ©eÌocÓÙ³G½VѸ1UWÆÛ²k1éc¿E“K5Ùš"«#DcÊ75-S³P˜ÆùFÆ´Íí·fYÎ0«Õ‰Ù3“;Íñ[f`.ù®vs·‘˜;:ͧò`bÑh¢‹½!ßXÂÎqÊ’»–å–æ2ѲL*v§e[•Y 4;­Ö­Ù¬iWÖìØR´6n›ub¬ûL¹iSžÖQ›-¨ÖÛB‡äÖ–:¶¶Î”¶Íæ5·íT«íÚDmow9´#{Ü9jØËî°>½Šˆý¯°ô8d­’›¯q½#p«¹Ž^æhëWǼ£¸8.vÅÅ©ßè®NoË-s¦ãq¥³a.iSãÒâ<tn—N »<ÖQÆ•Š™k®zµ6tM¶š­ëäí¨ÜºžÃåöjg(.=È·ÝÍmãž:÷e7›b©å d2GO>sxº!ÿgüy奈Ík›çËÞ˜ªyôV’«€w4W€•ï |ºu§âó¥d_á´¯3_}ëz:ÔýŠüöàwÄÓ)"¡¾øë‰~Á?kåÔþëØÒ +X4rg ÿ[Ê«i60öô´Ó¢; +Ãx0¤›iƒ?ãÕ48l*òÁcÎiÒùs(˜˜ôC?y]64ì! „Žë£*l4Æ7áÐϹ. åð8eH„ÏDZ7b.¥Í‘¨Û®ŽÔ4J,2ÛmŽQlÐßDíãßu49ë,£­ekýSWÀÂÜüż•Û.–?ZαA,-ÏSh«ÇM?:{¼ºÚá'›#PñÙ©êzà·‡ë×XbáMo`0Ç8±°tBÔS›>Xu­0­=ÄŒf5 ?VÎ&Tý®3¬ÖàÙhñ›¯†Šíf´ms°£AøX\[q\l—"è]bã—F!{Ìc÷Óu×E (ÈÃB?µd†s¤q2y5r‘¼÷òd-SêÐu4“ç^×’è¦:õT0œZuQ÷ž@cWTôq£® +\BƇle¯í®Uár>û/u€Åµ˜5| tß.žÔµi€z>SYê ÷Ü·\¸ç¦¥1:>7‰É|ñ¤ž“ÿ|MoÁëkïÜ/ö*üXÓîÓ—˜x±?P¡à ¦±ºÖù´’kÓœ/Vå™kÙÚsÈl>*â‹ÚP4 +`u®4cu'ÉÕ¡íé¶%ÿXa导qÜø†kIÅò¬.¹bÖ°v–Ôâ§FcýBù¢â4PYsÃ:/ÖtÆV¤°­ªVÀ‘“${^a"ç¹w  bíýÔj:öß­U °:w U°Ä¬eµšƒÕéÜ 4VC㈇çþj_À»Ü)…•ë <ª +a…ž_…]ãïñ7€õ/òռʵ׆NŠ]«Þ¿õ…h¬pnØ ¥ w#%~¬ŽNÇ’òZ~x±ÊRK·¢º³•ø°Â@€T¿Ÿ®K®Üì‹q!¬cKÚ0jòcM[¢ê¹ÆÝAXQ0-›ÈW¹!L`í5"‡A‚ÂÉÞ&ÅÂÚ X +n£bÕq°4Yf~pUÇF@ì>rÙ¸ðÛ `uÉÝ›Yj „5a)êú^„qg¸Ù“/òwþ©òb­ùÕvA¬ùyÍnáÊ6ǯÑRje|ýÈò™ùÏoW«áÅÚTï—‚Xk«Êh‚°B[ìn¸¿iK3 ðc-Ø•T$äÇzÌÉø°B 7‡iÙU€È¿%K+œOðc-†’ÃA¥ßçÅÚ/m²+Úoî‡û×qÎRX{Kÿ²5òcýù;îJ^ƒ¢Aˆ‡Yã^ÈgeM `í4,Éõ.Ç‹Õóc”a‘¾Ê4€Øwâ.žÛÐ=$°NìZÎâÑv cÂjS‡4öX –‘Î…X 4Vˆ"pÿNäbç û*&…e‡ù¨Žk6`£‡.v·2 Õàà|Ú©XwM¡§+Kf¤¼ÑOï7 ˆ*×Á<¨ôq²cs7ç©ËcÖ‰§—ç~yºö+Y›¯.!ËY_Oð©Ç¦«Ž„Ÿ®Æ5M´ûQ›ª;|ZÐïÃ6á§“ÒÂO?åÍ%/ɦ“ŒÀ람*h\ð§ õÉËy·¡_“jëÂ*óÝ­1ÉÕö| p‰—Ðo΂O[ʉ~ÚKø‚ÑxŒ”·Bðéßµ|Ì>Ý4m± +ýôžh»M*4zô©âw +>ÍÙ¡¶Ñ”Óý¤Vz]…©²=àÓd´8™ >ÍÙÂ2«Ñ¢˜M¡õ ¶Õ8Ѥ™å¤ +tºQ¿¨ ®{Ó‘µzB83ÆPV±iH¹è@-9§R‰þ@¶lqÌ(¾nm¼YN·˜}ÞÔ€ƒ‹›:laøÝ8DDu(:û·Xþáá¢û¸ÑÏ3B5&8B87Ô ÑÁi$ç°&{<‡rj„:’Óø õÚ†½¤Ïáq)axH¤—4«.ö—…8í!Û“ôòŸâ/𹨛4Î_éÞéyêó’¨<]’¡ß¦¾-ÖõæÄIˆ&@/¶ÒÞK¡A’-…ì‚RÉ4ÑIö²g& ©N³h¨Â¥?ùèÎ’È=2$ ø‚|Ö=?ù:FLPˆ .OäÀã\GöüàXÛŸ=ܬ‘;WG¼=Iè9ãbmkŒqÍË&Áw25 Ð4O ‰WØ_›A_j=2Ù}¤UÞµSe8ZÇ +uu‚8#x‘6á{uÐIöa24òñC³J…Æ +‘žyL¤»_€ã”Ô(¾úàî9–µo¢*·Vüó«gqÜñ“šdžoJ!ј³ +ÿ€Y¥=Ø÷ FH‰Ä{)U¨>1:†æšæí[(=¹ 3b™_æ;íì~ZFaQ?-³ô#íLªÚx Zp§’ MÒŽó{ܦ áñÄ$§!Y2Ï+U¼R`–fKmzô^,Ò§k8'¼{–ªD¤èz OŠ9}øî)a½ +qmã¡EÀšÆ½RTÛxbÓå Š`è7 Õö:—§$hì æÙŽQ‡Å´Ž¸‘óÌ0™ÚÞûDž?I4¶t{²cGŽÏfä>ßY·×ÐåEÍ™}~z”á3…t]Þ=Ûk¯°G2¡}ó/ÏkXö¹åkŸÏ™ÓøÉîÝlfà‰K¦2ØŸ'PG¦’j›ÐZ'—@¡ µS?ô7ðkŒŽxà_7§*t·9=!ú¾3䤞pµÎ×Èò@0zBXÒz=k™>ïß'Lwül“¿DG Ùú—‰‰á +Ÿ²÷“O`pÓlx%‰ÀBÉŠë"øº‘Ü-ù‹¢€#:áÚë_•â;µTQ¥Ed¿€ðÕ¨NxÕž¥@<ö|pÕ|†wð/ [Ÿ`­ÄÕšì_Ò´Œ`GÛñZF¦;X+»T.%½Äè%}± šE¸èõäbgÑ‹Zìè »Â»1³Wz†½ØyóǾ(À¼2‰Î1§CŽëÈåvGÌ‘Ëu¦ìrlý^Àt~ìȃc,(’žö¨ä`¤CQª#„6£¸ÉÝØ;õ ŽÀ 's7eÒç‹³Ë +8‰=Mȯ·ËÁsâÎ[N"H ÞAŽPðí@¹¤14Cˆ²\G–š¹qÕlÀ ÂþGRBKд!¥ó\5ûòzê‘R¼GRöpíæ°ÓZ{jkÌs´äׯ¢ÜcvÏÓ»!½ß¼àÆ>湡Ðð#â@3'¾Ò'…±ÍçºCž°ã€Þ]Š8Ê⤡Pú@Ïo„´_€ë ñ¹m•}ʨÆUƒ†­ŒÆQDìGŽ'â(Ì•:¿[¶Ífzþ¤P@³€A£:IÔd(¦¾{[ãJ·ËF{'Ý.î1 éÆïL‰ÚDNïJ·-Ý(÷ýž í±t£ýΠ ´×¥½<ÓÍä˜9>éö¼€ž—n÷^ÐûÒ BùÀ).$rœdˆi¨S 3C³ay˜»Ró fg3O ù‡¡Ê‰ëFÑWþöîQ.µß,Ô'a‘$Qc‹ƒ_ºò­jÂyÿœÐКØSžx Ý*Ø«º‰,n¶ÁþŠÚfŽ0%(l’¦ø BÁ}6ÐûQŠ€ÙÍ=È ˆ}†/Ñ-Íw }ÂÉoŽ`„z¤r°÷Gð³ñíŸÁªcYõò¾QØnIu~1½‚ûcë)íÿçB{_ûïø6ǧ·58sÏ{Àx¶5èퟅÚߨÖ íŸ +mâ +’º?Šoޏ°éÞÞY›ã{䌣?$Ô Š"Þ(/r÷d…fÑ¡‚úÁð,2-Lj¤áµÛï8¹¹gÚ»ëœÑ1žEþ º[„h’4ar6!“ L¨IÒŠ9†’6™êà+{œ> ²5ôpqwª¸Éx·MÅMfi¶§„ÊkÏ#…Cã„ü o6iÔ”°È&—†öh‚g?´kHj?€fWøó…8SÑÜÏéŽp6‡&iž[šÀ²ïˆFúâl‹gHê–D¶¸[dä&/bzƒ 9‹{^Ø”·wYbÆ}e¯lLbƨ}3ø’|¹|_øE3ï§ó1·µû\¾/NÒÒËé|â¹|¸„þ@:Ÿ V”Ë÷%˜ºød:Ÿx.ß3uñt>ñ\>¶:øF:Ÿx.ß+uñt>ñ\¾/‘ÔŧÒùÄsù¾PêâÒùÄÛ}Yßo§óÝ­`V.mx¼™Î'žË‡ëiÓùXÐ"™neuŠO‰¼NFâÑH迃8ñ8V\'-i+ŵ¤_¼Mpc'‚dño‚­<7}Ì“Â7 +äeRùu,¦åd¯Rû¾FJRÚüoÞ|äoᜊAò’6BÜ;ø(‰Oò9Ž.žu#ðæçûÄ›»%îèë_òÍSù{’ÄN’_ˆz.ëúT| ŸÆbò¼»YÈ׌_lö¶{«c”‹޲֥ݱ.Ÿu%â &þ]O3žv'tìÃ1£¥Ý ±â§LÑ™ 1aÙ¯¬”$'â‹•À, ;ÀËzâ3±&bJ“_ãÔS–1¾<…Œã‰]8Tó©¤×/”…W”˜ùØèÅw0Nëi÷¾¶G¾ÆçÈñ¨€w¼º¯z¥Õ1Ád4¦ÅÍG{¨ŽIÎ)¼=Œ¼"§pò0ÿFÎòq çÈ 'ራÙ<‘÷êàJ.Ô­_Ψð>޼—–0K³½ž¼sø%5§Ðs~”“#Æœxíc9«gúÜD01æhÿ ¢±Ý²ïíaâªôaÒÒí5¢±ýŶX»cdQe8áü_< eÒÔÜ;Wñ½F­ùª€¯S°—Éö €»HÈ`<ºÇÌõuý‡´¬½—fih‘°ßŠÿò€Év½_ÿ%êˆéqvÞ÷‹eëqbE("¦Ï€!‰ßÏBÎ4 Ów¹K!Ð$®¨ÎHRøLªw¼7L¿@î}ï   y"îïÍ×]êâûÞ˜ÇñÞp”[鹂ާ¼7üg9 BÒ²ƒ`¶ XxZZˆ ,Rba+ÒyZ‘‰U—¢HÛà ½\G|‰gHóŸ‰@s㫨?ãƒóiEKɇ{1jžµßÀL6a_ÔilwÁ_¼©‹RüžÐå †E)~cESüɬ•ãɰ“¼èýZŒeÌÔ:EÃË÷÷«Âß$î|ähƒž>“™‡Ð|"lO<3Oä÷“™y¼a×åݧ3óÞÉñx"3O4ös™yÈÝýæR”™G¬<B|#3jE¾¤þtfÞ÷.U<9ïÓ™yŒÉÇ›Ùë™yìC/ !¯eæÝYkBçB0§î‰ÿpËûXè%ŽÔ:¥„^6’B/JËÆþ®jG1Ò.2¿¤5’,À^í·×#')O@¦}:)Ï#úDRÿÜ|<)ï _'›hâ&þ3¶çIyLž—÷oIÊãs?ü’òüi-¸Ž˜ÆÈ +_Ìû¡Å²¯V‚a±Rn¿çèiqÓ»Ij唿„”àx†Ð„ïç{V³¹»BùÙ“‰/Fª|GâØÍÃ@°óí 4³®¹)~=Á |¸{åRåÙ.è• Kéøó€J€†J«ô¶9&ä³[2åUD©z¨œŒ˜¯j¸¤êaw•[Ot“çH4ãªçâ1Ó4™ó°ìBíHîOÊ-»Ó„ŠÆ—ý†Ì("QêW8ÎSñ•™LÆN»óOKE¦ÓšÕ¹Ò)ØáK(ÙÏÑi‹¥ÝÍÌ‚X-©zL4ÙOYZÇBXG"XÓF/+7#̧¿0ÝvÜ´;G{U Š6rRÑd±´;«‰ƒõ‹]§Ð¿JösÉå'×­'”v÷+–ý¶{ìw¨×±ª +óÕLëüAÂJ[kòç7-HaÅÞî +a…ÊíÝÔ‚¥K }"ØÝ'±Ÿ¯á~`5uô +’@:´e¼±™\<*êeF…R·-wó9Kˆïe+·ú=1Ö)SYuøLr‘„`X®ƒE¸¦×IBŸ˜gk"Ýzû(x„0q?Y^¯äÊÏ 0|QbåõžsÛý&$Gb>HÎÄo¸|"vðQe=ñØAé\õ ²žàïÎo +­H¡„ê +’ ÿ¨Æ +÷6¸7Šê=±nÒsázL‚¡µR«ò=p¿’Ø÷¢ÏæÙÄ>>+tÛ}0±Oê}6o&öñyïÖÍû‰}|Y}_¯&b +'öñ¹ñüßIìc†X¼ôIáÇûø@}=¸Ìä…ľW7é'ûøÎyèÝóc‰}|Y},¿Àgûø²ú¤F =‘ØÇç¥'MÜ&öñÍ0î þhbŸÊÊRýLb_Vß—ÀÕúo$öÝ÷i%Q ^MìãS[Ñ>›ØÇ7‡|¡Vo&öqA=®ÀüRbŸ ÖùÙľ'ˆöNbÔÝ û‡û^#ÚÓ‰}â™^KìÈúþtbˆæÃ‰}|‡-ÜÈû$öñ +މû‰Ä¾G+Jì“°ß|"± UýS‰}Ê>“ØÇ—ÕÇ2’ùˆh¤mDÑþ²ÏÝ9%\Ó쾆'ÇŒ’œ}uz°ìYôw„TŽ7ªøÝõ銎‰>]ÅODåFª«^ý©h:±.a’èCmC"°R#¾Ò±…ºÅé“T¡@F‰t‹}¶õRŸÑ@·žªS-Ö'þØ aa#B*‘:Õòmkl“)lÍ]8&“]á=>¨/îÊ£¶5ÑúoÿûbÜÑ%Q_¥øŸ °aÕÿ{upÔµo_B eÒrú$Å\<ˆ‡¦ëÿ½7_éÎñKJ™Q§–¤â6oÿ#5ñúoÿû³ðÔÿ“vütÌâŽ.{¸aŸÈ'r<ò :æiuœ/œGòà‚Z©\*|LËö=Œp|Ä¥0¡šØâÎ{I9}R"¨!šGùŽÂ‘!’“!‘àÆ'‚Ô …†–Vo  –«¹)Mð*XÁQñÝj%t`”.ï^Ì/c‡ZÖzƒ.9Ô +€zŸ&9Ô +@“D.Iág1ß?IµEn='Y@" I5pù 0ÇjŸXŠÊ]šýoóãL{MR¶¯`å n¶omŸí[ÛðzCí#uŸqNý•"ؘ›™ 5ë|Ô䟦±)µ­»?†I÷!Ûâ»PÔöü²ùLb u³óóêÅ=¨ÂM’Ö)%…<( Ÿ6K—§Š{ áÁZtoë8ÑðÑ'}âл¾q(äb¤wϧŠq²g¦P’w7 _Іì›gëô=U QSDOë|îV­~„÷¡¼ÛŽà­Z/h6“ËSÅ04¿˜wËX¨ThÇ—„tìÇy· OÒÓ±Åòn wœŒ‚›!©ÂÜ»L°žØXã1s®•ÏsÐ;˜ëkõàa¤wOé2J5Lµ{©™M’%ðy„>gâ+ð'\ebeeæ4y³Sfz¶Ø¥é|ñߎ@fžV8ð|ù¬ ÍI ´è„]r…»ªí åö±ÂÑÈRG»àp-iy·!ˆU˜–B¥é´4Ö/*¡Œ&rÙic`eçÈ]Ôn]aÑÎIºÔj¿[>¬ $2·+%pÌMDdR8( `uÉ•ŽŸÄˆá¹å&ç E°¦.a¬éŠ¼Ë‡õ ÕÂódX©ž\¬U± +‹ù¦0Öd²‘bŽÄ +ØÀ@}"²Boº ™Ííìq‹`»/f¾§e¤óE%€Ôû×$½q‚Qw\u”:ì!]Cìý4.â_¦v>‰Ñ™€®N-:Nbj6 š¶k<ÈM®zìLN‹ºÜìbhánÅ¥äW=N®º|}ª0 ò?*L#Õï”Üœ>R³au«öLŒ›X ÷"Í7ÒãD‚âtúú/i\Å98{v„´»æ>]‚R Ow1`wëF2៊hĺ%ì_~®OPt +‡=º‹Ã刮d/¤cŸ„'y*ƼfiàY ×{?òÜ’Ÿº‰²cÄ¸ÂæõŒ(Q·´äc¢Aò+v¿è É»{ï^J»ã?ÿf†(JJI|Í#ÍŽRE)‰ïÞ®ËwßÝ—`ÞÚ#«æþ¾;IÀŸÆEá9¬§ž*ñ "lR³¤Ç©;aóê:žû'´ ñC¯ÇEýX}ãž<öñ}¡:…‚Çé."aã9?¯¤ì`\má3ÆçÚîëx¼Q©N<›êë©L/ïSW10úÄÍ¿™¥Å|ÎUuVŸäÑ7cý>™—¸QHÈ-ýbÞÑ%’—ø¨ôƒ9däÏÒS…$s§ ôo™' =*$¤¾KùÆÙeÞ$ÚÃl"éÃdŸ€¾K´‡%…ž#ZÁÑ€v—Å̧6’D{1%Qj>â£ü›Ç‰j’òÅBâ%¤$JÍGäñC?“’(5‘†})%Qj>"îî~9%‘Å/"Vè]Ìís)‰RóÑ^OI¤I*.A¾Ø™^Ϧ$JÍG¤-é—Rút—È:÷Ä{t?®÷‹~I/R÷N±BæhþÅ +ïÝÿ–b…_ŠÔ}¦X!‘±"®¶¼_¬ðë¿”<úâNj޻íþ-Å +yC?_¬ðKR}Ïwвܰ[.ÁnTz”±,\íP<1扂‡â.‰ÇÑv J»Õê킇ŒÁ}âV+¡‚‡OÆ@½ZðP¼Ú!Ÿò¥‚‡â.$ƒýù‚‡ü,(~«Õ %0ô' +Ї›ÐŽ®7 >L(ûX´Ú!¹ß¼]ðP|p\/ÇËY=¹«vÈòu¾SðP|H¼Á°¯<äM޽¾]:m$gï’þ´· Šß[FŸ°¿YðPtç‹ãÛÚ +Š{“¿žºQðPü<†v?¼YðP<™÷‹›$ûjÁC%”Qíi­A©ñrÁCÎz´°«2•Û²c,TÁÃǹ¸)x(^ífè7 Їx3”Û÷ +Òid|I;SžK¹¸+x(NC\¹ý@ÁC‘5wÙØ%}?.x(…R Þ-x(½Ná[)(¼ËèéT’»‚‡")C{çÏ<Wóáh>RðPh[oòH¾–F&A×§$­ÇGÅÏ®9a ¯£Ú!Í[ï]ÐÌj‡”„~u=’ţǸÛÚËѨ¸¨— òÌ £Ú¡ Ñž-xø†¯“M´ç¯„lÏ7 +ÒBŒ¯Úáë!Šœ‚‡¢lÁ,~ò^ÁCq‘0qß/x(ž¤KnÒoÿqžššùBÑŠj‰?Y½šßø¶öaÖìOC÷IyŽì]?Xë'¬VØ5i—rñ›Íjo+ù¯ãЛûH)€²MCz­‰™ôƒf[žšú€]±¤bù˜%µ˜æ,i—ªz>¼šóÅÓÊ^ä×äâœü–©ÌϺ>h6¶Lö‚WF&àý™Ï—ÞVàóÊquGœ°R^ýÝÂÐVŽÐì¦ +dÂr›·‘U©‹F +9>z!r€_Uhnì +Lp¸(ÁR3VÏËòf·RìÏæ”ÊæXÞäÛ6ƒ¹­92]»ŽŽWÜ£ I,šª×•Å|†ûʶBä,#0¸rœ‘¿G{iƒ"Ž!—2cÝÔ¼JŒÆûéjÛõŸÉ"æk 1_fþ”W¾)'[ûPnJo›í^4ãÂ&PóDÂÅë‹j¬ú&Vv;£qEwÄÐÑ|«5Ô'›í üÆ\Þš`*±7ÿCÎΙVóUã†W\.›&5ùɪA>g@÷|uëP.2=Ù#ø4àÂF®ÛÚïü7‘o¦Ì©¤­èp3} ¼¥4™lÖjP¯vÉéæäµ˜Cn-ê*ì]ߪ‹[ýñõØl‚zƃ±"hÈgq#ýÌë6Âäƒ,…0ÏDhTdW$m~´@x6ÖtA6¦~ÓÓáQDz`šRÏŒ @é£Ï3j“óÇ3vÖŒ«`ƒ_m8ðÉ@I¯èñ&“£ªï#Ós«°©CÌU1á­¦®8T±Àà³³uš)¡¯Üi÷×JÌW'¥7k;xZ7 §6­Ë7#±ÖM‹Vá±Ø¶5eÒàÕ±4L¿ÀHCœíáqçm"üC¤çyxœXué - V³üÐ7ügW¨áø‰ºû3 \}1›¶[ÿ ¢u~mÔììŠ@`”jó6ím¶!Gß2ГfKd‚µ[&œJ‰nÖ +÷v…-1-9‰OÛ†øtûZ§-©‰O¶¥Âpâ0†ÝÙ5Ád‘ƒm¸-Xðׇ·*|¤mS<×µ1º3òÏþМh]µ<'ŒÑŒZXî<~øPmMK]´<]ù,V£e +u§œ*†s‚q ³+oÙ9Ù£¾ Ä®²5¨¿v•ÿ×I|JŒ×T;;Ñ®¹‹r»SŠ×û©ÄV6Vë=Xå791FZp ˆ9B +\.|Q²õ öy²Š%D)w/D©m ÊQŽõõKM²+æbÚí^£àÊÄ’Sý^ˆr‹4«ÑЈó »wµôI!Ø ˆ´7z|jcíÁÅbÞÈL浬¬²+¼»«Å¢1]™D'Š=G^ZðÕ¡Eù×Öd/¿úôV°‘„ PD–49û=ðRJ—Œ )|0¦Ç„|PA—DÆ,àÊXxX>Èk`˜í åxXö#rVó:\œâÊ õ›ø­a…¬ ânfâ£MtƱ‹Å9ÉÃÉÈ[™’1vrá:ô²!ÀÐ9 ­޾…¿YIµ­à&ˆ‘NQ`ìUOàkÁL‡‚vVZtãRŽXã Õ»Àé.’bçηÕ[´„.\ NºŽç†+*ç!ÅP†Ño²xTÞ¬^aã&ëÖ +€– À°N²íte@\NRªLƦñvì´†‹~“ÉBá´e¦Ü'ÎçàAÇÔ¶€*u‘¥RJ€e.sšY+èçv»¥`¬5,*¥·p248á“=¿ ++ØèÈ‚¸IŽ~ƒ¬jÂë_†vDa´Èq™6¼²”%¹š(–m[V(½²O«”¨T9ÔÍeðA‡}釚Vït‘–nL^ÿ¹ Ôáð»5€ž s¤¹E»a)ernnÄŠáóà¸üª`ExŒ¼àÄ+'º³müp`:†=A´˜ºð=2}“ì¯H¥O¬&#’÷W}$6 ci=A„Ä¥F¡‡ˆ@±€ÿö[¢èÀ¹rEÏ ÃïÙ>a\¾B!Þ H"˜Œ,"¸Ï¸—Cœ:ƒáøéÀàt¨àD °’µäÑ´PD uh>:™¶1ãXíîÒ† ƒíf•È fš¿š6v0'q:œc_šš‰¢Ú`âúa¼çÊ6" Éä&Îi\z>¦|‚#‰ƒºP¦‰öƒ†ñ© œ rò&¯7b¡g„žd­Ižë¬ÍˆU7`H¥¦ÁÄ74 +œ¡ öHE£!`ŒÃ%6 «„NR7£ 6†KNÏÈE–ÎÇY¸Ì:ºbo÷—É{‚v6öi>ÀiÚpšùylÖpšöœ¦{À(È%,NcÁàä-jœfysFÌÖ-¡rˆÃà +§;a$c9^Ÿ³ðÚ§4¢ýx—¿ÍøtD{m ¼k„o|¡ûxûa{—švI›tÆ,Æõ8ŒsÈɺÉmd{nKÀ7iN?l†ÇÄïw¡2D§TbØLϳWtÚÌfUl_²ñ®ô{ZŒ=mVöWö.c³†„fVfo䂃´°žÞs¨ºNÕþnò ÌY`ˆÿdâãeîÚƒNÚÄD¾ +Òd$͇Pº¥ÁmÚâL|Â(-Í¡°!ÌïöÆhff‹y|2â{ÿ²Bv&2d™ªÉ3^¹g![wnR¶:îÙÄÍSgÄHù:û—¹}¢}6–Å ²¤Ìi eØ÷-3ÆGÚÏ>ïÉC(b à©$…ù,eb8<˜}ˆZ Ç8cëp+œñ[CCû?¸  !ž-”çðP)uÛZ3ŠîÔ²fŒ);i¿C“<\…_+Là“¥rz…p"Lna9áù7ø¬NA¸n*fÂ×ÎBWm…€;­4\x•`@‰«‡—:*ñ9Ôp=ÖîX›6ñÓ^)€F¢Ÿìîž5Ò“³i3©€¸ßôuJY))1絬˜§û]Ï2Z»)ÖÉî¬ —gÝJ{émýÛ B»»;;éÕ®;˜~Ͱ›òR·Œ„s³‡Ò¢e&ýû-|Ò‡zOËJz´Zèøë?Ù‰ãUôÅÃHúw.ðµK€NÑìw)Ÿw×B}²2ýš¶å6ìÚ™½<7Nr4]— C™×+ƒ‰þÃõ&÷‘è¤ÛUÚ$müé´ Ü·RŸlÌvÅ¥þæàéN%5jvâ ½G›J%‹M©ZÌ×Ó2Ÿø\H°PR ‹`Òn(äVÁˆÁŽ_PÉ^‰3IÈÚ‘hD–ž8”qhp4Ĺ u’¢F.=7ÉŒ­%G…¾ê)¿Z¬OH¦8òÞ” €µYóº}5á~µÁ§'Wí +2Ç—Zf7òø±õ>h ·ÂÝ!:&âœßȲG4šP b Ÿ“Ml+Û§¬†›rKç-´×`=ƈ%öi  .XxÜÉeš.-'r¢åFœß@2þ‰£ž£.ŠÚ¥9øg`“JW­T/`_Àns9¢#ÿ.ÿl_n‡Åúívº¬ßæêm;?—Îëåzÿmøú/ÿ×™£Y«µ±ŸRçù¼>ÿïkâ0½íæûë·ïۭųY31Ÿfóo\L ‡$Ç• ¿eíh5,—Ð5ß<ÇlÐËNEH/¿}…a”âÓß\G,DÀlÌ…ˆ¾ú43FÒu ï·!`,¾+yfµÐËÅ’_½äÖ/ý€”>…¿B¤ô°Þ—QòA‰±ˆS‘tVULÔé¸y¾<`bOgMpcÔÙbíž÷í÷/7´ÔÐWz•QÀ‡ÄII9…T*óÿŸ½wÿÒ个g-ÿe@ Yt)ãaÌÃ.ÙÆ¦| æÊ#Ãà¾RYæÔ²1òå2ýœ½÷‰Ìü¾ÌjµºK0³fæÎ2­Sùå#âÄ9û¼¿CvCÂHWà}7)òcÛß¿ùñ{ˆ§ü‰=á_ÿÐþóÞ÷Ú ÷þæÒ}w$~ñG·¦E~v¿EŽÿÇ| yþï±hï¿÷Ñ·þè›ÿôÙð½o}7ÿó•Ù3»O œ¹kâʰWüìn»åÙý<ðûÊ·œ-ÀyËw~Øÿvôïï/ÿø“ÿþþ~ñg_÷Sõ³à +â´‹ï|úüœÉ~öQ^¿þ£=“}ücJå?qÙýñï9÷üá>¾ÿÁ;ö¯®¢>þyüóñƒhûõñGLÍñÿøEæ=|ÿå'¼å3fîÙ~8ÃÿòËü×Ï7žûxwÿåi÷À]|¢?ú×H¼¨]é;=õ?ýäçïüòîÖïýø;Ÿö?è;á()ðÇÿpw¥À\½ÍœGS´ÞîÏ̓³Ìç?_Â÷Ã_¾mÿú(Ìýb A?¸qðù?çÃë”Ïú½o¼óçÚ~úì÷ô½ÿñ£·ÆTQéžÿ[[~øýwUþÇêØïÃå¾ éÄï¿ù˜®pmðüX +áïÿÉOþ]“ÿLJ_ç¿ýýÛ.D÷Í¿€ý+¬ñß¿þί>ýó¯?ûìoÿOÖ5ñ‡¯Šav¡Òsó4†¢óe0æi0ŒË´ÇaÌÓ`UŸ\ÁENÝ„2“ìÖ­1]ø—ï½ÿÃoýz±ýx‘$ÝÉï﹌vªïöɱ&Û7…L~<”ЬVÓÕZ%Á}÷çeuþ-ã3»<@…;ŸíÃý¯¯ã¥_ÿüí[ïñ7‡xiþÆ÷oó_}ûÅU¬sóÂÒŸð­g?Ú#Çxiýƒ¯¿õ?|Þãá®â¥¿ýíwÞÛÝ |ïÃï’§¹êÀ8ž.’÷~õç|—ˆìöçd÷Iûé¿NÚÏ~ûÞ¯~üÙ»›W€Œw‘l€¯ÎïÀ·áÞýÖŸ¾øÉ˃‘{q¦ }7gA8Fð=g¹F²üëá6'úk;âÃoÖuøù~ öEøûý"Øë\Edÿ¥ÿf®Ã_¦Ý:пåëßÛÖ¯ó/Û"¨;àc‹°Fdÿâ›ÿòÙ\‡o¼u¹¯»X„?ûüU"²/c†¿øæß|þ +aé—Ed½úù £ºß@åšvƒCñ‹˜òpN½{µ—˜òÃ=8©ëM>„UóhiѾô‡|ðÍ÷¾T¢ÀÉñü“ñù7Þ„µ‘ÖóîÕ Ö°Â+.Ò€ž}ч|ô­ÿ¶Ý ýç¡_”ìÀ=¹œ~È+®&ò6oðo¿ÿý¿úλëH{ òÿº»ôûßù×wüÒïýsx÷dú‰³ûGÏÿøM9Í`ËÛoÆi÷ùv»ÁãœöÒ{üü/—7æ´?þŸo¿§-Ÿ½ó§½ò=îßý“/ä’ý øWœöóvû&;bfÿŸ½wvpÚ«Þãû÷¿ÿÅçöüÓ§ $øÊ‚ðü%~~{¾š3öÿ +;bÐó ÏþË^‚.¸ß|óÍv€÷å«)}ó²ù«gßûrgäðõ>ª¿Áù«¿øIü‚—øíŸ¿öJú¯òç·|kwþÖ›©„ÿéÝwW%ýÒ÷xÉKü&<ÎZW/±ýïßãáÛ³7b‹‡gv»­æ^t~jÚߣÞöG_bÌ3-ámÂÇm:ŸßŸ}ý!¿ÿï>ÿðýß}ôýû»üáø÷-”¿œ~'˜øxàelC5„ƒÇ2ާ®áàcŽe_º†cõ¡þõ;û?ŒÏ?Ú¥·ÿõ»û¿Ý¿»F¬þz_Wqa?¿·ÿÃF8/B>gAΧ‰p2éøeAΧ‰pjÑ^ä|š§›QOvËG"œp¦¼4Èù4N.ÚË‚œOáDPþ¥AΧ‰pòk^ä|š'¤ÀKƒœOáüÿ½ƒÿÏôþ¡Í?Å÷ü „çßýìû॑ß2Òß}òùï~ÃKÊóï|òO¿úìþ£ÿøÄäz¸Ñÿ[ìÿáÛ¸ ±ßÄRì? +¨÷í÷ÞæÕ7á›{¨œçï}û·Ÿ¿ÿ«‡ÏõëÏ>úíÜ|“´tÿÁÞ¿ùæ®~nWÿéÍÛöNËs»Üþôã¦Ïñ¦Ï¿ö{ËÍ·ñ?þû×~ïwxoÿÿùcûŸÛÜsoö6·K¡ûǥņ·¼µ” Z+qd\s +©Ý|ønðüÏâ߃ÿ÷!œöáàY?´ÿþç›xóï7a¹ùÑÍ?üãró‹¯ÙíÇ!{Z/7Ïb·©|cvPhõ¶µ‘vÔ0º½h)öÛ^úØ“R»-1Ü<ØO7b®·¡§z³»[·uöÓí±“tg¿é6ÚOö.á¶„åâvi÷ظ¾Þv·õ#Ž_ký˜[²Ø2-¶Láæß¿¶]g·´mÁšÄ˜oËXúJ‹½Ü.¥U#Äp[c¬{RZn{Šxµ1Û§a×m÷Jõ6õw¯¶’ìÕPn½Ø?÷×ÝŽóîfe{æF›¯¶ÝIoøD{Ú/å¨ýuqL‚~pÉ%<`¿øÚïÕ›·ß¹ù­mŸŸ­Í[Ï_{uì§o°>o=݇¼Î½õü3ðÊÛßþìןÝÄ‚Öå«’s\YÓm.öžÏz»m¶l”c+qÔÛz» Å(!È“v›Ò~í&…,RoK7!²]f+X²é‹íV+e>"l%Ö~›jÁýãm©Ý–²ÄÛZûîNÀóJ»Í«;/Zß|½Ïá%ºÎÕÓÛÏÒmÈ¡ŒôÎÍ{÷ùoõÙ?ݼýï|ûÁÔäO~ýùG¸øZAíåŸ Ö#¤i6¦X*Ws£{Ë–ñ-ý¶æ†Å[Œ?Ò(ûõœ$~ ÉÛ²„ý…ö©9—´¿ÝFšÏåoWª­îè5Ù…Æ(±©…žc¿ØG'=H¿-£Æ‹ ×ÏXowüÞ‡']\“cJ‰ßÍÿߨ÷k#Ú‡Œn‡¹uÓ`ÆñXiPíƒíóZ³Ã¾´~sê¸íKÀµ5܆XHL‰üi´d,;üÊÃ]ï_ú= ´mËË«~Ï&OjLx@¶WÑ[±A.µa¯—«Þo±óSM<<ëK^_e˜Èè& @·K­™ÔÃ]_þÖÉ„EHéµv¡›\‹ WúmHÆ}ö m8'nÔûKªí|5ñÄ·ä0F¾ žÜ÷~ƒB}?üZ£4Ū´ZìKMÒà鵘iaðé}±+ R¡Î;Ü_ÜaGý%§‰æoüî F? lùÚmÀ^\Pk¶mþ€Sê¼Ãýé}ú½ù2áæ}}F]?îäÙ“zõ”=5µQ/Þ~£–Ó/ÝS·UÙQ·¯x„šÏ¨û7;®Ã£Ôm;?pLrÄ!ä´·ž/XcÃǽ|!úÙn^ÐwïxqŸÇè÷¹Dñ+G&NqæZ“‰)õ¦àœÔûKj¸mÙ%çvƒSâöûçyÂR“™GŒ·)ÿ±}ƒ ófЧWóbÐd¥G·/‡˜€uuî"Ű.í&RzÕ ™:E¨Ý ,«6H9uPM ×E·=¾‚^uÑ ÚýÛ‘5šíp^åöè0ªíKniÞ©-P±—T;+¦ûvw¸?½¯/±'ä~/ €‹}H±åãžµ¨¨•Úã†HÕT¾ÙçöÁKœ¤jÆ€ÿÀ 'PSï®ôÌÂ4 …—¸¤ÆÛXæsj~°lqJõw2b¼iÕ„kJ~!w<®ïXû æ¢òÅË]>ÇDïXøKª-WÍï`ÊJTã¼æ}—„G%Çù\ŽŠo7Ø#ýB¶ý9Ýöí±ûÓÀ…ê‰olõ”HJË©[ý;æƒK×Õ D6޾56Xì=B§8n¹¸ë±j¡ð69¶&R+eðmìûªá3Q»)Á.Ï Â)Ù…Í0ìèqOÂoí,٧ǵ,092ŸakHæ!$)ÑQpÂRÛ”^1>ÔÖ­‡î…X¤Ö.bëÀUywæ[3Ð䟱O&ŠZ[nÓ‚ âM°“ø]µaí"[2C4­Ú"GV3’!Nðƨä#;ÀÉ~,.ö €Î•z¯©ñ( û4;\Aó õªcCfOjùqjkƈmÌÛ^­ÇN.´n¬6(àvr0.òÛìÏcHÀàìńϻ šMRc¸ '·ÕCy¬ !^?ÏäÌÀ‚\ÜÄ–!,±\>b»~·Ãm71ô;G^Àj&Á°ê¶<€Öxt6¦]úžÚïòèÚˆ q³'ÅÛÞhÙìˆØ31nZ2&œŽÃšÅ¹Fç÷N,¾ÕÏ£Ý;-á“ +–ÓëáŽfQV‘ €Ô`ÛÓd5g|]k&ðŠÐÍf}qÆñ2O#å {6''›¨âo;+`KÕB&ÛB +´JR-Bóûú #º š‹çBîj¡_Š^¬ÈÀ·“1LÓ¸RŒ2žÏ¯2 ”ô]a¸ÂJ&Ëõrv¸cú®™²³*ëêgva2û‘w\©ÍìÒÅ÷»ë€íIb ͘.ÂõL>,KMÚÔJÙLÞɆ1²Ùk Û™;¬áI]@±›·¹IfžÛM£_˜„€lzÇÄÞ¼k!xÃ>bõwH±9Ù^r¬À¿òbºÂh&×`h󳌉ë%-é­øó•l‹E·¹ÑŠ}£I.ªik[TÓÔ·€‰¿¶ÿ0M.¯\°åãâŽíâá;2 nþ|½¥é>ÞeÿðIÒ«ÛqLbçõJzL‚ÓÌæçD…_È¡c +Tç€õHÐÑr7S8º„èvé@în´oGÙ,-ûd8²Á ³±Ci‘§£ñ“L6dºOv—‚¸Á¸¥þvIG†?´pE¶[Ú*š‰zùôIãÏíEëêå¥]Àßhuý ûëÒy]ÚÉ&_¦IÛ/8v†q?–®Ÿ’›á4Y·ÜºdƒÄ¤Ò ·¸GoÐzÉ"Ñ5³’&#Ž2ö×o§°C¦ñ¿6XXÙÐÉN0^iB:ˆ„XWˆzrÌ+Mlhа]]9dkín¸‘.½#Ã=edžèº‹­T#%e¾8$–|Av[žÂ ƒ@_Ýö'0¢wI6ìo ¨ê&aq±ÔÀ3£jÌ"hSZv½”!àrA2•GÛÉÏ®ï\úBI ‰ŒhÖcé¡Hx·e®i«ê€bw%ÔýÀ4äÍžMy¸j'/«’™wÌk°|{ö¤=¸Ò3É3./í.÷@3pÅ@crŠ¢Õ>.Ô0Ùz„ 5¼gÿ]¥*¸ G€~B€ÖV…Ÿ!„pȵ¥‘¶ˆIc,ÕÎi0¢v—&àÜ’uNkÂ÷ìi&—žüç+¹âÓb±Û-7Pr^Ö ˜=4Á­elTô"±1Ý ‚ªøÿ ‡ši0)$D@œú+›‘’ ®-,[`FHìÍLZ Y†sh¨|e¶@éTÁ&“Ò~Œ +äDõEx/çl€DOG(Á'’äV³ûÚ»åž-¯M!KÙõ0A3CQ–]^ ég83KÌ…(4Å D†³£Ö`âæ˜ 1G.Å€MjõVƘíž œ ¦OëBd¡U0ìÚ ¾è°j32à•‹H3˜ÜsŸa{˜Ì¹¯7 Ø{Èè… +v%-¢˜ã|QˆÜð†ñ÷«gísìƒéJN×¢=.Áì5ä ØºCý“9mâ È0ÓʞÌ€àÀÏp Ísílë“ÈPó-€lÔvvA+Ìò¬ÁÁBk8Ä e€6{¾ÝÀØä†b†5Þ Ë³Ë${™ºÀÐOp ã (å"E|²3Þ;ð¶–vt{F³ÃâüX\]&ûW7îü¡è²Ø´äàÖ_­\®´Iä +j!O$lâ[NT‚ƒ:°ŸC ïÚqn{ð´»|æ5øÝjF}yÉð˜ù”ð!tFa‚Á12ÓŽlç4ÙÆ˜z ð¤"¢‚óœZ%ð1F`Ǿ «É= !á׆Òk(Ž¢ãäš Ô\Ž˜b´‡wð€mc<{«»VàïHó=ÁIŠ +˜Ÿ·À¢8H)è5#?‘Á<’¿æF¶Ó=ü5‚e_>¦õíu1GrFÚ“íÁivòz3Bž”H µ-ªÁ™a¬ÿË Ñ@“µã•Å„³-cŒ­ÉBÞ‘ñ2màsw9—&JÑíV|Þ*-°F%RÙå^»/]t¨Âä¥(¥Í£Äˆ©v¾V‘ç„]‡UMFíióM ß6rÃŒýKŠ +Lã6Q2•°@ɽ ÆDեȵop_Šíð-ÉqóvµY÷cZ‘{²­„+ÉÆk‰:¥f»­ ‹£õlžv—ÿ³Ä´[a,ÒþW`”ø¢ÿÓÙÁKaÂ[óèIaTV„Ã@Qè¶2e$Ïí<&fRìlÇzPñr¼$t­"h>"|m h¯P¡<€Id[1„/d–Ëc‚i@ª¹’‘¢À“ï`LXMy‚ƒJe‡™éÝV(d«%/[2Åj‰lï-ôNwœØÖ´ö~Ò +ùÈ8û·à弡jº})€Ñ)(æKöMîðu~dwùÌÛ 0ˆÖWÞ˜Ý(¿ºËÀ¿ó5¢N(ôäWÿhX:» WvL‹»C×CŒa ¨¡0šR õ¡öä ³C + ÛVfe÷PG©ÈˆM™6FË„'Õã ¢Á¬ƒ +õiûnï”û + ‘LH.-Æ_ΥƖµ!T^-ó[àPˆ 5 !lKܘ›¯¾Ã ŸëŽT·ê²,¬×SÕ@êѧ¶°­ç*ñò›&m®[ K»¸X[—Ú_–ØÓS¼”u᜜‰€çî–` °Øþ铦M¢YâÅ¥ØF p»åF»xúya€´ÄMBþ¡²Ú@Sº2’êôìVúÕC˜jî®¶ãtN†©–g +Îi«òf£^ç4 ÌJ Î$g¼"¡¬³7?ùù`ps”ÝÄéÝ +Ðh×¥±£Ij!¥‹ÕÝ¥C59»;n¤ý³7*¢€>¡&1Š>&žìÄ-MTø”ï.…óÅ*­þ*ª€ª+ƒŽÊkz ìï-å±’S§!†m•$G£°¶Ÿø’¶rÊŽ ¦Š! +/¤HÓ̇K÷pcÒ¦Æö%]/…öÕ_o¹£íŸ¾'Û¥=¸Êö[nævÞ(iƒZöß¿fÚ¤L‡¢+/^ð£KÚc ‚ªà¸ GFI±]´©²2aJ—"-³˜¥ÒåÐL[¾ç’a‹+ÙéjaS2z™‹¬]{¾©ÓÁ4ä,¢rÓ^5x*ܤ4 móè1†'$SM]¢×ÎúS6ºÞƒ0‹ØñJDbLª‹ÙLK™ÅÁeðÔpñU˜ÙQà ù¾©V<_u)Þ`dOM`:ìbT½¶”´fÑÜ P.×ÿ‰CF ² é¼2‘ŠTÙläœ^Ó.P}aZ¥éjˆ>{ÁíU⥌¸ó%"œâå¥Î•›½I=ŠŒ; ´ [4’Ó, ·0bPAÚ ŽÜ};úÞ àƒî˜‚ Ñ E>Áa,íû¹L†‚7‡ +НŠÌB–>Ó;xèbf‰nV' ]D•Þ><ê  µÞ²bX½-¥©8D¬N£¨Éh¾mѶöV«ææÔéÈmšªsD„û²Ï9]à˲·5ÆJ••×d¿Ã<í&ÿɘÇвŠÜ²ŸBDÞ€Òãò€:Ã…ð@BW)æ<À1yBÖb˜QÔÄÌð LÈpé¸g¡ +§&? +GYc½­ÐU F·äç«:Ši š…®¥õRÛ(ˆn¿%ÓîŒ!VÐH«JÊ-0í7\©Ô(†uÆPC9ÅÇ‹¯1ûâj\“K9 Yò|”Â3µ4ÐÖ$_,ëq^ÎY(¦I&›^]|,ÃOU]Xò)?ÞÅ6,ïÈ|ç%f¼ ª·öyû<øÔUsÎ5ÄÕ0ÁÚDmrÝ9&(y‹'§ÞFKFìD¨½*àÿß¿«Ó(@Ø9ØewiFNý»Àt,‡åà0gÞ›©¬,£á+ùÞÙTø¥¨öÒå>PÙáZ¸kéró$ï‚zIdÐxÒÓ¶…=Ùƒ§Ýå/–OßôƒÌjg¸Æ£}äŠAL’VV‘Ln$Û¬F3ùm`»Jî{J@#Âò‚@¨®u÷2BìË(4å=S +¤¸ %fáœÝš쥣“ðEe)¨4‰c$G ÅóLßÛ© îyuNFÍR(¨Jùäu¢'iÑjĨ‡c[è×!ŽAUÆ “ƒt¶e`‰Qñ„`çf!`E°¹6Ï“ ð/f’KWѽlr3 +‚edòOÖÿ‰ÓW¥ò|,UÇM ù'ÃT âh¤©§"ÎÌ¥õ$× Ü°l D>O††ã!h˜¨~ §þ@ÚHUâYZÁ€‚ì¹ߊlu€Bà]fßÐp¯m[8)ŽàŽ‚N­næj áÜlÇ$vˆÀ‰AjddqF|îEe™!È4¦  R†X·nÉphPhò†W³¼ÔËw=#G\@w2/†ÓJ]È}‡-xòì•}äH^,:ç€#"t(ãc%S>.ô<3._²Ó@³GG‰!v•œ’X>åÁTÈîRYG€«K­+Þ[aýÅÐ)ô9z¸&±1 VqAMˆëÊæ|s¶ _”{ðåšJò BqH²IeâƒÙ2vRùÊr#U ˆœ§˜Jל ,P×-€°' X× WϬr{PF"BRÉÑÁè]‰l¸ŠbÅý‹NÚDq»+sòÚs¤¿ŒBÉãÜ4³²g¡G«\G+y‚ÅÃY?îФ.¯6VW7ˆ+2‚Ì­C,6&O?o®ëqžv‡¯Ï5œhŽÝȤ{შ2E(–Ų¤iC¹Ï>3}¯IW… Ñò¥ª>4)80ŽªŽƒÒŒ3M®¯¤(1Š”™ü±„â&!µp4Xpè]e:Óáh'&RÂCµ÷,‡£vЍ´êGñä-Ó–Üá¨f³P,p–Ûlx®´ýjYYɲtƒ„t—Up7ºn_ˆLÕ4842æÁŒ'£‚Tƒ€ÍPms²úOœ/¶ä6ÏÊ-®îF¦S§ ÌÖ!2ú!{˜jw£zÃ!É"¹¿ëãnEäõ´y½p±‘êy·à%eû±ôˆÀeµ(“¸P¤Ø®.ôÍ`*ŠÜÆLô3S­F,+³}=P¥¬X¸d¼^òÐÚìD¯2^àP7µà»êž/€Õ2¥KvN«ÃÎÆ®šdø×§ÃÎF#8¶QN3m8ë-‘A¹ãzG´½FºTG‘³Ê“¨Óí ;Mîâž`nÇúÕ±%å³<ûÞ_Sk˜ Þ°3IÞ°%ïW·(õGɹyj÷œ-în„à#\ÝvGm*ÁUŸÒüu[X©ul(¬tJúRøÞ žîIÛ"mÔu1 Ußæ¶ß…ŠQIÑ'ÙO+ûź¿ ºrSλ­¤ýc÷TØÈöuÛíà$MPÛsW~ gõîîªòiU-£Ö­2ÿ…áØvÞyq·ªˆ ,êPº£¢qó¢¬]ôÃcLé*¥hØZ¢…5STÃEÓÇò¹wíÿ +(iñ7j бCëÈE]PŠNM&⎄ߟÑãÅ…&S¨·ÛHûçî¨önz!öýË£‡_¥d™yçýêõ2íNÅ9Ðb‘“´wf£å¥Q-0NxOÓ“P™Õ{™5ùs7é°g†N×=SLÖ Òhâž·ö¤€X©› Yo·I›£Tz£lGÞñ`8>)W²§0mHõή³éPÇÂw`&Œ³ \…V¨•HÝS•<ý©£Æ†Ýµ¼’píl/RæIFt¤Cc„5è…8{GCVšLƒg1Kž5ö¬SÃVXÁâŽøbX(Ìî&9²o=…é@²3S®™`#É^éV±™²l5*Â3l¸…0ByíÁî­†GÊþ)Û 3A/Ó¯^Ç çëÉR?­2ð +ª1ÚTEÐÙN8tç˜H*P‹çjìdØÄ«UÅ,$Þi]Øtõ2ÕG]|µàgÐ$•aÝ«¯sRËŒƒÁj¡Yó(nâ²;4VD•ÙdecÈ.ŸT‹Åbùx"I"†ê5ySM¦«AÝ`Ù¨AVcT˜»šJ•‡uÆiE­c6¸hC RáÓHJx+C8¸£WIŒ´ñlM°õѽÛMâêÍÉrÿg¦Ã?Y$¤±*žöAoª+b:X¹¬˜Tôàc¾&r +löÖùStw68¬V°ò¼D•- “åœèúÂ¥c¶tÆÁJ^Ã8›í’Ù²ô¾'5 Ù½áð–©èÔÍÆOe&Á÷ÈÔa&&ue¸õXÔ± +¥¦Añ%î©Øt Gu‡[õ&vèù¬Ž×TÔ~Míj7Í%¢ÁÇfÃä$­#:ßüi-]<À^Ðs‘(_xÛãÎõšT¼ok³.•.|˜¯*¢FA5ÍX6ÀåÒ0› V„ex-» “:'À80½a¸–MÕÉ:°´²ÙAzG-O°6¿¯B°™w£Šýˆ®Ø^‘콚ºwÙÄÈ’N¬ˆ‚¾ŒÀf¯m EevíŒæø x) ˜r¸Á@#V< hû‰“ѺºèQ|\ð'÷]ügˆ‚ÚÕõ°c\C"Á Àc¤ÑGg¢>Ɇ$¦D¿:½³52r X×8å(6% ×¹EIgv¡Çš" ‡jŸ‚\¹ FP¥ƒ° ådUHáæ* ÕThKÍÕG*ªÈ¬H*^%åê€ÍlOCàp¦ µ†Jk ê¶\Ùâ2³8·*eçË€L/¶ëÀ\ô¹×â0½ˆ¹´ŠAEÓ¹™IU‹“+XiÐÇÀ®Ôn@*C½ïSb’îdµŸ6§!Ò½MRÑ',3«øˆKˆÉ Ö)§žôV–ìÓ"bK*jcùXÒºäqúyðZä ŠM0 “6Õ&Ù!ÁÈš%º½I0Ñ /“VUÛd5q È¢©HóŒâËÂ?yjÕÕ¹|…‘Î.guÃp³!«ó…p8ëFíì8f-²´£r’4ÝLn) ~SÛžzAƒöЦ_C]2Bljîw¯¦Ì‘MABÜJæ7ªi¶%ºWÏþP°Ìñ«4FÕ§˜ÁN49^)l6ì#"6¢{cÑßû´ ö¿áȃƢt4AÍzçEe]u´~Ÿ²{ÜJ„q•3ÀOrp\Q‹ÇæÖm¦ Ø4¿o%^,Ež°ˆecZÛ½fô¨~ìb‰7ên;¾´Î/©Ýç°Í-nA@´ò”D(pû®$w˜pVb<ɼ™Áƒ!{*çÙ {j‘ÞîVõ-Ý=u’èYZ_o»°Ëš|†q¨Ú}k‰jsw±.“z¹ZŠ^‘²Û…S*²íW>6%y—ÄèítL–(œ¦VTJ¹#!¿ ®é•MDõ|oqŽg,H²‹1aç­¤ vP[ÝíB29Vg»ÝŽ´{îFe“p¼3Vå@92†›íüásÙÂëîâ¬î–fwÚÏ©»%§aoŽKê*m|w"iîõNv혢÷êïÛ…h*ïwsÛ“6^ÜQ'Óîn·ŠÂ£ÌÜ»kfæ´DßÏÐ@Ípˆ×Á5aGÄ84ŸéÑU§ \®Fð±õä`oÆBÿúÜ•êÃÛkWö¥:‘9N¶Aa—í&ž0Éý™*öòÍîÝúÚo¸1ÛÞ—õ2lIÓ€5ñkj8t%Žì¥Æîq‚tõ÷‰êç}˜Wvïù~AH‹œ¶¡^O ¼Ä°Å\ºã +?±É…q+à†ÈˆšÇݲ2‰\O,ñE») ÄÙ1#T´ûÙÐ#­ øÏ…™r‡LKuÇtóÙ!]Œ˜r_83ª¨©Û^lQ¿ÇMµQ£I#ȾC_;T²ƒ_Ûd¢ð`dî^gC–C9Ñ­@ýÖL;uµ‹J„vWfѰ'†ÙuQu5_#æbV÷+ o¼Ñ7'ªÙvWªÎãBIê“1·i²N1ÑõDjpf[û?mG’×V_¹õLF4§@ ;”ŽÚîý;:i=–¼ãz!Ï%'yÖ¨p¶&bïxnG¸÷âd®Ôy4õó”Ôèâl^^;ç%užN,Ïìv<×¥Œ 8ƒ¢Ex^TP†¢=3Õ# V¹ý[qû¸ ã&5øA³×Á± çWbƒ[ƳÏw`Ÿþ€×ŒÉ›M‰ÀÖ…0÷ÖUíŒL“TÔÎèd½ŸÖƒÞP +å+ ÄE.Tà²ß –bÈ>òIí¡ØŒ ½?™(…|W¤¹ÝiYè}†ôJº¹ü ¿Ã¾v¨MÆn0´£ÕSS'”ªât6ZZ]­Y{ÔÆpá?4{f¯Q9½GjEŠŽþË–/ÿÔ:¡š6vDó=¶…äÉgÁ×?µ«Q;ÒÓùÔ¼áy¨E¹nOúÔ«#¾N*‚Sþï_ËLZ °ìüøŽÚŠº?Ø'!¾ÝÏ«:g7祡f¦ëƒ¤brH½ˆ¦Ól"Ž€Q=»Vßùo™…môüI\šØm¥~fbQ=¹{›}F +©ÜéPq7h#ÍFFBXÞQâˆõÜÄ-+tª:ˆ¡ hæû³U8+sX‡VTÈ ­V]ª²ª³…§œH\Ež|üͦ#Âz’èÕÂÓ“ˆ,ó‚Y‚FÍçï]R1U)ÓÊš7 µ¨þîI™5<¶È`iâ‰HIßÈÙ·x6z-°‹)~ÚÇeX®&ª'#5zÑ8×Î%eBÒ˜ó“Lï¡ká¸gmÅH7ìŽ1á¾g*ÎF¯ç̈öW²#ÿÔá_¬ oÄpŠ÷\ÃKׇOöÂø•ζX+‚IJ•Yñì„D[:€vŒ½£ÎC@ê¼ÊH—X&ÑÔiûâÙcJØ>Ôœ+eÒ4­)ûÃûJ-ªWõoT¯ä€*›æÐyÎ|"•ib¤²Â®Ï·¦W°¤ÏØTM¾¹e9Ñ §EmzÐpÆg¨UeÄñÞY¡#¸…RÕ‰xÅ6t±"W¶ùn€½:ƒ©!j08 üº1+Ú¤°þânÏØ¨¶õò‹õ\ÐæaY΃†$ õÌǬG/2õ¹àèµÛæŸÇ4¤;?Íä*þÐ'ðäË϶Am”èp¯eó}€4q¯¹GÕ)siôM0kY¢ïahê°IA&/'wV W óX2î\ ƒkÛ !Ç(âZ=}e­¸%&V¹<9õîB†ï˜úcè÷ñ]Eåž¡N›íØ_h;Ë•á›Þ[ƒP•*›mIbÆéðãÆB +æºÓYˆ.üMEi2F˜7ÅsØÜQË%禦Å> rANÞðŽï³B™Y¼iÈ«ªb¾Àâ¢zzpcÐ ×ÇAñtq°ly}ìðÂGñª;I>ޝzÆêt:óÀ,ì²F丂Eº­¸“åäýå9±‰pÉÅ1ÁxùJAÙˆoaNjé“ÍlÁ›fFNIá J +ŠîˆC½pPÕà/v£ÆW/ì*¶áÚ¹nà”'cĬ¹B®z¥Èʼn*¸#3'¢Y9cóv¤ýËì¨(b·-‰Þ +çˆz™“…™Û9¹3(”m=µbÞ £â£ý{pB×8ídPÓ°àdYe‘q*_¼®9ܱRœÊ†Åh­o TEBÆÄö.“ò ›žaäÝeY£AE1‰ÏÉ®,¥EU-b,±ì¢7ŽEÍ8ñ•þ2ô*b5.ú¤v_{\9à^Iˆ ÖçÉvÏ{ç+}æéÂÑQ`zÈ;7…!Fá”IÖÈå†yØQÊlÔé¦Ed#G—U=ÔIƒG-º ÑZSß±=iÇ'É%É^qîí.Þ +)ø<ñÉ7>Øaã‚TDU»ƒµ;êNû¶[àní`-G[4}Ÿ# +4²ÑDÆw  SQ.`-;ÞÐk¹¡Z\©òÐ=ª-ÝË ö ¶ÐAF¸:AmAqZUÌÆA-gj„2™ƒÚ¢½ª— ,A»µ…e)q\‚Z4DUâÍ +jÑj”Þ6¨©zí¥]‚Zä/•Ð}‡_Q[Þó5ª•‰¸¿‰ˆ#źÒ,óÝP-Ç4¤Ú.Q-jyÕ«`j‘ìïîöª…}î't‡já*P½ßŠj9A#] Zvˆïר–SGxFv ò]Ñ· ÔâJÓ÷ =JýÙ+sÅâÕL ƼFß6T‹F¦ö|½Qw`w‡¬Ý=jÂZ¼PFÀ {`¬Cמí`-~ˉ§°_ij<]ÂZ®] W°–‹Œ¥Ý`-·"æªå–5BȪåö²sjÉ + “Hv¨VlÃ,†ªŰCµN¸¹2ëÔn|½°Û¸ NɱGµÛ±Z³ž½Õòjíqív ÷¸V‡_Ÿ²áZ ŠÞ/p­ +³&®•Øé{\+ñT®p-DY^¶­®…ÀÔ`Ü=®Åµ!ÜáZJÒZ÷¸v'o'®Ý æ®=í;\‹AEµ_ãÚÂqˆéÖ¢z×D÷Ö‚¤v°Û©v?{\[ªçÅ_àÚÂh´Rj×b~M(akOÞP +Œí6ê5®“UV¹ïq-øQ­®W\ G?mõìNÕ(w¸©zÒð†kqd‚ ÙĵØ>Æמ¼£¿<9^áZx<;_ìq-©­ç®©ípíeB„Ñq-ŽjZÂ×â«Å;X‹Ïƒr|k±ê»ÂÚâÙ…ªÝ(û7ÙˆŽiAa«Ÿ Óž,НÇŸò î0maî’vT|°{ÒÓ §+L .Ñ÷=¦ånµºÇ´p‘¦¾Ç´Û»ì0-|šlß´»,xÃû‰iq Í÷˜­Êc˜(|bZ@®Ò†i SÂÓž,‹0-ÚGŽ’¯0-nêŠt‡i5T,î -{ý)Ö7!-Hò[ì -:´g¹«vÔÂF+¤%©È\sH»'í¸d£NH‹žïšž·BÚ“¯Û ­{|—›~ 5ØÎavFO-zþz؉4ÜÛˆýÉ]¤PäECßÖ…éiµž‚Ûv +ÚÈÂåø1p&¦ÝùMÍË„zƼ¿°$µLbñEGm‚rŠhX +ó @ÃtÃÄ1DI”¶˜´…θIðß±1ëåe&ô¢ß«›¾‰-7DÊë#)©H4+¼.ú¦ªî qQ½ÜJC Ýâ¶ Ĉó˯Æ`Da¢TŽ‘qœíÄ ×2”®B¯÷%D¥] QU^hj¡gÜB”T?(C¸¹°Ž8ȉèl]éBפ]£Gr‘ñ _”wSUmÓHE(žŽx)Uœ1ø®YABû;„Éø,4ø°ÝD½[­p.C” •ŸS£n{ÑHü£ñÐçŽ$ŠÉ9%—Üg`  ï[Ûþ¿B[ 6Õt:2A\=c37ûöõË€A삯Jìæ”‚¯Ã‚x:D2Þö C8NŒ "ñ)œlŽË$²}W¡ .gm[$tʦ!6)x*ò—"Ýmëu˜"‰óy·"å©öxóS%U#ú$DÑÚÐáìWö.ì‰]…Xâ¹R„×’¿Êz]©6ÈÚ`‚T¡N||P *Æ9ÈF/7ñ—¼`Æ0ál˜)Ñ *ëÁÀÛ¬5ûˇ’rbjµ +ºÖäá¡ÔÕ%¥b{õä4ý¬`rODÿÜ$RUx¤ê-jSå<ã S ‰&N)é¢úN0è·ˆïn³ø(îX˜—ÅÆæFÝ61f>BK€Ä~ô$aî£Þ-o§áºð:ÎGuÊ$éhOŠÿR9ô×Í"À.w HÁmpÔêÍuG/m^ŒªÃ +±g+Í)j¢¶ô¸£S—´¨*A¿ Salšî\h4wP,HÑÀO‘EËå F4;E4¦ÑË~µ!IlMŠL@¶€_˜°éZˆá^~*Uu¡¾lk~É”…ÏÜkƒAÙ‚(|* R„é&Íš8¨ò;©Øš ì› qÁS™Ârf€Ÿá£„Ñ×CÝÚxàD‹È¹#h€ëŸÃ4´‘‘ë]•˜{‘%ʧäIDÛ¸-™3jh(#§¿î_÷ðUw»Ÿn«E!Ý‹´« 7a‰ÿ سowî´ÂÖTC +¢ %¤ \ç˜Ï‰JlyAþl;ä×rNž<3´©¯E)4âDëu•~­e¼’[N¹“Ü +.¤ÖëL,ÅÊšU®Z¦`œ k"¥Ý +!cŒè5ÇHâƒða1 +sï˜4|'áÓêâ9=UI\…F‚<-?Ó!õ“‹F’cLëÔ™7ùŒP´ØhŒ Qì]>Qîä@¢ð™¡iðŠ8Žƒâñ©yæG^œŸàAóûã²Ò0++œëž4NMöTʬú— m6Õhã›Ý…ÈØÁŠBcxköØk„Úe%@Øæxiiš¸¨|Š)zrb‘†nÝÎ(1IœJÞ³Ÿ*ü¥Ž rž9ûí0䀡0"8däÀC` —KW8e}t‘.ÁØcö–öóq}†ìWß»”;a>Š]»QyÁƒÞÊ/FÌ-ËÈǨÇ@÷r«j s›\ŽÒžÃ¡'_‰q7eGCƒ¹Ì„’áÛ I6¥ïŽOŒèÒÙ)ÈÀד÷ýÙî›¶ïSf„Á˜4â46(°E‰Äi€slqq>^Mp9>¾1C6<0Ìm?¦4ñcòQ5ØPO“ÀéýÆ£ƒjUï +8lóN<£báÀy1×eºÄí ì¦:#À°"™  T&rÖÁué,ŒKÀAäò¢öLV¥#ŒÐ^~f¸{YOíª™+mž™ûK«á@P$Î#¥Qd˜$õ÷Ó6 Ö“Ùì-¤Glç4]œÓ!ívY“'O7÷€dJÐï¿ íÃ~‰éÞJä‡Úd8­J°”£`)›`uz¨&j•C¸(§þÈÞJ’æÜ ™Ü jʨ”è´V²åÄö›KÜ a5—øÂ½Ÿ‹û™)0)Zï…jâ¢*ï’*AbW78èXÞ/´~‡8mšäÕå쌓viƒ—(lêtôJ¿~ÙHÒ›lC° GHÕ\º(4£6TÍ85ãY‚ +lti© ÄIÊÝĪ©^]× É€J]ò¬‘)ÊTÙºÉÁj ø%¬bDÀWX-$iÝ®á=æ/¡«£×ŠfÄêÅCÀðhª³ã”\ §)”rPAõ|Ï~ÇÉÛ‹&˜Öed°öÏN?ô~_’ãÜ9ˆÁƒ(I¸Kwƒ…jI¥|ƒ¶Ž´ÂÖa{Ú©m":1µ5f·árGT¤7ï~D=ÊJSŒ=uAMp*Ó`Ñùk€”7€Ôfßêí::ÖülVNcRLÝê‘6¶x9Ì}¢e&»†seƒsX`±Ïz¸B黨eÔ0 +çè&2+ùÛ¤¹jZ4-‰þN vØ °ÌÙ.æ:ƒCw®°ú•Ù4fÇES)])®»£.ÛÛ ‹t÷šwŒ©ñYs(8´ˆñ#¾%°<[ V|4b¶°ói5ȧy¡.N4.`耘1¶„½]#”»SðCxó{.»Ëº‹4}0ìxJ˜ +'F…‘8‰ —\+d{ò]R/Œ‰³b‘·žÃÄxë9ÑÎ[ÏO@ó ÑOðõ5?Bõþ¶™Ô;`t¨téqHš‘O ýøÄ‚¹2r®Aw„zG4xúå]ž@ÐTÕo˜ö}† Ï@ò5–ö ëAõžŸ€ø#Úç[ž'æÃÁʸãžØ#Ø¥ƒí"úÑʹ¶ƒÆ’óÌÁª:š^G¯xbÏÝ‹~0ýNØýáÒÏð?ËÍÛßþìןÝÄ–yX“€Çä~ß‹§®qú5˜çcÉ£¬"fO{{›£Mñ³GžÿÒ÷þg]Ó_R<þ•‹ç dÈ'xù‹K2ê¦5ådøÄ º©pAqB×ÐiÝ'ž7&±:µq\8ÿxÈ@c›“aßwÌù)½o£æå~eh¤n£oÂr¤Iè9¤ +Üx2wè˜-‹_`þ$Ž.k^â’ázÎrYԬн÷3?®Ëgì߇&嵑Lã@=ü”|1PÐøÁg©Þer­ÈZLfÀ¢ý&Fb´'Nè§ÝŠVõ,{Æ¢9xÂ#â™ PÅìå¥õŠ»p +CÕ\”ò°%%å’wœåÄ+ãb–MMhyñÝÅÕO¼­þ˜3”½ >g•€ëèd“Z¼Ó*åŽ É^¨«Ï`þmAoj oë¿p~G+>a~âç¸ Œ*É„Þ|•ÀŒ¡ù,¶ Ä—ÂÍ×ç<Þˆž|4â“«§pšø@Kö1æ8üv?ÃW鸬Ã*‰–‡ëH€Òu ša§ìźl‹p¿’éÊEè(­ÃS‡¥Àía]JÌ3(:VE!LÍYMJ¢Éš)ÅáKRØÙiúv”qו†fw+1bvŽŠÓ³X¼f\?/>ÀsE g7 и0™g.jFkQ”ØisyA,jôIædt!á4>ÜR¬¼£…¬ymÎ0“5‹‡´˜(RØè»bn`™“ñA1”9Œ–1×­KæQÕô…¥àÃG¡R€´Å³¦Ý‰Hª)ËYMÞ瀘š%7”£ÓêFÖÈNæ&q%äÙ“˜P‰à¤âyD­+ævA0)T‘ [´þI«N¡*!šÏêlC­‡ZçänÞCAö3þðºÍ Æè¯Zèô;Ÿ"’—æ(l©±hI,>Ý—!ÕÂáÒ@WìÞ 9Å4ÛO|¿ª‹ºöq?‘¿â½ððE_PÐм™Q˜{ÂÓ •Ó…cð¡0è^ÀA•(wžÉò8vLHÖÃ{c€1d•Ç63K%½bY'`‡¿fÌs*ž Þ{?I Û +€›O+A1#l¦Ä9^ÅÌˇ"×<'› U'gÒ G Ù³]$~ñ–•Çë¸ô/ß_$ÄÒã«O©ÿ±oL BçÜ[ÔÉ1kŠB6ÏeQ–³­Bô ÅÂiì.(SñF+l6qFæVRC¸i×lð¹­è/ï2°ðöŠÌ¥\ªè'dA<ˆ†»ÞAss2(s_loóBé†ÄUÚo™cQÃX¢pô s¨LuÅOòp(²Ô©Áz.,‹Kr;ßî IMŠHnM¹s4¹(Æ4ƒ”™ixUD[OVýi·õ?©OÉÅ[¶ÙMüÈæ%§NT'TZ¨)»Ä{¥¨%7ñ£šyøŸî|$¡O/ Ûècèp©˜w6d#3$kT«Sâ¤!)îR(¸'…o\FO"{[`´XÞÆ4iV±æM.Ó@LÙßp£¢Q˜£"—];žÚX_\³ 9ºùþâ˜7¿}PžiºÁmÌm!a³ïãqÁ¿ˆ…š}R¯,"§ƒ;Ûb^¬Dú3ip'rO9=*ÌÑ✤©9‚=–ÕŒ3¨y„¸<„Z·”³T_ÌQf×€˜5²ŽÓ£¼âØ4š¢íM±¹#¶ ±1Ú…J‘^<¨S‘)È£ÉáÕÃg#nTtQÙ¦™W¾:†eõùŠë¥¥)‰ïŠš7ÆŒŽŸ°½[N6NÌõæ¸ìO»­ÿE#®1U®¢é8™i$CÄ[O…ì™S¼ò2e³IýÔ¨¡ƒäËì>™Fbe»î˜àÞgƒ©`à” íJœf=sií¥º,(&!.ðpÒ]˜— æ´LÌ®ed…—Ö1¼3.ûXÙ÷´‰å³cˆÊd g²ªû°\Ø7»ŠF¸sê‹‘§<‹èé´¬äÅhD&ý˜ó² 39>ˆmFS{S¶ñÙ¼œ±˜ eØãK! a†ÈjŠ6¡DW´‰ïÝkÐø—ó*¹ À{4âÔ¯A?tg˜èžT5ÊÙ'ò.ÉÛ¨óa*_oúJ#æôB'Û[E?¶ØÓœ ¹øT96†E$HÑ}N2Œ‘Q8&ùì +ýÀ¶„¦¦ê·å¬7Þ¨Ja3’{˜~œpïlª´.Ôå‰5¶”_{+G‹ïdèM¢(³ÓÓÀaÏ> ¼öY Q%–ÿi7ø¿`¸u™Ëf¤Ïë³arr[ö^±s±²ÏiÚÁ^’<(&a¸ö mF\ Õ&žò‚³Ÿ$Kð b&}¯½$OöϨÞåÄbVŒp« `9§ {¡fàaû¤†:BÝ:б¿Ò»bv½3Uƒì ôÄd£ù;×,K#óòøÞ»Õ8݈páœÑ‹‡LŠŽpÔá¾0³Ã NÈ!÷¾²šjeGBu+lOžu2ì s¶/g+G»Û—|›³·gˆP^CËê܉°ðœÑ½&ÿ2¥+d ߸t¡É…εÝéG7:ï™#Ýÿðº®tþü œé”HoâNëù:Ô]Ã=âTÇÞÈ­NF9s¬ãg®už®7q®ã¯í^ç÷ž8ØýÄ\ì¼þÄÉNú‰› ýúŽö—îü—õÉâ]ΜíÜ™×v·ûJî¾R—;÷û5îøík»Ýù™gŽwgÙ£ëÝYöè|çÎÜï\â×wÀ?ñv0á' ï[Ïëc ÷Ë;Ü^ +nwn7ˆ¾·üJþòŽy +ã×¼Cßkç<ȯëžÇoßÀAïotpÑÝž9é×\»é/î´sÔóã^ÛUÿÌö强ö*gîú•üº{.֙˞kræ´ÇÞÀm7~mǽÛ×®{çÙƒóþâòûþ’ž÷ÿõ]øO¼Ý”-Gü¿Zœ»ö©^Û¹OpæÞçÎüò_ÛÅOó&N~~ð‰›Ÿ/væèçÎ\ýüÙ³ßûõÝý/eÂ/ëv_•ï<8@)ýáj‹³ÿp"˜ˆâµƒTz¯&p½t ¸ö>„ +H? ðgá_í×¼”¿¬G™øõ$hàhóµÃ¾^‡Àég¡÷¿¾vð€÷MÂüⳂsñ1„À?œx§³0Â\ì× $<ñÆ?nS}ðØcÞûBÆC þÝÄ{?ùä£OoÞþů^üø—¿ü·O>ÿ™¿À³8`‹ 2êú’ý’åæ½ïüú×ö—ß~òðÉgŸò[§‡IÿÍG¿ýèÅ¿mÿÁg¿úüW}ú«ÿë“_Ìϼy»ø?/ùö·ñë?¹Iïß|÷—¿üäáóÝš•íç¼èù>û·Ï?úìá“çïôùGÏðþó}ô›ëk¾ýƒñü»ÿû“‡ßá)—¿¸ +ÐmÕ i_¥ð¯o–4‚qêÅ‘/ ‡H£XQ¿M¼%EÏñÖ¦ÐY& ´I€ª®¬¦óû ÓÅÈÈŒšFZÔ¶7»µùÛ¨. ˜´¨®ó VÔÃAžQá?S¬#T€Wc¹.~K¬:£Œ±¿.{r"gtN£gCŠÙT%†5¼ÁqÒlo@· ÊŸ!~%¯3†6cdÀÂiô#¬ž)€ê€òµg(Â2Yar®£äP$Š˜F’f5¡ø}´ü·ê|XØ,f5J(Yh‰ªÛ„F€<…v,ê9N ¿eã Gá|áÛTCŠî–£™ ú4X­-Mv-Zq&+^z¡¨j|φ—QѬ!%'©Ä´ †,Gý3¶½ ~hWÃ`p‰ÄæÕMx©äuQh¶¨0¨ìDô©Þ€%A¦¸Á' Lg*ª +¿R­ JÖ×ÄâóåÂè}L9cËFÔÚỖ$ mj9GYªY¼lŸdß.r•À¥7@šMq2öà…ÌG š$¬$^™-ÖP¸Ä˜ +?»^¢!ʬ3¬ÁMœH + .¯y†A…>ÜXhŽm³çåV¸›—'¶W§„¯Nâ~–,NNJÎs8ŠƒA]‚q¬ÜÎ q¬iÌÓÌÃT³~›Çh]Ï¥…áC–™Œ$y¨’_ÁùeøÜR|`8_°¨ýæ‰ì¹g³u}¹nø‚/7Zç?Ä.WÌ„…ã)8=+‡C…í<9}ggôp˜ùÛ“S"®ez”5'éTtȸ3Ix™ä££l=‘ÀIílt-ÑOäþµzÀ/O´È‰®92ÆãLtd8“Î<áß#£» +»>'çæxÀ¨ÃŽ'ñä¼Î5~zrþO¤Ä©89ŠSÙtb®JÒîT&^ÊÎùÓk{"‰"ûAo|%Û +àDQÜ=®TÎôϹ¦:Uj(ÀÇ”å•ì¹÷.3ïC¬UŸÃ˜1²£h¬V¬Å:€ ÊíÁ§í jóçeà<$÷‡#RÖõ½b|{õE¢†V5 Ƈ3j²šÝ-èÀ¦¹Hê#—¢äREä( ZŽìÊ£O±A)™1©Û[F¶T˜¾ #—¦8‚>8£o3Øo ƒl +Yëv dZr-‰![$ûõ™Ý÷<'ʢ̷¢ãáRVÜ┣ÄA2›-ŠOS‚ÝËÞ#‹OÉ×þÛFÅ8f„°l»@Ø#ù-qÆ¡˜}Ð+wtË W²á,ë­PÀ¹©X{0ç±ðs‘SÃA÷˜~‰í¸×Ê>OÎÙ›‘-ÈZÓµ>ù‘Ù +ýÀ‹„O½— Pì¥pD¨¼ ìvÍñäÁé˜Ök5E–[ª†wâ)l‡³Â^„`És˜Ø µ,ŠÌrMØîµŒARд~jñÙôlœ†çP õ-¥³6@R41`K?Go*æÆ6Ò§ÌßJ7A(Á}¦èC¯’^5xf2š ÊL1Ǹ +ßYì—7Jù™–©»GŠ\Ž(¤éÊF—`ùˆ`‡” ìùÐÛ.¹°®š`ŠD;YÅ8‡ ÇÛ»‹ù4p.ǧ ÆLͨ®¥8¤ÊóÀêHø¡S»%¿.KuÒ¥Îû/Al 'l ÒØÍ¿Ìt¢Ú¢ã…S‚&†Hm*áv~Ð j®ò*@÷šfž`AiW'òËaÙ³ßkU'øUBo;ì•ÁU­‘)°á-¿ºÈM1e=´ªÍ ] 3§ì%ü ½DØGÅ©ŠAÀÀ KÆf{ðÄo/òEô–©OƱ&í3Ç0鈴¸H +endstream endobj 64 0 obj <>stream +ÍJ©c×õ9û;He»mìÞà𙚳ýLÅh:ÛÅà]AbàÑHèÁ níðÌ2ÁÇ:«L„s)èÔ±ýÞ®³ ,Î&ƒá”?P Õþ!jÜlu1`j$V‡Tl¯)¸ ¦‰:2ƒRCÐé +ÍX׈DŒ4Ô ­L Ûúøc;…;ë_¹ÑÓº +¢q© $b›=¦8' lRô˜$4„ ²-·„ö@ŠŸ1Yõ€†${Ù¬fÉBeì0Œ½€ +ì.Åíàƒ?‡R#ÉÅu!÷[·‰ ¢v‘¶ …Æð¤6]ç™èqàE¢’(®óP‹r;s8Ÿqa|¬Úòx£‰ –d‘€löx_¬c•‰h±"¿+¨})NMèJu&t¾„¹y”BK¬³ç<òJç¯üTб“59®Üq‰É'{q²c×;{'ž8pÀ‘MìÄŸžðÝ9Ï™øŒÛgâxx(ÈŽ§ìä,íƒPõõé>‘Yñ T}-SN$ÏAB˱ƒ¸£ ;ÊÅéy³w;®äñQh…ûŒök-p¢+ŽJåNùZûUÔ#ªìDç]ëÅ£ú|ê=èÙSm|¥¶ùÛ£~?‚€#X ;‚Š#ò8B”»ÇáÌôYíL¤ ³õ0Ä Gмx ½=ôN1aMêÅwîÍÍ‹Zæ `u™Ü’ùŠ<÷âŽÌóŠpë0ñ/SH˜éŒ£é,BËú!Û(6OyâšÒ£Ín‡Å¬#’ze6)Æ)Ì9…¸—LeɰðÐŽ3i¿eã{²FóÚOrØŸI]L¡ )rOTuÁŒœVCɆ¤·¨»c lˉùÔKÓ!ͧà;?¡‹,Hð„É‹Ð8ïP~é²!»&/À5­|}3*…à'’ÉøpF)ó†b¢ åQnnSrŒ” $%Nàe8y qí¦äUεZ`æG÷?ê8*OôqsòÌô<5SO-ÚGŒß97T¶¡ÿT¯o-¥g@Ò•)bÐ)’0rÄÖÎÙCa}lmaV®ÜÜÌY#e@ØD6™¢‹´-‹_©c˪Ÿ :`Lã0(ƒ +ï±ÔæòjN´Ç /˜< 9¡Œ3+‰Õ’d]Ò `²t^]‹z›B¥*Ë¡°g,Ô Ž”>+ S#C»ÎlÈåf¤æÇƒoü°cE™œ¢®SJ'”‘,½)vN1"N€£»Åá'šÝÿ\Lª¿ ¥„)J~¬Ò‡!Ãì8àHo Sºú Ÿ®'70ái 7³o«&¾ÃE€ì®g‰ÖíøÑ°‚¯°e'¢ÊNaÞ’½1êÌXÐ’ˆ£ìÔ ß€ëA¡Çý=ë}è Ú”ò5"&ˆÐ1:šØšô€_šÇ­œyÂïÐlÓÞŒ“E¥*k€JLã59Ù—·)ò­ÐÜ5ˆ“x +ïÖUß“‚á3 +ÏÝ›¥Š£‹ã’\¼ ϹåÔºþM¦%3õ)l§˜‘›5-•îUfRCX@¯Ôö‚ÏáVNxf5ÇMkˆ#F•$¯ŸxÆÎ‹¨á€B¼ÅPCYœc&ˆ¡§ {V#g^Wa=ÐÏtñ¤ˆL#a˜÷ãH—.‘Zy󓢊®,P£a ¶ot°0c¤¡ýº`zk ~‘k–“7áÍ\ó¡q’CD;{h¸id\!zú>vYþPÀ-!&DMä'NsËv™€LY²PƒÉŠgçed¯ _·`âÝñó1E|°2¾‡î]x'1¥÷SC¡w—C }¡¡q¦;-ôØ.`Î]÷ Ì“è°­û‡ÚéF2‡œÑ]… ¤aDt>Þ­)yíÀ1º‡Ä¡–yƜ™%,(£™/¼\Ž93‘JÜ‚JÈœ'¿JcÖ\žCÏ2ÀÜô¥:ßqD%Êâ*Ù¢7%4u‘ÖæhxÚgháMÅ–²R?’Ôööûlg‚ù¤í¬L~ž£8Œ ZPòdz6º½{âà‡¡#Ùð7ü°M'èâ=gYêxreÄ¡5}IÇ=% X°PX(žC[Õr7 L\j?‹* {ÀºAæÖÅ­ºÄ*E —)Š+˜øòàÛ‘Ùî‚HãôpŒíbª(Õ”Û rŸæ‹ZÍöè³½@4î­7ng¿·ýÍÙd÷¦Úó”¨Uã+ÂþÕ ûƒŒyÁ­¾–DGiu"ÓŽ’ïD:žËÐkI{Æg2ûD²¥ÿ™’8ê’}sPK`‘ƒö:j¸£"‹ôåQ§U/¸ä ¡Zü¸ÿ1Ê5C™Ä»fº#[^ó.ÁÁgàxRîÐÀýú@ÝñlÞQ._áÃ!?“Gq"TNeÏQDÅØ#ÒîZ(ç©|=ˆá£¨>èG±Ð ×êã2ò¨d®ÑA_=PÑÕÚµê;hHüð¨HÊö “ïÑÞ§zþœb‡ÇPÆ%ù”´kÐr6§øç“ŽPê paÙº!¼#íÚ>! +[ž#=\~¼¬‘èÓÖ(A‚-+Œ}9OeS¨aöRsÇ…òp[c­œŽlÑrÓ£€ü ¤ ¡CF”$Í«ÚÆçŽîšžS@©<041C„'¿‡C +P³ ‰,ƒütYæé:Ù»¬Òä×Ï|!æ\ð©8€A̸¨œ¨lVÉ&ÂúVPÿаMª“Ï‚2IP,yHùÎ0\[ºt4¶&aì+“ë–¦<€EzÊP³K ©L0·!.´¡Ua àÀÀ¨’]&´2×3¢¥ç£ ŠS‰Sصã“¢‹œPÔH£ÌÐ $yÃXkAd—ª’{ª¢pH¥ý°-Þ•r3Hc¿PèÍnsª*WPÑ<üçÌ‘j¥7}bAº·ü݃&´ÞQØ÷’Š ù¾S”9Ü,ŠäÕÇ“û´0CFÎk<ƒó„^Óš€uböJ¡.¦² G5¤^1±: À2Á,¢æƒXj¡Ò¨æíÁ!(ÂaØôÞý·ÝäýÍð žÀÁX¬áÜb4´‰16M‹œòÑÑG­Yøj­y‡ÁEÉI¥ ¬[N¢-RB¹/¹+@bÜù²ä‰ÓÂÆÑËym–‹zÊ*3vøÓ™gV"FFGÌ Es"I ¼:¦âà—È +LQ]8²3¬õÒ8W¬G`S’µøË4%=üµéNðæ*[5@䢲HI|Œ&ºø.H0¨úÐÄNt,MYµ}€ˆ!Ná‡&GÒ“KäF"R¨µˆP=ˆ!Ÿ0å NMÉúV ¡:\›L¦êsÊ•ÞGµchL“^2‰C¯€£½äþ˜5®ÄF o?UêòÖ€¡)c¦3ti‡]xÊâÀ±i<œ ÖYeøäx’2b7ÒL^‚¹‘oœ +G3:Y!ÝXÖ=íç€÷Zìœ@gÙ|Uq±D—n˜rE0øÖàNž_ˆv4Ö,°5Smí]•5Û7àœø;xkÕlZ'O@›Ù‚¦«×ƒë9ÖOb^’¶£H»÷EF0‰ì3f‰ªzU*‚´ÐÙêJnO±[g ‚í«Xú¯:q±lQãºË)‡1y«Äî#…8ˆ›å±¦N9è_¹x„g 2ØEö….A0 ìž‘K)£·³šš±¸dât"®Tõ2JPcØKÅ»•An+y)Óq?œ$‚›äîDáp±®ç5·áä&÷˜‰÷*%¯B‡P_NüšŠŒ˜³Xq RªÅ»áGožFÿJå‰ S¡& ¸Äc”Nz«¶0¥%Å¿;-š÷¦=¨‡WwƒÆcªåü1¿ÒÕëêw¸þΓÕ8,› ²ÃúžìÂa»ü@öõd÷lâ,và§S®;aÏ>>ãöÓSqrzNÎØùa<9µ'gû\œH‹£H9='2ê(Éïhwr…Nð8â”òœ9žSlt¢NÐÖ5";Åm'ðÅ#¨,3þG€ŽB#ÎxÕ1;«œ T¡E°?R›–“!ìDbpäÙr’¤º¨ý©§²ÒÛæƒ¶9xÚÞdÂE™Rñ˜ù\X¥Ø"BËŒ@¾*D +’ɇG)±ÑÐ&h Q×X½æ:õ5ž„ÒÓ®æIáeöÂQr9Û ‘ £)™3yûœ5Z„tpÆ×u!º¢°coÁГÒáÁ¯8Ýó,ÙE¨'k1¹}+›ÃG¹Fº¦jÉhëå襲iÆü9z(]åtìuF‡*’.“C[”ì¬XS òr¿¢%1e“ ÀÈ“&ê†LD§›¸¶/Åtiƒž"±¡6%,‹0øÛæ-¿M˜0B¦t­"l)ÂPN=ËkÝâ¨ëScc +Ä^)÷´a(wØ? óª}ús™i:¨IñŽ”Yqx´VX fÈ|:“èg{w†öSˆ³á…Çg"³`ÚL¸WU,¨¬gÿÔ¿;.n\ fÛ³1;# ìØ` +9tA¬¶6ÒA?DhdÒà dÊíR¦©•Yw=‹ËÍòŠ;%1¬œ¢‚ŒþÂ"W_Ñ{š 3[‘˜kœš5 eÆ’Ù(5!#Fg8B-òŒfyMO—é|9OÖüjsü§‡]<ÙëS8/žpÏ ]1£ÿö„k¬}rNÎÊÙ‰:½ ^ѳs|8𞌔 ùq-g¼úçJI­ƒx»{\žŠÍs{.OåöAĪ7¸Ögã ZîTdu¥NµÔ•:ó_ôÞ‰v<¨Ñ;Õk]ëÛ­üˆú>Õó'hà6œà‹rWNpÍ ú9‡IG8uÀ\§àìÅa½($H?¢ÇŒy£ŽÒ¯Që ¶=‚`üö-Ÿ`ê#ø~ P¿V ûòAŒ/Xe©­®÷`°Í¡»‡é¯hïœ1HIàì³V-z4N˜ÍÅÚt—A™°.ùø$’Ø¡M)å›ÉgàñTôœaxM“Ö¨e×L ÏœY≿eM,f?Ï×e%-™2¦†¤ gó8“q‡Ù»´$áÕœfn˜K†´•â»Õ[)³áÉZgÙ\âÚH¤Â&ýTÅl[H‰‰ìÂ"Ž‚ùŒh1£³‡Ò¬±ihwÑ•É2lÕSe#Eöaó.?Ü¢85tð¡/ø-«ÇÙ›º³4¶EÉ/ËÔÅPÙͯ<å“áèå¦ä:Šu‰(F\Oîï‰Û¦šI3 Rýžè (©M'g)SGGþ@ꈲ´ü@ÂmŠú>PzñTuzqý§•$}ÕOs˜ÒL`!zf)5¶ùSÕ{’ +0H›³¶«ñZ¬ÿØõ”ä$—¶œ+FݲÊdŽê€"_8œƒþžêE韵xØÎ²SðSR°òÔ(àéZc(ã˜å†rÁÏŠ )$¹M£êXÑF9±H95§y˜j¶xOk\QìLJX>ZàH¡ã àÊÝe 1-Êø¾—€P~<äfŸ,ôfC5oècêmsÓuGÖ4w<‰»®c°hNÔñÁ‹Ž›¦º¹;Ô;u%Ï|®Ã{|Ôác•ø…=$‚ú=ûûCh74? Û0ÆÓ #ZoUåàeyAb·|ù¸À"f•ôæð‰áÞ;Á§2·p¬Q* cf9^Nm +ÚLð® b†hªòÛY{­45*³Ò¸73óYöÞ—„eî,)éº5@B µyw6IŹɨ‰ú¤Rƒ¦*HR«}õøEÅü·¡Nå“XõYú >ùR–âoc ÓÔࣺéMॗùvìÇ͉RºûÊœ{èæ¾TÈ”/ÔÔN!òuÑîÕ£*z¤Ï£€÷ºvfDêžO½Ÿ#ÝÓ”Mì{Õ‘žªt„†@kgÉ)Á†,/h$tÇðté¨XC@?Ž7#`dSJôx€Œ+ð¢ÿT­­ÚèŸÚY=Ä×öS5´” HyuØ„MáYÖ^ ÇYð°ôâ-ÝTÞÌs—ü±Ð¬J2© +l=˜ÇLöE$vT…=<ýWUOIÙ©=°óà´øTJQôØæ&øX«Në¤쌲xªZ«c>·y—T´ª$©'´$g'ÑÚ½ê"´­áæ4fBÁ }_“G-B ÞFŒÝȲÑtöÛÔnMfï·)¸¨HBðH•E Ío-’âš‘¨žé㬲ÈQ)ìhgM 0÷ ûÛ[¤!„¢^¾ñ4*ÞêÓ8”·îîQd?(ÊΤô§à8)-4BSŸ:âNÙ‹-JGÕ9’¤eNᦷô=öfJÏA–r©ëŠAkˆ—ÚˆzÂ|ç9Oè(«w*"FD8ˆ,z=ÐPçu8Cf¶?Ýâ¾í±2GSàOè|ŠŠ lxlÉëÜ ”øÌdoƒ%Þnº¸é©r}Dý•tb$¦ïß ”%¡'@ EA +CMì¼?¦[ϬQÉ( !KŠbm a¾HÞXÎÖŸ +“š’ᵉ–[#ejP¯0äéót¶wl:!E–¦´p©RÕu1äm;"Iq4ÞëÎŽcYriÆÎ’H¥ðŽ<^˜p‰üîYpbÆqc_ORZ\I?¨£³ò@þoÚÞ®Õ–åÈ}è?ìC7\©+³òÓ~Ó\hØÆøÁØo¦™mÜ‚}Ô¸­ûàk|D­µ+sër[ ¤sB³æªY•1Æ⨰W³ÎæÞyKIÛ»¤•rƒ$ÎàL)ÎPœÚö;t㯔ø>¬©Æ~ií—ávÅ.Kû‡n`Ù›}²l¨—šÇÆÛíÎe;±xî÷WXÝÇKOgñ3‹7Úø¬½cÛx¿½›ÜøÓÕén}óƇ?ý> l#Ç&¾ìÑ&b­qm €LHÖH¹‰§KÜ}«ØðstÞDð5Ô¿Õq]r‚5sXSŒ_IG–Ô凎ùg“í¦MfµÉ¿ö‰Ú&£Ûä}Ûüp“G®Ùæ>-½kzkõê—} ›ZoÆ9$ÏÄX¢lÊJïíb±ÏX䕲 ûÂ=úÑž}Ƚü½v1¤Ø¨ Lj]WEè‚™R`†×Бyhš¤/-]‡VB:}z3Î:ì‚\“@7¤zàC3þ5…=iÌtŠY-N0¬CXS9ýˆ¯)Ég©²/Â2LÖ#†©†äsõ´Z' Þ³ÊX*Ð2Ù¤±G0¶óôç8Á›JӢγjšmb]Žæ™‹ç Ê +*2Η`>jr³ÍGѰFúÁ wó÷p€€"85.’pöKv²lg²ä¥6µüÑô!èØ/R&)@®0L±ï©©(~!ÿ ‚ú Îê±7v-º„ð»þ@¾ej.ï%e6A ‘Áׄk\êqÞÝaÛÔ˜¶å¨}éj_åÚÄΨQª ©©_]ÅWö–­BV ]ë% ·$®ÿx`d@Ü”æ4YÄx/×cñ`¼½í[÷Õ¦˜û/µ%úM÷g“Zjú6bËó7ɸ‰úÚ¥IÇšôR‡ÙÃÅ8– )—HYªçSæ‘Oc ^NezÙƒÚh‚&Öõ9¡­Ä§Žt_«.,;‰­êÚ¤®L'ÔTPb«Å@QNûtD&gÄêAWêl¦óPD ª/ÔÔò}­FŒÑŠ­DÓÙâƒHî`r‹ú1ãü`ÎzæpNmWsœ“€~Hk4rnà~RƇlýË¡¼"ø>ïh¦ÂFª¬RàÚørëìNtõõ7CrÄšš¸ T¹Ñ¸ºÎ 8â|ÁP«©bÆB@Ú˜“ˆhùÝj‡åáFÊü X™³Wêô5jFI>‡}ÈØW–Å]É7îŽ ‰ŠK;Õ¢—¼}‡ŠÔ†1?CIηt†IÍÁïÃJ±° „]d +“˜“Òµj‘Œ¨ Ú^5È Ì 0N†ü½ÁŒGœ_5!åÔ +ÿ¡e!âÐP°$»Lz9l£–$†ñ±Eô¯P]¤an¦u÷§§Ý¦Ã _Ê—ž­™ùçi‚Ôg$Ö_g_\Âx,Á9 Ì$ß¿ªË Ü+KDMóçs¼aþTi|Zá/18¨a åNRÊÀ¨RG¦˜ŽÁÍX,Y©±¾ØUSн`$´”¿·Äñ¶·ø¨8[зì8÷ÿˆ{äd…_Ê ¥#š"^E× xçZk—:ë• kG +@CÅ%è6*­ù³˜-¡‘°0ñ¨‡¸Ë䬩â1¡"ÂAÂ$_¦ÓG+¨‘…#dG½Å^pIIL’zêÇü’Õß¼þrí±çžýEò7?ïìu÷oÄâJVo³óI«çZ½ÛÖ ®¾rõ§¿ûÚúh/‘åᮯ`ÿ®v/uóê¿X"ËRÚ,¸íÊÜ,áÝB_vÄë×vϲÑv;r»s·[|qv|?ûŒ­cÙ{ «Ú8´¯<ßâ"7Žtïq7®ùá¾/¿ÿs,€ÓÏc)ÛгF¨5ŠmƒÝ׸¹ ¯k^#õп ýOó‰/Gñ3FÕ<=¤ë*štê¦LsîT[Ác¸Òëo„1j@°×>¦RÒ‰d«(ÛME%´ÈQRì%A·jP!|ËiñÀ$™mL«")´ÖO×±¤,Or;o~>PJâ¦âQ‹®}z;. + +IGñÏæ¬£ëéQ¬_ãÞ¦öýw>Ò¤AZý÷vÓ:±º8íÍFù¢º_ÏL°²hq’Z·®ª*Jx°ÞÒ…ó’85©7¹Æñd߸VwË¡‘TÆ„áîã¡K5{;Óˆ”£¹r|¬Ããìøƒ¬eá%5‹‹Ã7s,ñˆàf¯¯$¦J¬þr]‡˜µóF¤êo!!3æ@ÃÃ]ÂÃÍÍC]¹ž¢L†ÉN‡ÕÜè4Ð&Â}øŠ.%y²—Æ´Ÿá¸ç·8MÂQÁ!±F–/Á@•d©.—'Á?ÄWkµcÅKX žž#CǰB|xSEy_F£Šô 5­ g»n•¢+yi5².‘œé§!)f¬Ë”ˆ¯©DŠEý'ƃžD¢EÑ_¢ø¨Í'cQ*â'‹h´|²’»‡pUB >Wúqˆ ]!uHúëÔ²UUaÈ‹™àÔY‘Š2›æ +"‚rÞå$…Ž’w·ä_ód®|[±ù)ABRÀåħà©oX4ÞqHrŠhô`Gl\Ø_ <ÂÁÛrÌ“L6`'{L^Àà­*¢&H§¢Ÿ;Éïü¤tGVcµ!/éù0*¢rþ­†*2âáSH2¸±Qî[ŒÎ„ˆ»”3²¢{?Èö͆$V°ñ†ù{ÉguÉ *EtžðIeå—sòÞ*¿¸°5åÏ +þ—ÛËœ @6, +«1²â%1ÍF8é£e)œÃJ€2Fá\Rø(Ži¤yòBÈþ¿©nhÙû3”Æbr€$È©ùJÐ 6Œ%ÕÀIÈk¡ÝJù XH¤¼³bNH¢1!¼vJ8™B I¸tÜ)·²ÂÈé.(+¾èR©Ý€_Èa?ÚîÒõà\É.Hº®±±³Â$Ðtx²ûýc0Ìçu†º®&-ÙN+¬âÎn€µò£HR|“n,`!@/Ò#_Ez«vò†šìP¦·ÀšÇVÁ‹9#q-SÆjgcMÌäyjøŠ<¼Pð Y5HîHUB´¡ê/=Ôtª^s;r°~ÏÚüw+Ä„wà1 ªÏ\ù÷eáþ`W4ßÃyó»bB°çx\¨3Mœ&ò¢>« +5E®'Ž¢´’W€”S±{ërf£žÃ„˜yÀ§5UÅ¿ò—à +V÷óËþûöx{‹ËÑŽ}üæÍsÙ>¾å)¯obû¾Ö·ú|ñÛå±YEëJ[$Vé²th`ÁÏ+|ÙÛ­²î¨u×m7纇—m¾u«ÏXýÊê~¾ðS«CûA™™‡ß[\ãÖ®~võÅ[—½zöÕûoƒÄKÖx³†%ŪŸã×¹›Ÿ£Ü&næWw±w¢×H¾FûmRðLÖìbÉA^_'+kZÇÆç¡è—/Oxȶ£äszJŸÒñ×(ï’¢[Ž3\üQ ÝH +ÉXë'ëd jžø©w`Ð'côZU¢j=Ô±˜3ºž‘9¦Ýú㜲sÝÁdb¤¤75Râ%édN²;.'‚;=4ÔéÔü¡l¡g¢øõÃhœÝA°»‘E7 @Æá89 ®¨Ò:§=1+ojÓ +2^q¼Ç;'ÃÛ¬KFÕO¿ëêfb7V·ûh°©_uŽL…Ã<èÑ(öîöG•Xl•N45¦|£9;³GöFb¶®ÐöÔ²;ßlBÛCÓþxu¸ËKã”)ªÍÞ›|0 úémO¶º“¦á»ÞTœUëþ‚0•VâôDŒ š6`×È1Ì»/‡òqÏÛcÓ&†EÂ’!â[ ‘ßüL†%¦}ç}Õ"}ϸÃ,ÀË[@Ž[ÂYÃ¥qyh}} +½Äj’c¸ožTÙf¿Þ,,°V4•ãm&4tOn<ÌëA„.vYg²…â ÕÛ ÅJ]ÈÀª“_*Ìb¬[²€}òî£= HoÞªËT6ÕírÐ=»RÀN?6BL›cÜiX‡4²ÇGUk[˜Ùp|8üÏ‘K%çR<æýãµG¾ýÍß~û¯ÿ%Ž?7’™D¥šÌŠŠY•ÍÎsJ‹ ÉJ'ÂZUˆø¨ŽvýN®¿k¨Ã{ðcû½×þÓosÝÆŸ~û›ÿôÛßü›ÿöwø—?ÿû?¾ÿüÇþÓ?üËÿþöoaËßþîïÿôço󇿿¶ðþôç?þáÇÿáýñOÿã?ü÷?ÿÓ?ÿãß~û¿ð©‡ÿÒOI÷OY~îÿù\ éÿä#5Mz:ÿñ_ã„}+R^žvRo”g¬·_TâVáÔ  EØ`'²á²”Ö(,äÞ­‹¶ôæˆaäUÌ1kàV7Ž99¬–Þ6Eþª¢%è:€yàIl F-¢’„^·"dk"\¾é°<]œ”ßkŸpœ+ŠÙä9Kc± jKÆaŒœª¬ùª†j(«"ÝdÌ~D x]NUÜ·Ðýí¾hç#)ss™BÓm +6åH;é2M(#Gã`ÿ½ÉwºÿsÖ¢£4ŠÉRì! +é‰oxVKëâšá¸Ž,}¼_ÉÑLÂÃB™³ª/ôÎŒ Eé]À†ÖbZ,ˆ³­Å¹ƒ•O©câM¹]ÖÅÛk"Â?´úûø"/ÆL‰#ЈÚ.ˆxªLÁB:ãÞÑBùÑÓámlgàÇ`×°å» •4­Ö¾cœ'ç,Û”²_)¨f¼ ^Åi•Ê©*¬ªý¨ü‚3Vš_4ž((Yîë¡k! yHNÂyUA=•é³\2YYHæx!HL£›ãM Y¾,î\²r<|]SMú +@º¯ä RlñMrÁÈZßøƒšF€³N¸¯;lqÎ0êÿ:3s¶’:hõаH(µž„ÑÇÅ‚Oe[È`€:ÍÞ“ðÙ£O:ñäÝHŒY¼MáðW—þ '•r Ncþ*©Yö 8Kv8ÿ><¤¤[–¶³œ¦:Ó§¬¿'•kC /SÒÔ`êŒÅì>èÃraÁL×5?R³é3ÔrnÄ–Ê<Æ¿qFQ–pÂuä8-&«±Û܇÷*ú#è$2k‘rC=î…Ê €¢œbRéÂeöSýz^w`í¤ËƼ£+ö"‡ñ#Dc–v ³bž>B¤×ˆË¤]€š;l.„ð' ²ÈÀfœô‘b\šðÔÛ¸ò9­±˜y¶::9@ êçÙé‰êþ/²êˆ¹ðé P=ãPE47g°01}~I…X}eܨ‘g޼K‘–ƒLÔ¾3ž†ÕÏ2Æ©…4ÜÁ@¥ÓÉMã\cžžb~«õê1)D4B¿S¥¨‘ˆA›^¢T·8Ì\_ÒHÑ:âOPž ú0>;ÃÔg +jF$÷8*àsô‹P¼>ÏÄ>ŒR´@=l˜,»>Jáú.i±Æi`–ÎuNø­LŽþ2}(šàœ©€QµHe%‹ÊÙï3RÞÃ…Nð¢Òô&˜’ +’-¡¼¬ÃM|Œ,˜Ô¯•)Î( ‘•£3æË[·‚•ôG­nžs”(a„ë§h‰%y+”ÇMJãøS£¨€±8ì)²^;.'äêà ÚÐHP¥cÑ%ë~L)º¬âÎSóK’ÆKâÄAé61ø^“4„r²,ƒê<”ñ„¤ +[eTø­CsEFŸ®ÝZ—áÍ(@q4Lò.RŸÇs‚I³+Ñ£ÉÖ÷‡õ¨¡Àu›4¢æ;dªG-÷vÞ×véc”$˜Ã3¯O…z˜ÎjŸmÖû÷j~¢ä±{ +¥§wœÀöCVOØó.S÷cDÊm Úäò=Ý-!IÑ™‹¯¦M¦Óå¬C‡ ˜êˆbãô\/”>“„äÇÌòïqá­i—{|†Ñàei&KãVi:Q_©D­•E? +'¨˜&ø‘—„,bi5 ‰:$U9³è(“t«!œ‡kZ !žþªATÖ‘#m¤ÂBº¦LÅSw`Õ Ö1-ý0bLš´W›mwxƒ¯5N)°Åg‰ê0ºËÔ¯PZÃܼÏb>ze"þ]ÒBÑhÔEÿ¡Ý¬eA YÀl2•«\ý¿¼$j垤ʽT¢f0[Ñh:¾Ç’oPÐèôe"?©îgºµÆoDI þ’r4R+8 A%ªJ–½Æ1œjû´Rç]­hJLP‰ú1r@ÓEdÃU±ÔxùÊ#·Ò™Szaç7•>%Wô‘áPÕ}Æd–Y9u‰HÅ(èM‚ºNꆰ5+qpN(-ha•êÜK–ëlÁ.¤š~°g÷W `õͺ…?8·:vÏô÷Ó¶.IZÆ·–tøË›Ç´ Á#!äFñЂV" >*gÃr„{¯åT«@å ®ö40CbLР17pZ¼ÛéACüvÐÊZ0‹ò·bˆåy?.Îj˜ó:­üA§Zc¸‘–G»=µÅ8ºN¸ë@ê‹Üä•`@›T1Ã÷(6°gjq9:õq£Qo•ÂŽ†ED1 +º*¦`Í ðš™Êãk-Mtp¬Zïé@øXR×Jó!:•Hª ‘Y}®já"k»"ô§Ô©&8š3‡ j¾×uè£Uç³H“2-Õ7 +@ø÷D=~tQ³´ÏŸjîС»’tœjÄbD¿«ÛÆ!xõð,ed9‰”y6¤œIi 6pq´Iz(îÍS½ùºß3ÊÙ‡u©‰ÌÍ$]H$ZÒñEÁsBðb”â„Ö¬ÞŸ5Báe‡ ã:$15FJ‡• =sd©–¹©®á)çEÉëJMÎzD¹÷ȕɶû)—€2÷á…¬ìôIÓÖTçh#!ZÔ pþÂ5o=ÁÉ~ÂZÊ¢gÚ>îÞF ô8=™_ó=XuÖͪ¶c˜2»ø…Ò.”¹vm?£­‰gjùý^ï¶8U§ytr#ªñZöÔ†IÑ›/š›Úob(à*¸nÜ +8±ITžDcyºÒ¹6#Nª¼ôÇ}Z¥ˆRùnœèô]Uß¼.Œ§ +ÈŸ¾ézóÊpaqJí¹“ºPpKF:?uvÿ{-“_ä&ÚÂSAZI‘[À…â~·íáü¨Â/°Ký2æ°žÃz‰Ô‘|ï0&£ D˵}3,5U€Èí|óBG>!¼;ï€ÒðÄ/G +¤äŸa Z&g +׶ƤCÔjøsÚЈ”i$G‹CgÑi~†JË9âX«iì3*Æk¡Á½ëµiJ¹¨¥ÁúCVcœaEÉ&ƒÀ …]†rNý Fs„ ¸ÕßxVu]0¼…QÑÞÓlöÄ—íB%©ÐnK©îIÂÔŠ…¦äÜ€v«,&ËL'`2á©=”CÕ ¦nõèÕo¨è¼„òm.¶I=²…|LÊæEÚlí8ˆ0?ýbëŒX”x³›ËDzó2ãBZÔöØÚ’ êÀnñ&!VÞli[Þ ñ>g"[MÏ„eÈrþ–05®øÂ¢lƒoGþKE²i <ÄÒ/}ÕYßwáÿïmŸô—/{ªûþë¾W»ïë®=à^…üt`SoŸW+u›ÐnqúõÖÚOó°•ð¸$ÍÝŠ²˜,uΙpÖKB¥_bh@©Ÿ¾¶Ý„ÿg¢æ^ŠçÓ?®jF¶Â‘ƒ°ØÇ5ƒó?¡&Z¹‹ô‰âŒÈr$‚e­¡^ ¥ò¸ kOQ ãdÎt[ cÙ£E§ÖI.Ž3¸wj‹yüÿ-AìVtUá­ÚÄØ‚ÓŠAÚlé>¥P/vVÖªœ4MÆ!A}©'Âr⤨PŒ¾-å—ZˆðtÎÓ—¶hlàÁÖ¡q)Žø½™o›5+·9>ƃ6©÷ý"c[¿ž! nÑ5aX$Mw«L… †Æ2?8°x9–tùXÊa’GS6s3ÐÓ¨W·½9–=aáx ZªÆ“$™Ü;½6¯.<¦ï½`¿¡À;‚¬Am¯—è'%¹ÁÈ;Dº}&I²%x¸©iª‰Îp06L;@ÃA±Ž™iâol¨‰&‚ Ó†K²þv¢Ìû=“s¸#•à» [@%eø¹èt±"púQucñ’ÅÌûd’㡼—e’زEÒØ‰ô‰.‹” ! hÉ7O e£/ µ*OiAËÑGÏ•³—Á|lÆÏðŽïž:­ü¦?(ms/?˜p£~ØM€Ýr­7“+(V¯¨Ó(CÂâù3Ø59Çe]5ç–$«ë-5rhà¾À®<†;I5kðX»Y”ôă)>.Ò‚¼–†®ƒ'v}®ntQnöƒð3U`‰‘ÚhÊé@®r‰/ØÒHÎM˜é:è ‘ò@ñ®Þ´êYìvr„Žº&Ç=w|¨SÔñ’õï§3íUÏn¸©Qîá̃IÚ1ž¥ŒÌLù¡Š$]F’$ +¿Š°5gõOÚ×®ׇwc"œû]z | M‚§§á¬ø÷óœäÿ`dãŸBºëÃpþiZ®MÛ£fòa¤ˆb7ÊZ ¦`-YøÃÒa,à!ÁV¿ÔóîÏë ’ÐJ'Ò!åÉ:ZˆI[úÒBrZyP[ºÔʪz¯¶ô¬ ‹kez-„0¯ïÏıÚ)vÙÊ@[ˆj*Н|¶•óö ÆùÂ…A÷dÙ-d¼!רè¢á9¾öò©YÖŽLR¨£‰=<ÅÂq hÒ’úü`˜ëü ¤gsè‰B ŠÓîøÔ1›cªT<닌œ%"#€+Âð»To`Ääh =K‚"¦äR`Ðä< « ­+ +¦½–c\WMÂæªE} Ëc¦Xð§²âŸsç—ù~7ÃÕŸSŒgñË­œ:pø>ð‘xV5¡ÔmfTªáþ^âûyrY'ðƒt?ϱC)¼{TNaSUD¯òŽÝ3 LŸp8ÈQ4gé À¤þpo¡{‰îgDVpè~¢N!#¨ûš4%Ê–—È~†{Þ«¸€/ž•røõG¶ŸÕÃa-SpWµpwš$ùK‡ÿuëB¹P#ø5DÌOQûÜFP$ tªðÝŽ·ð–}D¿ Qû¦›²’•„â–˜ùx;‡„@¥–ésÓnrûL-Ñ{ËÄëá«A¤ßqO˜doX—rÜ0rKèÃd:"LÀ(À…™ªøàk ;&]\©#П´ L:ÓĶè[tD³”ÐèMÄ–!Ój%"zfe2¾öŒÇ•ùCÖ…C¹aZ.”Ì—ZOîæ†áù ‚¾´¨¾è†UºÐO½–Ÿ4Օʺ§¼n¸±í–j»áä{Šï† ¼a ï©ÅòJTÞˆ¶L£ i!.½Dyzœv$¨Yê%¢Õ“Uµç^ýÌÑò¥ —kÃøúжá-L³-%mÃ]Û1ÜöT¸ gnìÛ2ð6L½•Ï·'þí‚áŽn¸a%n¸‹{’ㆠ¹áLîÉ•惨¹esîXŸnèžDºa›®”Ô=uuËq]‰°;Âì†Y»£ßîiº;>ï†õ»§¯4â•k¼'%ïØË+ÇyO†Þ±¦WnõŽ‚ý$joØÜOÖ÷Û„ñ•¾ãÿÄ5KJú†·þ ¸¿}¿O&ü–/ÿ Ö¿ÄÓÿ™ƒÿCFÑ/ +:»ŠŸÁÁ„…ë“ .5á /|hÈ%gS¨=Vain$Àe2yê@3yæ¸T*´°²ç“_„b3LçY}'­$vX•­Š œŒ¦éòöú Î#:šwEñ ½”OÿlUúÁAÃo2Sr¦ûÝ‚Ö_è]‘šûs•`]‘“Z«èïžù¾™Á’‡¥® s˜””Ì\Ïy_zÆÚ|ò0¹ÿ"î1‰±wÿ¦Ûûô4pE=nŒSîÕ;#ÓBë§t#|é8½Ckiúªîs;ΡKsIÖ_‹K?@£ŸÓYîðCÌœ7Í …¶;Ðé¾”#Úåi*p÷?™ôˆ?_Úëñi¢hø¼óì~(ÂõR!XØxLöfG,J!³LñÀPH5÷ìònÁ“çqsªó‰äý-Ö0TbQF s÷럴v´°Ã†€Cu7®å:…$Fš@§Ë1еtÁ¦³Šz¦Äò´x,bìL3‚â‚4´¹•TW]I„Ý&m¯i–sèڼͲæ¦+RKÔÅU܉œª8wiöÒÚ¤ÿ=>™èóz|\{ë|”äÛûƒå´æþì`ŽZífqÇG$< ‚Œôù×–{üÔéD³j'²ù]øóåpÉrÚw÷[d¥C½O£¡‡”­ym½›«L“b‰2’y5‡#Å5ëù§¼òX 4u{ýÍÁ¬$$ѸŽg4Uíx7G½ýÖ)©£Ú†2œVì"‰JÿV:û;ë—§WÊLo˜PáÊk9ëÙ¤"<>q,q@¥ Ùè©îCð¦$òr3½«î)Rü©™ƒ°Êƒ<‚9Çší S.í¼/ឣ:Œ÷8Ô #9íž<œÄÖËá/kGK‹új/S-XeGÔœ.jÁ–Ÿ4ÙÙW:2@'êÑÖ°äæñ×?ƒ__’ˆ¿ ïÈÉ"óY­q +4†2%ªC¤³–§P€VqÅŸºRnâŒíC›Ç)p䔚XÑÏûÒÈ’Î=dΉH Æ)Ž\è&@JpÓ¬SF”§¸iAëO*’$gÑd T^‡î¾®ßàØdöüHF9½™µ¸,·u܃!ݱ±òE×{Èàë%}o‡ëÉ”œ¾PQ3’á8îëü ¶é<,9åp}-Ïþ,Ï»Lë.ÜYÏœãr…gÏ)¥[;Ä…P²Dé6æi£šD±‰³aXx#+Pˆ*Õºo#Ša7“šWH÷mÈáÀd$¾Í%_û‰™=ªþ®‡n³RÖ5ñ!òñúRd/²Ù‹’ìLV6÷Y] A¬Ñõ$s±i:((PÞÝÀ47“3³uÀFÙ &O‚‡)u™ŒTE%í:ôŵE©ÚanLšÒqw(aâˆQ5$óµ¡Ó×ÕJ„XÆßÅ$‹u»X°Îv&[P×Fw½xÂ*;@8ÓþÐyÜíúae1M|Ÿ-:J8òžЇ»Ud/;õŒñ¡ET¢“PcsÜà +±4w¶3F@,ÈA†ÂÂYw)=iþ7Ê\îcµL°2ë(j½JíâϹé´0s€ž¬¸¿| +)¤¯ã‘<«ú£?kfp <A’e“š†E­djÅ #–dZœ,Åì>•F:øpÃG‡\…Lõ6gïæ$’ªT ݲªª’“=Lsó“Ñ1™`®|~Òé@!Gw±®v£¾ºZ€‘t#ÃØƒwR¥ª¬œAˆ—.Ä'Ó§G×f7 ¯•u¶éR†™!ëæ¼•1µ¡‰Ó=·t¯hâ½f’Ä1?ðsL ÏjŽ-åf¼ŒÇ¼ 5÷k ª»p¿ +%)°±Ùª§ªÁJÝ@ºÌ½ +Pã€"Ô=ù©nè9 ¾”u\ZSšú’ô#ôl¤¥ÈžJôñÏö SÆó7š€MÃÿç&{ýµ& S\¯ Gë¬JMuN$cÑ ŒHÖM®½‡–ôᓜRvrDúID*EZI=ëÎ9Ьžà‹P^îõ‹wVö‚Q—òr²òµ‡Î;ËCAýòÚgþ '•!œ9ÎêTˆF4g$›|58„8)jlè” î"íH¢ÑO(£`ìꦃ­S634Äò,"*¥DW”ïLçᢩvhˆçpÄv¼4FìCèèZ±çM-<ª†y"dŒa•±õdr8?b¥·Û-à¬p-B ûÐ!‹PŸáó}FöZ.ÓÚi×í•­$St® QŠ•Ø +*WVñ­´È\tZ. *‰ê‰ ³*­(.[i°©K^–*©ˆ0!*˜k‰§ÿ&vTÝ3Î>/œÙ U8ä˜c ÇÅ´jÊ8ßÄ4&+w6!«pêR  $p‰#´R é%ŽARE± bÌ¢ÄèÁ˜áÍš t¬U6«&z­M¿ N,O¼5µU.%^Bw +=—N”HmSÉucaͱLY%™…$xœ¡‘à—Ú=”<1änõ4¯¥Nžð>š‹/í¸^Ué7öoè´ƒzº°&ˆ‘EÚ¥8õÖzÃ…'ÆÑzMRw°œÁ+…òÖ!‰¥’ƒ”#œ>&ÓöfLâµÎÒ·bMŸn$!S’˜<|ÁÑ—ã–ú²F}¨û 4Üsÿ°Fè œ7µ±þÄ¿D¨¦šmLËVž: ¬Á3` xfŠfË¿¹WÅ[äÓ<%‘Uã`£ÆÐ"xó>õàÏAÆ8Göáš´iÊ ŒÖôRÍØÄ—ÉoâÈPöÅaOS#Ih—ŠÎ•\]žJ‡ °‘¹0ªßöäcÊHÊçf•JWwÿý/žü¼zŠ_ø[eãtVÇ´:¯ÕÁmýàê.ºs»«s^øÖϯá` KdA¤ß GZcÙ[·úsÄ[‚â;ßTÿ±K^£õëWâú’lÏv™íä²thdÙÏ+|Ýëf‘÷ùyK­»nÝœZAÏ=¼îó§7ÐuOŸ±ú•­ûY}ÔËí|ÝÆ#®^së\W¼úé­;_½þ¶d‰3K(ZâÕ›º^¨¶F¾5@¾I¸xÄÑ5Ö.ùMªÎ#n¯±}M¾L–´BƒoÉÇ’ŸlÓ˜5ÛY¢mÚ´fW› l“§­ÙÜ&ãÛ%†1»â®’:¿Ð‘¸¢€âßù–«`ø’ê‘{HÐI*6v=Ðj¹0ú!:ù\['QÝ +¿Ø6z/þœVuƒ¿ @y¶FŒÃetlT“ª:Y8Ô¦zTÎX {Ñoße"2¤Q£Z½¨Ù*¢@4^‡%ýTÓ¼åTÐA½Îò¸£ÐsdÏsDZ‰±+=Û^5®ó¼§IU2¸Ñ\¬®R~g¬¹ØAÍ ¦IP"Éõ`ŒøB ©êRŽèQ±ëÅXwKñz q6ëŒG¯pʽºo‹v&Cö­Æáè))ÐÌê¥$R+ ÇSë‘<,âiYYI–—ÕQBdE,í+ìqþ59¹ØtÜíŽá©+ È;x};:=Ð-ñT®@»¤Ì’gõ¼ÅW.Rcè¢Ù ía@yÞŽóÓY5<¹Œ"Ÿø]°¤Úc÷¼qƒT8 þ6Z›!Ã¥bøQ²ò,bœïZ†ƒÜA+[&2‹bò]üÒ¬&<°sR„ƒå” +¥¹øU³k5a€à¼‰Túù1ËþhôZƒÂ‘ñ¬B3” +¡@3jo«“¸§Ád‚H”z'€.“§”È¡<(ûÞf—nAÍ™\EIðKñÿÊJ‚ì%¯BÁ®¢Œ*‰_ŠsX~%é‡20ש٠%‘ÏNŸy6Н(²ÂMF{ÐiZ®1“1K-d¦R‰ AÈdÏ"¦×›»Ì”9ô˜¡²~ô<»ž +Ò(X0:5Ö˜oJ½¨y2È«ØKØžgu§é„rbËÃg QœP7¤ÖVŽJohžV !3G;S•|Sws‚ŠAg$ QûÈ8‰%úÎÑ«fÉwô²†YâÇ÷¿V ¨Í +Áßïýúª_<ÉC ²øÑbÃûd_¢'•ÂÑs£¤n² +I[e¶ˆØ…ƒ§òZp1‹ž½Vö€ÁôïR@ü³³³ Œ&/´$2 ¸8?ÒB•¢“´ñXÎ3¡*T\ ¾H8mEň+)¶¤'YÉð9‰}èæ6dM†ŸúÀm(Ë„ñ¬Ôiz2̆GVf®³›‘Ô'Éâ†3¦r{)e˜Ø×rs+,Ë4ôO\§ðj0¦ +%ŽZDþžÔŸÅÂNyµ=¥z« '21'§Gâ aâqŠ; 4×xx`'/DÈï]®‚ͧMdxýÅŰÕåþÂ*öÃ3¯Þ{ññò¤?‚5V¬!ˉ<›è´±—™ì?źm@Ü=Ÿíƒ\žöúV¸6¯oó’—Õ`Ÿ¶,›um-kÐëwY¬›%½_û›M²ÙJÏ-‡5øÅÖ|làe£séoÂê5ïòVÈyº¡ÕY->íõ•ë[<äÖ“î\îÖ7/NüÞ¾~›¸á ù 0›0ôŒV^KPÛ‡¾ŸBäK.m ¥›€»Ì›¾ ôûŒ`Í6éÅ>Ù$,›´fŸÿl¥5›Úg]Kz¶æpkª÷¦ +ö##\’Æ5µ|sÖüÏ èš£®©ìÛÞŸÞ5'^Sç¯rì%2|ÿ¨›qÅf|¼î|!¼‚_õî¸q’)áÈuŽ‚kŸB cñR’ae'h|eª› ˜‡ÜY#ƧuQ Ô8µ“ŨaT#¨$b^~¹”SZW¡æÍ_,]S;ŠÞµ'Á‘ ‡°:ìø’Õš·…À]Épw6Ü"wÇÍ-4%tˆØeâó¨b4¿I6–z–-×+’(\³¥Vܵi(Y—qÎ\È™çƒêé„£ßÀ¦“ãzAvIîørÁ$¶!‡›H=ùä…BÃPva©DÔâ({Eìë’ÂZ»dáÊ Òp5;g€3NÓÑMu ² LéZîóôµGp…‚r‡…ät‘„qK• æÓA'HÍ|ÙÁÇOmJÛ]E2A¬ÚœÂ1à è¥.±[³)VOiÁ0E«ßóùÞNé|  h¶R?±í€áÙûÔI.pbqéqêŠxùx‹~t¨ÔÕ¢ºûãÌözv«úqâRTç{ñ4.g…¿Ñ ªs ‘Ã`©µK.I j¯vE@ÁuüXHŸ„Še‹—Ù½Î×›«y®˜áŠŽ£ê±ww¬A.óÞ{âÖ˜bäëžTN1IJŽ2¥¿ÞüéÒ I¡ÿ‚\sîDÌä ‡rzl­$¹€}”—£ØÙŠXvæ `«€òœô…{0,'†G^V‚²È›Í¨¥Ö- tŠß$ˆñ³Da!µ›Én‰‡Çáï%É÷ShD,Žî™´íSÈä6°ÕÓMð°x¿[I*܉ëý‡(HÔ—õ€$G‘4]ë·}Ó®Kçáׯ+ ^˜§>S ã 1»˜¨žnI>)=fU• SK+ãL# ŽF?<ÁYH$¥•Œ¤1¿(ÃÅ´ûtOþí1§ýå@^À¡ô-PtÀL°° av½ãƒ]â,¡iÀ–H‡u° ‰KÜ\ãë[O~ ÄK¸ÞÄu:ÿgøß¤ë²ø•%ô\m?DÐ~.Êuå®Küe>äÏ{a³c6[Ëþ繟»tÝÌv!Ë®_]Ãdñ4´õ[‹{ÛøÀ/œåÆ«n|ïÖGo|ùÓáïÃ6‚¬af G\u›¸µF·5 ¾µîžár ©ÏÈûsþ wQ| ÷¯¯SƒmñEʱMOö™Ì3牄ã™­Ô>ÕÚådkæ¶Íð6‰à&[ܧ•Ïôs“£î“Ùhnáy2:F*øEVSûaš B Í Á„Ó3iIi,ïžõ)¶’|>™†t«7vN%ÙÑWÌ+‘žÃíÖÍ#Fåè¨ íî¢zÜIÙc”¶¨¶(bNþHÙÑ2+!ºBµ’„¶GbÛ….ÉšDw9NƃAËj¨ºä"Uâ.òÇà ‰ô2š•Öt«¼?ÕRáhä ~ªá(p·8ŽÝ’h;°w€¾©}CÖ<5i¹O5”Ã5úUc®Û´v«éì­ïˆv:E[1£‡ê‘/ÝÈ#mD”jK¾v#Ë´oz¨<ùÚEj#µ¨KÙ»²å.˜<~žõÀ2›f0¨†de@øý#G•ºuþ¸ÓJdw5 Áá£8æêdoÜ¡˜âÀ䩤tÞxÝh;8Ì{dIâ,Ðl/ORLV>P`>uH®ì#cˆóEñæ µuM?³‚1œRBqÖ›ˆõ'æ2̈#…mÂÐÄúØä ê0MqiÓÞˆ”3Îpë;4„…3Üšk¦œîKc1ÈžóÚ„’A/‘w/å·‘üÛêþ¬è+W™ÁáÏš…¾r£m¸Q@üI(ÑU…EOq'ºøP˳S:5ew(Ë—$®|]Ù‚÷˜3ô«;{@(A<9ªV&YÅù£Pó(~«”ÉÃ:O4Ò$Ä΂d‡|jw°¨Ù¢aÅùdHb®äBA±^t׈rXG¾Õ]Ý?™ªW~—Ù™‚6ÂYß%Ræ±»ü¡Ü)SôÒŠ¸ªþ¬ÿ:Ü`øZåõ´3@&eŒXÒ• •cùÙ"é:þ(†ëBIÓY‘qUê6¡S4o‚Hèõ›®’Ôåó•t(r4($KÔ+{¹õбÅ÷È]a™Séˆ÷ÀÜohâÄ)1o8§™í&" Ž Ó½¹Ã5˦É^üd#‘òÐRñ¹c]ÙJ³<4\|íFìe# ó³tŒ/ÝHÌl„hŠ5ÎÇg‰Þ4ås>eèš—Ù$Ï>{×^°›ûð “Pò;ݪdð2Ó&·j=MÏ×:ú5q~(É`; ˆFÂFËññG£Ûô£)úٷĉ—¢4èˆ|ê–΃²h‰n:‘]T$5½0ÆÐ ié[ï’2óR£Ô@‚“âcÉ\âHØ›îTçΗ +s1ïÙ704ɨIS‹t¦54wÔ€›@û&Ó#æ"ó€¶S`Û+µ=ÕÜž¢oQ^Åá6r­9_»¥[•ë +w¾t#…·ÌûYXÏqUœJä’œúŠìÀ£°¼™‚jÞÒrg‰œIJQ8Pqfbf᩠̀²ÆàØË(5Z9Š€ Ä©aJš„Îaö3KB9rá@Ã)]µÄ!ÉÊv¥RT fj‘¾û•b|™‰ú¨&0ßž^¾%d½*ëp*°€ IÞ*aœ|¼Õmr:ØÅÆ‘üWÌ"õ‘lJî ð¯Á=RbÂ(N5}•Ù'e¡ŸBì¹Ö/˜©³É…}mWÁÜP§„T­\é[)ui…Ôõw乎&°­ë™o¡rýÿnŽÕª£”~t4Çê©B¡÷©a-Æ0ö¬GšASÑ#Q O§´Hà“ά£C;äü,Ñ Á<²œf(Ëaô4!BEh„@øT®+1F¯±[íXQy¼­Yòk|­ÂùK,¾}â°Z9‹ÿ,ô¢òPu„å³?„$¡6¨®xM½|4KD è’•ˆÊE‹ês‹(}h„b÷üîJo¬w²:C`ÄÓÍØ®…sfNÏ­`ó ‰¯*Ú¼^Nš­ä±n8°# Äp$Kï¤éÂ0æÛDeeF„É‚3ÀŽÅ‚w¥…ôõ:)À°IèÌDã†zì(TưfÄî'“1[+‹«„ +«ÚX…–­´°Ì+·”úª8Sh V¾fá¿(ŠëÀœ° WŒ]÷ÄS@D\Úò'24ÛTŠ¡ÙѰ$ó;Í’#C+AšpW'š9¼ö°r!G¸g ».!rƲ>¯­ç_’T|*E5ü^Øï¢þŽ©L4³÷0¼ª2jR™Ì¢Ÿžr ˇ„‚i&@¼˜Ñ¡ ƒV¼è³TùÞZ}*™qJdü0Úu ã¯}ˆ•t°'š¹‹"†êÉÏØ» jµ{®‚°8D¬áãõ·É6ž÷—ßþfã¥í#Ÿî|ãô×èð²–á3Œ,±æ‘èäÖ¸µ nKä]Ãå.¨îßö9¯ocyk\Þ›·».e©ðÒÍšZÞ²@¹¸×•¼[ïû±ßAÏ}¶lHoŒçÎÝíï§ðò~ú‹WYÜ=äê§6Þlu{¿â"wúCj˜·»ñÍ«å÷³³ßE„gäà2X#Ì& -áÊ¡n‰k_D¿5Lnâé&êîÃóÆ7±~›l²‡MбOE69Ë&³Ù¦@kª´Ë§–Äë-Ÿ´dh›¯ÝÉÝÚЗIÊGæ”Uj¤÷Ð{JÔî™®&Oiï˜sÆyƒ]íG˼ŸúÌz>í÷w}tw¦üêü¹=«æ~ƒGAµ:n«&9ò³çÙ"j >ÌØÈjÚ™¬û ^×yè`ãû윩ç+ª ~¦CbávýAÞt–ÓŒ´“,K +%`€JÑ¢ÎtÓŒ ÓãPS2«p/¿e¹‰Næï©Q£œ y«¶hØ•vkÿÈkö ¾@ó¼W¹I#E…~Cjx“Ò<´«vI,~pZሂÆ’¤âBŸ7¶ƒž­ž1í"33‡ÇÕ1Ð"0ž-¦ìµÓÊ,¾$Ÿ<Òýý‘¾¾÷þÚógáœëüɯߺ†ôþ‡ÿª¦“Ì)ä£vŠY«¬¬bâD öñAŸÙbëaPÈ[ÇFÃða^;ŒÚÓÔƒ€"ÅP +>‹¾þºÉ66»Q¯ý*Ádü/-œqK‹ÖÃóìpáiJP $š³E}+á5×êÄÐb`«TGt¡¤\-d˜ž‡ÉB•:²XSM·*Z¹SX+QHH‹ÓÔª¦%²ù`:¢m½$fïeôL@ÌàÒÎÑþdû.🦉§\c ö&j\{m"ñ;ä ïY»úƒUÃ<- ôè©Zg=èGM7*TcÖŽÌ#¦ãÓ4m@'ex +•‡¥-R$-QCO\1³q0FúÆó›{íÔ²(Ù9GCfͰ¬§EØ‚ƒÊ c2ö#ICfŸ*nÅ,&5žš¡­°]®jP4ƒ '¯+Wv×§§Bá»cÂN…‘ŠLžïÜý_R_ý ÎG‹;Z<ÖÞ¯­îou‘_xÒÕß>\òÖs¯~ ›P±”5謱émq×Ïl rK(|KÄó瀹Õ5ö¾)›òÑk__ÿW e]R—Û[WÞ²8×%¬´à±Ò—Ͱn™õE;kÝ}ë&•Ûûy+¯»}ïVß±¸—Z=ÕÖ›­Noõÿ¹u³«7^=öƯ¯Þ!–@ò¦2ò3Þ¬1i ]ÚÏ·FÁg¬|SµõP—˜»†æ×1|ëwIÁ6}ø*Ñx¤$?ø[Ÿ™ËšÝl“ 5WZò©mÚµÉΖn›æ­Ùà’0îÒÊ(–˜ðIG‚sÖ/4Ë×%=S +_‘]Žê' +=‡,{-:•C©O—!ì_Ô¢¬T•A©ôöo,M”bþµßñ¡DÏN•Ú(XÚƒ£'396ÂC‡QϘfFÞd ¿v^ÈáÁ\›òŠ,=ô¬Q 4޶†ìÏ ˜’óv-`ÛîI†ˆHœ¯Š S ‘à5¨â`) „¶ iƒäN'ÌwÉl&W{'¯Cp·wy‰@ÃÓNG–{¨IEUp(Ò…ÀÌùvôR¹Úé}HpWA/‘¢¹w‘xÀL²fÂ5Ù <=ª‹ÁÂ)±<äÕÉq(ú÷ +2C<.ó< 'V7‡qò†Æ©Ø4uyKKo±‹Twª|'•«¤Í­Ë!5Õ01ìðc¨ †ú5Ç[W$/ê(ñoëšUð^iÖ![êçiO"`+¾’“-¾3t I]ùýÉf®GÕ”…Ή¸-¼ºbýq®lyÄ9}èPÞQ9Éáä¡CEanQ ¿! O s¸àÐDg7S;y@+‰c­Tƒ%ÁgŸÕ}ÐJùÒ[ÆžëuD8}j&"Z¢Æ•ðÇ:úáâ!•Å(Ó©ÃV‰Ä„— %À’¦±‰Ã:x•â" +ÓvpÀ_컺(@W²';"j’QIŸTBd¥6"«.;nl!÷Qê [®dÌp·2ˆC9|Ù̧-_Ìir#iAËÞRíáÒ‡ºù†Þ’n(™fTö¡×Ý‚.÷(8ª’ãu9¿„‘ +’X‚ +C>­s|”E¬ †‡$·†¼i‚ü©¶%¼®žЍhûµ#Jƒp‡HÌ[õ˜ZXH³T:é뀡&tR“ûÂÈ&]zD÷¬J£} ;m›ÒN½4>fd˜Ut !ÿêX5ÊfQ€‘‰ù™¤ï—ˆ'‡åáM_e¢‰ÃÁœÁñb/S€3ºWBl¸'×v®SÜ—F·7¾IQ>øqÜ‚H‰I=Ǫ@†ú–§Ÿ9=x%’ý¯ c–3ïÓG5LÁè!Ã-§CÃg𺋄@DêÕ ¨x= Ö—õ +’¤ï”»­b)àœQÕTãüð¢Ç–’F}‚˜Tšü刊H-r<¦¬ê3çVW?»+iLû&. t––êI¹·„nakàú~rÂ%îä„ü'žÈ䤡/#±¾Sîž›ƒì¨ø—Ø.çIejU +¨/¾–¦V­i +Ô‡~V#^œê¬ŽÁ8_ä[»ÉSoÚôY•¸u}Ì¢î|QÕ8ONGa»y'è1Mí;ØJ®ÔÌ9éØeG¾µzÔЂ3jµ)LR€}%å,'Òê +æ7&s!oçèM@èŒq+‘JàVA¸Ej §n§–/LÅG€²‰¨Twºî` z\ž7šÚ‘3¨&4L…°íŸrðÁ %G‘W¯[äVëÕG*&8Î\I„&Îpx­Èά kÀm5ÙŠFýDâ8”¿ãt~íLµBÄá—#†gœC™48û3è ‘¹Ì  Éâ¹Â•¨RøŒ·:Žn1y–Ëê˜$A§ ÏëF WSPOÑê»g !•HS2‰c*Õ‚> |: +HÃrÊ“)È¢sˆÍ,>í‘Bí2äbÕg`&³ë1a„ÀrÉŒ Ž]ˆÐ¦®.æ½±K†›u„`²FOsI‚üC5¢Çf‘áÀ9ÕÔ2û'í!8!žÀ¨ºT––×EdXêÑ2th·C[öm5ªS±g¨ã 5. >Âd½ÆŸcÂë/®€­^õ.ñ‡ÿ….Üâ¥WG¾øû%dŸaa K„yQ‹ðˆÖ`µÄ4û²GìÛFÈÍSÛ>Ýõ¬/Ëëky«›w¿,’—µ­ž«i³æ–ÅùÒ[VñºÔ·[b³wÖ¶îÄ7_ëcî›zÝûpƒ‹‹XÝÈêmÞ,¹=œÒâ·çö¥|ºË¬f?œêêxWÿüb^ùpã««_#ÂKùâÏc .k z1k{„ªM<û*ðm"ä&Žîî62/ñ{è7Á&oØ'›LdÉWviÍ&ùY¤g¥ÕýL¶Ö„ì™¶½é$ŸÉÝ’®yâ[ãþéäšr.™éë«v“ìn³âmþ¼Í´£Lb•ê»R­ýt™l=øìH›³Ô¨ŸíÀ()§á÷3:X‹ÜqèbpÓû7ª«DÓN±†šŸ¶ÎüÐÍa­´4£‰¥ËÊM½¼Œv¡‘˜½yNÈ"ÿµûç­¡Á¥E(£ë‰ÁˆÚÎGÐb.e†eˆ¿ $¥á¡Upd¯jÊÇÖ–Å€“èã/^N#ác¦Â¥ tªfüEŽ|qXwFƱX¥†Õ‚ËୌךD>Çò!ÖF*;@CIu`O0Š’Z5ê‘\!ŸÖ¨û6MÊÅ•lnÜ$Óbìö."¨ä`1ó²4~LX;8 +/¡n€ÖC¿«§LSXƒ¤>}“T°¦õ6;3Ð÷göW]+0´ÓÕ*»OrU°J¿„[!£¨V4›î2Bj~ mŸj00ôÛÉÉ UÃÑgÑK½ èF°ñÒm0ç 6áÆ`ås6¤R‹R›µ4u%hÄC#Òmú‹,…šÀ̾³ô¸nNgQtÿԑξoBÂÀ ÒZSu†l=;x4Òëgšâc—s¥ë·,Œ ܼ“bZN©,m˜žÍL®U‰gË£[ç¾ýiyÞk÷hMÊšK˜®Ö%Û«~¢×pp†9® ÄŒ¸êvÞ}ZÐÃÕCqˆôó†4jéš·aða‰JàORø§#þ.²ÅêÎnÖÇÈDzøŠŸ|–xiÅÄà#æâ"u`Ïœù-ò‹½Іt§!¾éÕñF1•꯸ï¡~ÙÔ˜—š.l^媣°asLåùn]?;N§ۛ°°¤ÿö‡Þd¼UG +8Y!d"‡ö.:ÐÎ/Mc}U¦Þ´w¥ïm|WL/V’¦qtʸ3Ð)v´³‰†¬PÃÅÖlá=a¹ž4ï=šƒél>Ë#OWµ~ô/'<Àé핃E­LC³Ñ$èCIŽšÑ|À§¤ë¥&])k¡Zϯ”X(¸p·U)\Kÿ–¨ékMIøúbÑ>ê• ·Ä´¿2×<>…‰²î\½÷Žcº®ýÐ$ +#• â`&)¯U˜Ã¤‡1Rì#ÑáN>×;›‚î.ž$3ȹóišx eyí[%´Yl³Æÿ“R6‚|hтЯodèwö:$6ƒ”°¨øät‰ÃÇ¥íNÐ8†Éúqúƒå¬ƒsãl×z„tã?éhV MÙ×~d€Õ:5²âH„Fó`îÏ©·Os=”BÍ[ðÜ 9X³‰Þ̾€Û¦©ÄÁ›ÇI_kX± Xú]ê§–~z˜úL·H{d6¸¯¢´DÚ]_g3L)ÝCKΚãÌ?ªnÐbœ·sèë4샦ó¼§SXgl²êñMÅ‘¢“¥¨p4›8Á×v&{õ”Év_ç˜êßótóR%_ZÐJç§*ùqÃè +"AÍ?s» rœwÔÊQDáÌfîq ÆØúd.Cx^Rü×fM1”U X*„+…€\–Îtœ€¥Ì#É¡Mò–%gÖlâA~a>f]4kÍÌx“¨9Bó´7 „eëºzøæYj¡âpç‡ 5D34ñ–¤²!qŸ‡m5ÊwÐKÊLåÚÑÝ¢“3iñ±-Ô” å£ÎÔÉ®UbW@ uA—˜ŠNÇ®ɬÖs„ë(>±ê¡äQí‘j Ôˆ¹m:&”0K¶ää*Ûr,[ZOÿZoCI’ë;‰±ŠL/EWîHCôðêb ‘èÎ)¿: ™Ã[$%ëÕ¦Ô +$«ÄV‹n€–)ÊGÔEígÁ®´ƒVThj'¦sH"Lh‚Fc)0QŽvË%d#`%¬¸Uñm –‚þ3j š7̵®ÃY††YЖ]RŒoß}öÔ0p¼@Œ¹ÁA•S?ÜcŸñd²)Þ˜Ä\ãÒD©£“ëêPý dã6MËÖ’´y¯6´”?X8¬Ã¢óûݨÅ|Š <¤˜¥Ô†7Ù$6ï?AÌk=~,€AˆšðBøK5—ÛÁè<üRDzQ„9¾¼¦ÊG ¬Ì©YÝ_’ bTX›ÈøE“âÈ.%âײ=ˆÉ¨$ÁÈdÏ67½»8ü²™ ²ÅAGìøUÔÕµx²}™fp•F2Ç‚•ݕё#úÃì@T@u¦¢Ê¯… 0´E>jP‡Ÿ³¼ëE#ùS»¦ipT2¨5½FúÈTÒÎô=C» ?(ãDYwZ[¤džŠ^:¬ŸL Ü$¹åŒ2.gqXLŠSغ­R®ßµTœCjšŽˆŠ˜ºæd²ÃŸy@„²Ô,ÒJEá³$Úù³˜V92w…û¯#p`TòÄë2< ¥Ijp¡ÂÔ£0bÊ`¡‰Ã'Ò@óBõH%r ð4 ?)a¼˜ÀE|ÃŸó¬‹ %•ÒF—^>”¤è„Wyzerd+vãPÀÊ|ãÂ[5¥ÄX +É\…9C$ ÊÉÓ+âæ4¸æø±Ñ\™ÊX}­Æ¡6A7C¿‰g{üUÔ½— †fmX}«®–0Ã&1ð“…n‰*¦9MÖ{kæ;×ÍD·÷3æÄ Ž ô=þòfÕÆ[,áé¶7Î}v±h± )kìy‰éø R›P¶Æ¼—˜ƒÐ¸†Ï݃Ú>ÐÍc_Þ½Ýò"7¯{Y¼v]@›e¶,G®äͲÝ,îí&Øl–uK­{«q¿I;yÝñoýÙ§gظÅÏxÿ<ÒÆm­þíõk¾pã7¿ð±[ü…ï^üüEðg@Ø„5¾x<Ñ&\­qÍîn €»(ùˆ¦^_KØ]ƒó>ŠïÂýšì2‡M‚±ICöùÊ&±Ù¤?Ûk%P#¢Ügê!­„ã6y¤¬{:qRä8bÞU2ªÕUjÔ– ª2,?¥ÆC-ªxCßBz8¥žš ùU[Ú °²ßIýõù*¤¸â<³ù)Yß!(™žº¢rQ¿ë‡÷Ö>š· +{‹1Îð“ã\ž!j@¥w…9Œwõ³tŽÓÓZuÉýÐ÷ŠÏ¹°ŸCX m‡Â’–µêÃU…'æ)Ím°É=·0FôâáF~ +A»ð0Æ»=Úy»Ê€µWï^IÆ9]‘}~*þœÍšgw)Ž „Å?Ã.=’V‹sì}$˜H w‡Kœ—XÛ>×Ã-`yR@ÈU’—äådáeX°K1 + ¨ÒæÐWF…:'œM¾- UteÏá·À3 /o I fT½…ˆ-¾%{ªû9ØEè"-ð3&ƒ|( +¸+ŽRn·F"´ïµM=G˜ŒÇ$Â}úhA–O€°¥jì™9•iK:Ý–Àï5£…ж€¯Üäp„Á[ ˜—ëYK ŸPÚ"o yÆÂjÝìú9ƒísú4ï9• 9n³t(H‰õ^I8&ÙTÌê°­IÓXåïZ$ +c°öfig´Ëœb\ßZ³öÌÍæ. d^DÓ-Q|!Uù "iw#ºrü%C*ÏéÇË©°ß8»c:?{Ltò +ó÷À‰Gàøÿ Á°:Š0l¼ÐÆWm|ÚÆ÷m=äÖ“.þvuÉ{×½ºøMØŒMdÙÅŸgœzk†Ò&ž=£Þߎ_âè&Ú.aù­—óˆß› ¿&¯_ËÖc»ªvËï‹uú\ÒðÍ›¥¿Ù ËF²Ûøy¿m6åf÷:°/Û|ã ¯×>ÝËÆ í½ÕâÖ6Îï+/¹q§§»÷Î7¾qöÛ ° ›³EKÈÚ…µ%þ½]zÊM8]ã.Ó‘5>¯A|öLHÖ´`“<,IƯä#KîòCŠg’³I…¶)Ó&µZÒ¯}–¶KçÖ¤oŸnÒÈM²¹ÍJ?†.u«_¾*qA Z¾,ヌc†ô¤裖=®˜@,Å©¢Jíúõ0Ix¦v4À‘nÝþprÆeTG QSeRÔ«|ôÈ”ìÁ«ã~|Ó4`ùgϳ²ÎÖzdJÓ©ÃÝ ”f6Ô¥—¢ñϞчǨ·¸TFcz O•rJ1ÐIcIí-§æÙ0tjvQE]&i,ÐÔ]ä¼é/¬ZsœOñ_퇇É+y>Y&ªúcCÆЊ(ÓÄP(º@ƒã’(诘úX Ñ"’î³îÀhÆÒÒˆðae:߈)}ð4;‚dƒÞ…/, `G!«ÝCyf ñ–€-Ûe<Gè¸P +PîKƒ«ZUÈZÌAB´&f0oÓ#Ôp|Jc{†—‡#¡Sý"N¢ëÕ4†É)yiY¢`Ž4n'\rVNõ·Íf@ÞôFTiu.ŽÎ;ÌH©*¿’Ž:M#†ÕûV%†ØgÜ{µ–ɬjOÐD¹†—2ay—ú'R¢ ùA=÷ÐTc£{Ûãå KÚU@’bÊÆY¶q˜ÓÇÎL®pCSéð„>Ê-0°ÒðtL p£æyކ¢ˆp®¥ûïªøç†<­PéóžuOǾǼÈ߈eØùŠ Í0´Ve §ü>c4‰‘Ç:íN‚]s¨¢ë¥Y^›‹Er&Œÿ£Å‚ÌœèÉÂj¢B” +jLÏI÷ùHI˜ÄŸ»ÀŽ/GdûÈZ5¬¬ºIiS¥ÙúLWlN‘1zÉØ}½˜æŽÝYÈ:š|†lyR.Cˆ»iP&â>’Ea½%°Œ^AqÀ›‡ç’œÍ@°[¢o2ö&Â_áÙ'ã§ÎáÉ$)äKÆwva±ÁÝ»Dƨ`<ãÞØAx}UÞ·µæ/ÊÒÛ +6²“PlQй„JÊÌ@•2gça€i +)•K°ÉM¹‚=WLä?á6‹å¡^ަÖu3,}LðSCz=l!å`7âö|ÇÛ´†@ܹݧØÃÂbÑgàÑdøØH%æM23QᎾúT!< —ž9Ê: +Àéçù&iP›Èï9…<92¥óZDÛŘ*I>T%…¬SŽO±c»Tw“YšÐ$[˜·~Lð‚y“‘¡· ’ÁY³ýðßаÑÈyÞ—Fßؘ©KЪä`Ò™H,CÁfu¯É¥,š¹§AEðp¨ e³XœT»)£‹!ÄͬՉv,ÚwLíZ3–ÚÃA.á‰Ç´øèÍÆá°¬Ü`¢’Õ77®ðÃcºÉ-b¢l9ÝC?õïð_ú)éþ)ËÏý??ë3þùÿáþ'ÿûøöÿ5ûR£¦%f¥…'vòÐX8ÐØ©„8K´ÖeJù!àßWrQ©ÁÌ$jXè;ÏSzó,q,Е(a`¨ô\‘ 1ÛDñ溓oÒ©C2Q’Pìš“¼\‹K¾RÜîZº• ý 7øÆ l½ÅÆ­ìœÏꥋVw¶qz«wd,ZÝèÆÙ®^™Áèé¼7~ ¯¯cÆ6¾|‹vakᢕÁ©‰›1PÞ‹£¦Z0×ãÌ™òÃEÛš»¶æ“OV4(‹º¿€\¼áË)á>P‡AG› œ¼X¬Ò+ ?c/¸Nˆ‰d ''©ž*=ð4±S º&½m1»ô²6Í@§¯„×1ͪú¯VJ£czÀ´ áM`ÇÒ•k "–¾ª'Á±DB?…Z—”|¸"9éþŒ­;Šæò<])'”à›´|cHòn´K= úA…ãF“,ýìZ£}j5UظFgˆ¥³“|-"•ÍO%ëHAžÝមk´…¬:.Á·< ŠWqÄ‘"Å`-€±ºù¢ø8pk¬ÈÍr9²Ðò]!Ìo M£¬Ò–îåÄN}¶xæ ¸R³;L”Òî΃î½–ã£æŒ`;¡á„ëú#~ç8#·:k›rlßà¸Ü‡M{&mãÊ*#v¶OÝäÈô¾àT`¶ùz Ð3ÇaŸ¨ÉQƒ=Õ½"úŒb- – a±í>§¿î˜éä")]Þèv‡³ï˜ðô\ÂŒ‰^,ãcÛŠ[ÆD` +îÁØp²„ŠžÊø”gÁkxžg¢ßÖS" Ls XF?PTvo~B&Š®0©‘]×=ëÕâwE»“´ •¼ù’ϦòÕÉypFxL¹Evåì%‹ÕEÑíÉÝ”›IQbRÖ“äÎÏõW£¥Ã\A™7•$ A/‰Ä21KÉ"/Øiʪc;µçÙz…¶ +’9=%è\©gußü¨jÆ“x¤pbMèŠwýC•ýŠÊ0\¿Ðbˆõ7¢78ý)M Á–ec—¯îSúˆæ€*?ãSOõ8†3´RÝë„^ ¾;Ž >r ^Ú²ÖäÉ’é/P•Ÿl¥£Ò­“‚4eÙÑ#SrÐ%+„ÔAH¸–œ¦-00Ê l "5r´a¬,/#e¡Tѧϡà{%ø~Môà +èˆãRhå3x¿N]9OOGÄŽ¡x\Á,ÃÎ]Þ<þŽ?h)6Q¨Lg)ú’bðFµ÷Â@¾Åõ¾~¾SòkˆBÔýǓ҃âøZ¹’ó % P…érS¿6á}Â$á,dqÔñàµE9Ó½]xÞ³`,˜§‚7&­¬Ê‰Å×Rš‘oƒú‘ƒ/œÃ6è)_8 U;:l>–¡†:ùx.׿xOp×wå…r¨ªÉ vH¸‡…(}¶[G÷Þ!†ë=þE4p-8 §ä <‘°68,öyb4ZE¨;@F äÆ8ŒáÜ\A¾GµPƒzùEÿ˜(ªšÉ…püÇê JSAÐíü®¬@z5ðc)GJ_B¯ kv|”œîå/Ç8nç/Z7Ë*^–úº%^ÚMÏ­ókûËûWnö뺫—Ýﵺx‰Å•ì]ÎÆ5­þkñsLƒV¸:ÍÕ¹r±=}ðÆO¯Wn<ÿ&<<‚Èë«p³_;ûu¶_“_­ße­ÿÐqþ¹)6[gÝcΊž›q·e—½ÍX¶:«X} +SÖÕù¬ê O¶º¼c\=èÛááéj7yñÜoíÞ‹_Á#^¼å –°²Äž5F}ÏV÷òÓñ1G+·ž‘%Õ#0$·HZ󛦾ÙØÚ·Ø‡{ì˜Rb! u +då?0Ð4&bFU4ƒ€`UÉ/•±Ç¬$ “ k¥5-¥*´ج® €ùVëÆ$¦97×zÁ9' ¯¯7Šã¹R܇ÔuØœ"$WvÈ f¼ˆTŸ-a œH"…Œ»p¬‚p˜d—tP.›N÷ ±>¾zj3+ˆaúËÁgŒÙÛ­ˆZ»øZ#,ÍÀIû“²ª–n¦¨Š†¹ÍpúXƒSÕ·)@'ºw!zlF#|yJÛèÖ³ßþ˜øÅ‘²hL°¬¹û˜ç5¼{¹ÔëIÉÉ‚©Œÿ»´>áHýÿr÷v½–,ÉuØ;þ‡ûb€ÜÃÊïLûit Ú0$CÞ úȰt“=„áïZYU{gžñP¼# ÷ep'z×Ùµ«2#"#V¬å7Å·LÒoÊ 6ì²PóŒ›$d¾Tñåü±Äha³˜D²mÀ’àFc±ƒ¯µu@.,è݇H¥¡ÇŠžL |ÞÇ)>‚ç) Ï\ØHÆÿJí ÈZšäw¸ œcz¦b$¾M¾“/’—À2!–9¨ˆñ’ £aeÌJ‰fy)àh¨ghº`n}&WdÕu„à1ÀÞÁ5<0»à¤lÐ1aÈøGBƒùHÞðe%j_µÚŸWǵÿ¥r: ¬l’Œ¡ëΞcâä(‡.¡'^­“uá ‹e hÍ¢¬§ud% _¯†À–@y¥lKˆ©˜ÒœËO"ìû€²Õ˜dì(Ï‚Å3?Ä/€ ¢X@®–l}¸ÌÞ¡e4|‹˜_ùÌ’²HßZÏѲXMÐÝo¨½0*'nc‘(úŠ”/¡6>- ÍÀÊ +Fâ†`!ºƒ&Bya"¾î›âº.<~\‹L(w-I|òȚέp>–¨‰¤Ó”4  GX k^Û8®ƒ ‰,9¼ËÆúb†OŠkþt¢ú)ÀB +Ç-ãzš¨–€‡…µú†¨× ±É¯9&¿ÿéX_þƒUbEZŠë:œðѰօkc›“/ È¨#òƒ§[/zÐ5Q”Ä”x!‘ôþÖ@D,mPjÄì%‡~¡4˜ŽòBdZ·Còމbs|·Èó@G“õKòPêâk[ +ÞUlÁ4‚=ùÄì±^’Òã¥UôN´2ªÁ¤ñ ˜È Smó ¸¸}­7±ÿ[æb9ÄKÅé¨B‹G +â‚Òkn´VÌ2»‚g8ÑãMAµ5¡áÔÍ'¤+ït0ÆV…88s7úJ]vº2r„ÓÔ’¦ãáó´ ý Ú5PÊ>-Å] –‡«´zN7v9PÀ²!YJ*!Ýܤ3õnêg’¤^(ÓÊ`M?äs妛­kàøÓË?Ѝ³s¸«[^ý7õêç—X°Æ ?è%¸¬!h U|ÒkHÛ¾5B~|Mwwû¨¿x-_¼ÂåuÿPè~]›•³.1Üüº×åº.kFèuýovɲ›>´<–]·îÍý&ÞlöÕ!|å86fã‡vkul[ï·w“ºñºï¼øðÕÏ¿‡¬æ]ÔØÆ–· Äk×hµ‰ikðûÔO]¢äJ×ûGÂóʱÚ71“¬)Ä Zï¹Æ&#yÏ\>”ôl2œ%Z&í’Ymò¯mž¶ÍçÞ³¾5=üTÄÛä‘›ló--õµ›üuÉrß’áOÅ„Mμ&Ök> =i`lùúY Õ„y¥ÃÛ†ãÝôˆ&û°8Ä($Ï“-/`§|ò§ ?½'æïˆÆ4 xüR«Shpqã¨ÍžwÎC'ŠO&3  æ¬/Ÿ:ã˜ú Ÿ:|R\Ñ\fÒªDðãð“Ü öaB \,öp¯Qó§ôá¼g¢uàU¥%Ntîfljs3|aA•XÉiè7ËèlX/®(‡i/”û„dÔT勬Ãë“p˜,k‚õÙ¼’„£ZÇ ¡âB9la½+l”ä+YÔ§+MÛeÏru–èõÎz<—±(·2¶–š‹t@"§ÏELqpñs $9JîÏNì6¾+Ö…½\Å»†ú6+L%pÌ…ÏŽ…LF \1çl_H— -l G¸ß5 I;¥} +‰P6¯jiûpx> +u&xQµ¼Ó¢ÊÜj¼Î¾ÜŸ,=³ Ag!á0– U…ÇŸ4¥¦¹ºwMŽ’ú •ëÔÇ¡ÚùRPÆA. +±C¸!BÎ,D‹ „ó`’¹©ׄ®vf‚h4~ ~ýà ™õi‡YˆGäFÓ¦^ô¨\+º–ÊÓ €¤³øP´"3Pe•ñ L¬¶œø.͈¨x­¯MyòD“mѧWå¤YŒÄL\lJ-Öy­:AÌ{C`LŒÅy‡¯ùô‚öý¡|p†ˆ ~FJyðsÖÖ@®ƒ‰˜8©ªœÈÃÍ)]âÏp`afsØÂP¦?þûA³”3îv;µÂoÍ–­aÊZI\l%Ug“)ˆÖ2MäI1€`BJhžÓIt™ê%â Pe[\¤ÉJKµQj胸'd¬ÇFnšÕEKäSËžf ûZ=Çeâý@2¼3¹¡î™6óÍÌ›^#h3ý£ØÊ±o9Âÿ}—þ …¼ú;m¤Àf¦BˆçºvfSQ?†•îÓTzyŒœtRFÊBæ(hT0O‡ž{hç?ƒ¼8CþcIƒô|O}Ÿ`ΰ0”eawõA þ +ö¬gvGÔJhÿDŽ9iøaÁžšIé€nìà[GŸ´%Ÿ0IÅÚEc€dP³˜y"€\ÁÑFGáù<œÐˆoœ¼f]¸ÈŠü[¢!ŠÎ°§‘PiNl¥’ ²£{äJæ*')nh¢ñI$h¾OVº™öJ/|þL +¶á9zZ +A@±&rò?Œ9h†¼CMX[o:ʵ˜ü½8#‹9—;ZºÃAeïäŸÁÞ"HÉcfÚ äRO—«ˆ Бk@Å\;=„³q0ÃÂn>óøéwؼ³?y·ƒ@›’ÔDÁ­ù©<Ô ITØ%ëÃ"ä¸8†Ió:djѱ‹´G¾”ˆFZ).—¨réy$Þ:üú•su%0Ž 1+JTâÕÁ£q\:¡.]Mž…Ęɸ Bv™g°EÈ‸ÏIÆ‘Žº_— +©4âhØ2 ãÿ/òq5æÞÓá@Fb'ì"àó8jŒ@Æd„ÏSŒêóÀ8¦þ\îþÐ¥ã˜)ö§+çé`†£ØUðÄw‹j Yüé,29)È€®û4`—:x&O0,iV&qèÇ££uX©‹¿—T¤{[›à¶FAGþ×`¹ ¨»Ç÷ÅcÞ¼Œ··ækßßîf ,kåÃ;r]T›¥÷¶F½¾—ż]òëÞØl¢íV[öä§¶óûÞÝoðWOÀK7.cãXd÷úæªV¶ñ{_»ÈÅ›þã|÷º×¼øp~Ëâì7!a;ü>vAæ%m"–—Á{dÛ„¿m˜\£é&ä~š7!|è÷Á’:lŒ/‘5_YRšMæ³I‘6yÔ’oÍsÈk^¶KÞ–,Ïiõ{:¸K—ì’iõš†î’Õ÷¤öãëüwŸ+ïÒê/2ð]¶~Wòš„Óy' ÕCgL3ü;·DÏæWo«N½fÌðð@ƒs~œaÀç =Rsµ±X—TèÄ¿%ððÜÊ h¥ee€ƒ™aAÕŸSó8ÓôܳD§ùäTÑA¤Áí!^ºH,"ñ¡ç¦±þ4ˆl]‚ù¢\³)ì B(ÊÌ7ý:­QÃòzV‚‡†˜ˆ”‚…ïQ}ŒbS¡„ÂP[ÓNŠö&¬Âa=Õ4ß:–?$Pú™U!»¨Î©àÞGÄ—MeÍ$ævó‰cIɬ™1|„à{æàV"qTsT$¬/±“g!ìÜÁº–¢ácL_R +?Ø.Ï‘†Éý¼hñ^;S¦ã ×Fç¡Ú%܆]å`æ+!åþ刢Ý)^9ý•¨=à`y°éK1×.Ï©aÞÀ“D™BSŽY¹¿õØ.šë #®Šžg„¦P(¶]å œÂí%Ïð¥Å!.ŒO§v‚Gac8jsÐTTFa)¹+>( ä(æ]Œrœêî‡K1$USÖ¢ŸŽ1…O™¸7½HmÎŒ )ìD0ÅæÙ˜`íìãë‚ÿ®7°-×|QÙÙm¨“^¢¢Áçu5\> Ì€––Ä +ט›D¶BD¬jÒ#@¢ÃÒ´úuØžL’DÛ†åŒù\ueÉ+•›5qpð½&¯SÇà_ã…Ä}šuã[ú¬ÍbØ©”ú6X–íx +£25I&Ùò³?á¨aÇÊMêîáf&±Ö¸f¢ÌžâÐ3ë”Äh<4 S<ÊL§GèóZ³Áª“g­_dâhr•«Žˆ”=ô4ÏYY2GP©ÆMÔc/ö%d Û¦_»”W"Jõ4jÀð ç¤óNíVéšðé„ÕüŸ¨Rr—±N$nAˆÇ1 rg(.q|¤JŸŠâzâ@üqøÚŽáÄB5™æïà[#WÔÀÁ¹;®EçIÜI ßËvßÌ08> pêW&ÑÔ1"†5Íæ;5°6ý9t8Îô 'Ä Ãš× =ß$`­MIzР™æ¼šÑ‰RA‘¦”x,À‘¢*?ã$ B1ú”ú6³CUx'ÂÃcR5—"ùêrA¯3ûÒáB?1ÐÔgÏœ:°š¨ ÿ9[^jâ%eN€Ãi¢NÈ@k4„N‹Ãûßõ +R¸n@|ZÃÕ æDá ¼‡0;aÀÌPŽÚ p·ç æ/R˜£oÔokD:¶ÓðŒrðÜ9$:(°hB˜G•,j.>5…„¦3á«ç+*¹ã¥ –hvx¸2çyÃP@Ä(sá»Y/•Õ +$XIf”ÕTuvbÏ®y¡(ý°'c/ øíÞf2Á¹¼hjÕWïOÖ0ó:“ø&T=öÓh³Rªæ¿ +È똩 ÆP!˜rgJDç—&¯9¾á–XÁàhuáÐ,P6¼MLš÷;¶ø½˜c8!X4ùûÖÓüé ®ÍêüùõJ^Vý½Àe{¬›hÝmøA›]¹ÙºËÿÐß8ƒÅe,¾…×®Nh㪾ði«óÛ¸ÈÕ—rÍ­Nwçšî5÷îì7!a \rkˆYãкŠþÈŠ[V'Âfïû²+ÝÖí³ÙdëndtÛlÛus¯^€dã.V§²÷>;7µqf‹×ûtd|w«]|­#Ô»OÞ8îÅÃêŽß#Á.Ö¸òñu ÚÇ«mlÛÆÁk¼‹¡:ÇSK/(]ê³!—†å‡…†óƒx*±2 ʵGâ¬ûªÒ³h’]–ö:æÓÁ–!²²´l†Zžù+«cji±Ì0œE(îúZ’ “T&ÌtƒÄv~ìL¸裳³(k|éÔ ¶#NI‡€¥›ê·Öf†LÆH×ûÊ" ÜÚÄàMáÁ•šúƒ*-9zbÞ¨¦Kšž¸8P±#'мZ4P ù°+&í ½3K7uá ‹;Ñ\%ýz¶Ç!• ¿›ËOû`#Xñ¢ +«ˆ2šá@Yh>vÍi,RE¨Ú=X\RgP‰sIµâ0…2™Áž8+9ß<ƒ5\„/ 3ŒÙÀ Žû³ÑÐ)²`Ì$,N¾é‡¾ßø¬ŒbÞP²Eê>øËËĘáÜ×LÕG`Ï<-“\¦óTÂÞTÿ(Då¸bÎz„µyn÷È.Ì&ª)îJh¸7ãJH#J„Ûò‚q´ +›çGº»š +@zY!BY5T-u†ÇCî†|y¶jWwÓzçíó‰à “Œ4Uá¡1nŠ]7‹>ýw–µÃî”–\ tÌ`Ôkµùc¢Ü‚o¼°KÕª¹t±¸•‚í:Žù”°¿€`.(e‡‰R%•Ãj”³—¢ !ì—«¿™úÍß·žëWÇ…Ôƒÿv ,`ýT6M2R‘.IäÂV–ÐX€3Ip¦°(Ô Û¢Ïô½ªšÒ”ú¶Ø”4qÙTÐû +Þš@ò º£»ó0›Wõ"ÜÂB¤HÏŠØM“§_a¦%¥¢©í +ö3ꈨä%o‘„P%šâZR}‡WV¥?ú¸]Q÷¨7˜QRcéqa´©?ÉW=LÜ#¨ù@*Tg9.ÃxÔSÛ'iÊ+¬«ZõÍ*ë‘Ïa]Wxfö~\Úæóç†n±•• ðõLºW’ó‚Jˆ\ךj@øûÔiÞ¬ÇTÂE¦ÚX%¨ké4Ï2½W.Nw†¹xÃg.5ýÝTúpd…sC‘Ø`+tèÀ¦=ǬÀÞÈN…ml(D—Íë€"’=º¨ƒ€O#ß0We&Hxž>Õ4¾‚][$ ‹Á]RÌûޱBˆJV“ä)OT¬=‹W)ò>Á˜´n“AsÈŸ–û.z0#ĹøjbDE¬pB5U¦*…ëÊŽB6¶0š:­áB‘‹=“¹¤ªÏG@SªªõUà{}m’¶|9B\]±Ê_ÉÂ"¼vñjºf¹ÕJ²Ã®›´ÁØ”§)x›£øÝœDWÃ$˜®Ç¥¹€³ ‘ß·næŸq’\ýΗ>jÿE_ßÔëýÓEm~çú4Ödž߾{¾›·°¼®½êÍ{]Þþ²Lxíºž6«î‹å¹¬ãÍjßl‹O…­·í³ÙcëfüÔ±ì}×nööê\`ys²ºž?â¦Þ=Ú©ß=ßÎ?.ŽÔnêÕßn|òê¼?TÄY¼ü Ö ñ¡}²D—%íƒÕ6ªmbß$í-Þƒé6à¾Äe_¸ÄïM”_ÒO­Û%oX²‹MòñuʲKoæ1ß'& ç8‘kŠöU:·OýÊ4‹E\zNª”œâVñQ‹üD–ŒÑ…B:Ü‘ã ÞdÙeòÛ:‘)’ª uÑ(|Ô7qÄ€Òá|¿¥¹ED öGaP9ƒ¶?È„šÓ;çø‚æùl—yédÇ$9 Ú6|qÍÃTÑÆ{£ ÔËÔmÖ® z•ÔŽ·d@‹å&ƒ¾“d«œ>šÜ*YnÚ!°‹è¬h=‡MýÐŒE¸»ÁåžÌ§b»& AO ÇÔ6ÁIÐ*¤$ÊŒsæ2°: ŽM’œr È$VðÈ¢I”˜çø¯Œ»ÃåîúÅ‘u{¼%ÙmõD +¨dÕ¨?G'…C™Œ›ç6¹9ÈÐl'Ó/ù_œ°¨Åõ +l8‰à9vi²Ä:¼>4I;„°ÃÓ “åvp”ꃨÀø¿wÃåpnå÷9(@$­-ëã¤^É:‡FRGñ»hú÷|l1 x³?©…‰‚<'ÝLüÅĪhè—a¹lQƒ¥.4²‡te–5DÕ¿8º» Î݇®/r†˜òįÜ"dûJTª“r¿bËñô­â!Þ8œ»ØË®Dçc뻾ÿËô"NÔu†=–·AØ¥T¢1´{Þ2*j¯Ì-Êø}ö Ô EäÉ‚³ù»ßÿÛÓ{¸½=_EéáâÃkÉC|TícèñF«²I#”Ü­$«¾LÀ3‚º’‹¦$,dÃ@]¿>:×F·›§©v—µ&•§ ñ¬ÏùZÛü À#T +’0„€²ôbè'NS0—ZR’òà/5vDYÀ0Q®L¦&EX³Èzšø}¿‹ÕºµnÂ-Âø~ÈjîuX;~ +h†ã£Z epj´‰ +¢eœÀ-”P©æ*"½ë‚R‘/N:¾2L3HE\òª£ü„&LúÁ(=¤õíbâl؇¨ìóq˜IŽîT‚‰“ Ž"N`ðå(·âBºD¨+r#`))òD¡¦±Öh":–¦©¦Cʹ4I•˜fzùÃ&&÷Ô¤¤"鎦àØÓŠèÜÛÖðL ÙL¤Õ/R0,AÀätI”ýRæ$‰â™å„*sš›¦b­Å‹.1óωž8šVLˆÀnÒDÍ5_ÛÅ z°ðg˜œ—Ùl&Õx1EÞ…¯_«~¬u×Nà4<ÁR,²¨~eñÔå”ÀïiåH=ßY à´ðß|¹„úÁD‰6/ŒÚ¸1çXIf5 ?¥šš +Gç ˆ7IÄ’f£©ruL‚6Šþa; Ut™>ä ¤ &k’êÆÑj› Ì œŒ¢q B©ˆH²š&ðrƇpþ +"ˆ•™<?·iB‘ŒŠ‡¨ñ¨Òn—¨ž2¸ÖHŸw_-¶KûÖ¤#PÕƒ€tÚùX²×Ú54‰ükªf_¦º2Öc¢¿$ë×r?}/…ò´&±ìyƒuˆÌÚ‡T(Á)Ötcd¢ÄÏ*غ‡3@ä‚uÃdŽP`†eãÓËÝ&¢Ï釫Ïô¢•Çf«â5)s´ïbØÅ5{~úýdŠšo¤þ¼Ô©nI:B¶Q$ºh¶5°[’Œ °ßÉ×ì(L7šÅî.ä-M‡¦`¥ðÞí•¿oc›’àêÎL¹ È7–y0¯©gMlW•V¬.*ÈU¤E¬tš%¡<ÀLЪT„Q…¢1L)>QªíCך+„ñ¢ûƒÁÝ_|1ÿ¾ämZí‡ÇëðÄyò TIóN#Å_¦ %( w^<Ê2,š. +H‚}I<Ò²”iâÄpÇ£Íö û¶¼;ýH†šвwÝ_x°Ãã$oƒkÁ`£‚°ÍxÔ@ßÖ9ú¹ÐD$/K4ûZýÄe÷Ðì:þT!Æ<‰–_º£µ`xoÍXô¢n.ÆÞés2ª) €,­z@²(FHwÂÀ„_ϼÔI(ÓTsºÄ0QWXa0ÑmÊRúZpÔ#úØ(F÷ 8lýý9?C-f^ÙEo*‚bñk6ÿ9\Îß•x\x8U#£á@&ÊX3DŽnÆì’uÓÚËÑù×&GEX;äkE÷DÁéý(`I2²¢¯m:RËZ„¢®³Ãz‡YÜe¿Öz?FëOì,ˆÜrŽlq…ô‘ÀåØ ·æ~ú)æok}£‡ ÌÇw[5çBÚ A(\«ÄXKCª+ ¹b6èš -ß•gºlŽÏž«’V…çA™5Þi†¬ óÛPÚ [Åj×<¤’ŠL s +ë˜ !ü0ŒRÁd!ÍhÔÏçœ{­¶øx˜L`D*£®QX«u’áØÓ5€¥·a`3ÙPêfŠÃÓ7ýJ¦$ •DºPé¡2< ñéB"  ãªiÙrV߉…Üš\š7—X¾l>}בÇè"Z­äk¿Dk1ñCÖÖˆ¤ƒõ@L| Xx*«|0õy&3Òœêç>ø%‘ðÀT|${ žŠÃ‘1ÏOéc&— té!jÓ2óˆ8ggîK£å~õ‡¤»<üâÛøÐ¥J†ôPŽ1W÷¹ +­jépÍêj±}¶vi’j.IU4À2«JR’'#4*4¿Ã³ðSL&ôZq£DÎ4*‚PÑqj‘àõ¯Òo,}$” "LH>l[n4‚`‘°8×0²n˜ŽÀŸ—ÍÐ~Ê)Ø‘~ +8‚"CŸ{GÈžÅuا íÿG-õŸÂ3µ8G“"[* |5ÑõëÑÆ1b}Ò€º§3¹F§ +‹Gè3™ÀØQxG‰“;'Ŵ׃úpþkDðfÄÖ×jª€ðF)Ïóþ¢Ú3–¬å¯`§ÍÁÉÀªoœP?¡Wu%öž@ãæÌ,ÄÈÊçPm-ˆ¸íSЭó—x +‹6BséæðGÑÂ9MRf×´SI³ÝîI^òùC®©^d€J¤eQ›©Éé#ç×êô´lC0±ˆOSÁ‰¦¬f(ò•v£Í$>ÄŒºK ð"ë=#0• ÍPÕøQ Cˆ¡(U.kêFQĽÍ`8Ü^IÃѱIWˆ  ~%„W!þÛ¤MB>#ˆ®mhµ°«ÐD3ð` †Äû:øûRHy5Ç–V˜ü„Pì%:Q£kÐhÉO†w5;4˜pü.«kÅsxl8‚¥EÙÂLÉr Zº†bE£>¸uiUaï3û Èä gTlà8›ˆb]éÒ "\Ctú…cxin©*K‹mMSøÙ‚”d69·O_ƒn­”˜“fk¸UŠûçg\A?‡;ÒA¨TR‘D™p6m—0Wå•öK‚ç]Pp©9“ ¦ ¯M×À~³ïÄ—„rÁ‹ÝÈœDóY[«c¨;ùÈ &~Yœ#ü\iÏ÷qÕÅ÷È~[/qV/U—ÍÂfËŸÅc³HÔY÷dˆÍ’$³é(ó| k£•4û-«‘åBª%ºF» +¤Aþƒ§nʯ« ‰òÆù½ \£ô»*"¬ÞJ+K"™Ôl µê%ÑF…,–³ú=׿Õ~ø÷½ ¶%…·ÚƒËJK‘bWÉx©w|¨Pò^Ù–NÞj,®Ï,ŘmÉfWÛYk@k¡h_QÚ•ž6ª/+Yï%¯Mal[AÛ”Úv¹}ånSâÛ÷ÃMiqS€ÜV*7%ÍMÝs_ÝR7åÖ}]vSÀÝ”y·åàMÙx[\ÞW¡_‹Õ›‚ö—•ïM‰|SHÿ¢â¾–æ7ü}¥ÿ½%°i|ÙaØ´"–†Å¾³±il%ûŽÊ¦õ²mмur>µ¨Þ;>›¶ÐÒ?úTïiÓhZÚQKߊ×n\›6ØÒ/ûºµ¶tá|Ì<ï{F#”R©!ÚŒðTîÑ‘ˆã6ŸêFP‚GÖÀeOñ\°ˆ¹s[jÓ4%Ôšè2hÌþœ²vš(¼„‚ä4Õ˜æ¥G:f¹èñ FrLì½ÈÔJŸª¼ÉÊîg0ÇÎY£>K‰.gÐpòç2çs.ÇÓDùéo’/%½,œÙ¡„‚$•R~˜Èy1Ûƒƒï —p’2‡Ë /fi;a±ÄÙ•Œ×#nvµÏ#œ?È9.˜Êѽ~&u7w[ Î1âØ>¸Så4±cp^Åçü÷ÕLÞå) Ñ Gðæ=Eê ‰¶xr0\°%{ˆƒÕŒÒ5Ë.­0ds™¤íÁ>èB†“S\2§yE~o3ø¤°Ä‰©v˜á謭D+·Âé)áCSglÒY¿×±¸ +·è{昭T›áϸw´ToTð„§wû·Ú¹)$„äØU¯£|\—»îu†œ#†2_‘ØÚžJS4é©ÙÔë|½NðP*¸a5êǨ˜ø9#¥à$÷ZÄK-°ã +»íwJ ¸–ûÌnNAA¬#1N“Y +ÒÔ‹‚1+ SIù<¯&öÁøZ”9œe”T¯ûÃE:’³^‚¤E¥zþÚ¤c sž*© <© f G„ô)E€jð;ãp'¯nHÃõüw +çè…QÐh¡IReÌÈŒ\€5H¹.¡uaQ!KÜ$ŠL8øV‚œ ³9±4pI¥”q&›ÎÐÂt£†+û:·xc§·›¯ˆé2åÛZ7ý©"Nõ)¤é +¥äpm0‰åö6 ÈvIhH¹)ÙXÝd,IJ¬Å”@‡†’L,lÓTúqéÖ~´§{D—ŒÓ­t£<H= G¾<—ÅÛ9löçBáü|ð§8Þ²Jµ˜­/†µš +É$‰Gé<§JɃ“ðc¡_h=Zsq©AF®‚·‰(¡ZIpöæk“¯…`q×Ïòí9 ,Ñý-vÜ£´pd 9EÇ<šÈ’%†Û2k^ÇÑf«ñLïÝàãH ñDgXyæµØc´ÄK¥íóàŽS ¹zT9ÑL0ˆäâ^¡i\ ÃÉêg+;RŽbTCßÊ:øÞ2»”QNO÷WØ~:&ñMP»…M4cfQ~¸—Ó¬ûkLT«ç!ý굂‘‚³rpºH‹DÕ9É,F¥€ÜËMD’ÁÔª É`“®6éJ ·"Poþà3‘^1¯Z©“˜¿¬]¬&Qµaþ¬#¹èÄ|ÖýQs>Í^ žSžœl¤çQEÃÂYÔÒŸz½¹êÄŽ©ÝPÃ@8DT»…éLNuiÕ?ÓJ}p, +’¯èƒH+Ñ.ôCgÐÕ 1Ô¹¸ü1«‡¥HÔ¨;Cl[Qý ™*~ n5îXkùa«ûžC-šj2 šUš$¬‡úóó/vUã`ÕÇ.¼9ýLÁÌO8Ñ[ŠlEnYIóSÊ.5GSNóSµ^—–2?G®sSø'UˆÕ³iò® ¸¼ùïIâaKmÒÄ…“+C”ŒŸºvòZ 7`*"XD%´wÝ Ã L©y-K/,¢ö¡K6>™ '!>,?abÆ}¥ ÌaMU´ù@OǨ_ûÖàýø¢üEÓxi0ÓÉo:ÑïÝꥧý!Z·¥÷½é/­ôñ‘.=÷Mg~iáóÚM¯Eì¡;ŒÁ‰°‡,l± +þa “Øà)ÔÅž±Áq¬h-*d‡Ù`L¶X” fe¶lñ/ JfEÒì!7;lÎÁ³‡úl0AäÐ;ÂèSठiÁ+-À¦OC¢ÞñO;ŒÔ+˜ÊWnPW 6kq}| øZ?líÓj +½¬­L¢Ë®RJ¶Ö2¹â&«hU_&ž€h¢ì5M꣢U>Ú¼Ô³èÑD¾0uuYqíº“^šÿZ4o¬âÀˆS ¡Í–¾ÁšÅª/±ü«Ùìà‡¬”…¦U+ÔiZƒ0Ñw57ÝíuÒ¤e‘áÁÚ£¸ØÜ§C³#÷¤XÓäHŽ›žÍ9jò¹ŠÔÁiê–ŒHê?pæ†S Œ°|Šcͤ~8B„ÌÜÑ­ßl›‚l0USwƒ®ô "GÈwY“FNZáÍw×y˜»ÑXÆhØByÖ~´¼`CñWå¥h\édT‡j†6Îu(·™aE๪Z´´\ý:&²ÃZ-,’Á¡5•Ò®¿¦ ÖÜD˜S¶ô2ksq~P'|b‚¦%ª€÷(ùø|²Å©l!-ÿóSñó+üÅ×X ®cYà"?Ü’„Ñ-,5h„Šÿ? +Øì× €qKLÅ4YÝwkÂ’Á„ú[q©ÌïlJö/!Ê&d£dÓük½¸˜®¿†¢»¯UåKVwM4JhÏ¡6Š]ÎDûø,l-eƒ¹À?,‰ZÛeµxxr1&J.‡»)ã´óCVÏnÁŠù1Rƒ$Á¢¤Ìab@&$KŸºÖ²döK˜²¨K’ôähᡞ›¸˜]ÊRz@Ét¼0Eñ…Á„£Ž:](|G+7ïÑ1ÝID Ý/O$HͲî“X?ÝýD¸2>um¨Óx4}μÔ8u嬿vvc÷ø{êÒó”54±6©ËG  ‰œrö§Žq_ëOÉ‹g~М?Ô·Š2½íoP¬õYm"ÉÕOȼ¬f ° UUºÁp/a*íª-ÕÞ&ž¥„äúû‹åVh +ö¤¨Óàý4}L2œ_>xLnwþ9±À„ ¼8*Wÿ¨Çƒñ¼ADªS_Ÿª0`AUüÞ ¥Qb¾z°•ºÄcIb/ÔE²€j¸Éé¼Â„|Y~…¾Fˆ0@ÅU(òÙrޏ 'íLv>5]lUŠ&Æ4Xr+f­£ó(WßH£çÇ5˜\‚>ØU¶‰UÕªš,¨’vSäKA ¹nל&­´E¦ LLEÇ̱¤a2Uo½9›ÀÃU²Se5rG…ib¹Ž&ÀW-_K’^Z ÉcÀ0n“‰æ%ìú)<Ú!²´f¢ lÇÇÅ«"}EÁ}| ˜[Áu?dÝ ð¬Þêû0pÿ½#(¡oqƒ9Ü _ŒB>¾áW(ä2¹ÁV®Ì=Ts‡éÜ ?÷Ñ –tœî©ëŠsݶø± Êìö! Ûµ¶`Û܇t;´Ü;¦nßù{ß0zßð·"7øÁgø)f—w8⳸€?Eɶ  7XÉTù)‚wôå +Ñ\¡œs!¯°Ï"úÃV³â£‚Ê<³‹€þ.µ–Éo©4Àg304œ ©ó…óô[ÈÿŽâ< VlÇŒ9Ñ,ú¾6¶™m50WÂ”Ä ƒ¦/ +¬¤M3­ צ¯-ê£`dÇ(’Eˆ‡ñsÅÊ4މ"¯÷÷ý%%IƾF§¥ 4ê™Û\Úé¨èã”Ë×$.”þ{žÐ×Ð’G¼tžJ¿©‘‚M†_:ᤠ÷/¬dEEƒS’l`4ígÒêNÚÜ ‡þŽVV#ÿyPæÚÕnJýbFÐ{hΪ Ò +ðp¿ËDð xi í™LõÃJ…‡-=9ÙJÂä‹!#˜l';î }½/‚øéE äî"%Gq©®ãï#LЬ‹AA¿«ëTE"à,N¦·<îãYð_ÊepÑÕc/¨¨sD½òŸ*˜réÈjÍû4šDÖ{ ò¥x jpùE„EN¾U‹cÄ!ÈS*ÂÅí!R9w§~~ã&Hë e—`"¯‹´¹LƒÈBnÌ* :Æ(:Ë!jèsòÕ#ÎãÅ m7?fûÝô¨øÁîp EaðhÊ›q,Μ+iÖ?%Ï$:Œ”Ž–Y)‘ïQOY­ÁBš\Öþ¡&|8¸ƒX;ªl—IÄD0|Ëþk˜¼žª ÇEG=Õ³›¾CP<š†üÈa™‰,-ð;+ñVÙ!Ž9úeÈ*9œ¢Xb'_3­~á):@ \7]Ìc ’ªL{©¾ò ÉVJ*žˆ¨’ÝxP£T$ö–CÄÆˆDÒä +̃‰‹ÖâM©ñ'ê˜q©wÍB$·œq-†÷B'N¤7䜪ìúcEFò*hýýÔäœ òf~©j–™ùÉ15“øC_ãtAoMÜ…S4ºà&s]ƒ°<Œ63 ?¦&]*üàùÖÚŒîU’;6ùRwD4«‚j›EûĆ¿O0ÚøÚ(„˜FcÞŸX]Ï”cþRe—ŸøxiœÒc°¢` S67uщ£¥™èn™°éºþLñèÈmþ9³¨‡YOLH;U¼ Au˜õgö¼a2‰-*aœýBɳÇÒä~"¥RžÖù95m¸»Á׋ê§*ŨzµIÉ^°K\<+ÿЦ÷¢<Ã1ætèšÃ®gR!vÞšf‚í§Oùš’£ µ:S7ø:` +c8lÃÏ öfkù}!Þ$kpÈ|@0Ö¦UJ…«y²»¾7EP‘33BCY+Ov…Š4­_œççV¡÷®ŠWßý2£ïaζïÛòÏ`“\#ÏϯþäW_¿¿Õågñ5n~ÿæ)mçæ¹oÞÎþ5îÞ÷fUì—Ïf­«q]¶s1¿.ñ²®[aÝ.oÛÊo³ÿ6»ôm;Û,û~ëÞ܈¯Ýø›WÚ¹¯Ÿ[œáê4ÅVïºñÁ«³v{÷ê׿„F±5–ì"Κ¾ ckÄc["ã.~®öCñ‘׸½x‡±·D`“-,Y_åš}¼'(û4fŸïl²¢]ú´¦YÛ\lŸ´m²»5ܧŠKN¹&žÛüt“Ç®Ùî’ÓÅm²çM޽$ãŸÊãß“öMfÿ~à•›“ÂrœXN쀲f. +œÓ¥ÍrDéçùÔWÖélÇÍ^å!]¿ïªÙ§ä†+wq \ÞÜ‘@I®90•J]N§œ¯*mOÓÚÀ`AìfÆÅ uVÎ0@QØçÁ±ðÐ ã2E'IÊkÓŠX;–jèÚ¡y6|A‘î^Œ×ð‰Jçaþyº†_Òƒ§Ò‰Ûk?â‹ÆÅ¦½ñÖñµ›†ÉÒVYú/ +Ë›FÍÚÍyëúøÒM{hÓDZ'õ¿éü_>´Z6T+ßÀ//] 64 ‚ϼâ„ ½ÂÚ”Ývow-Þ·V°/ÝôŒ7å·´¯][Õ›~ö[ãÛ—n:ä›>ú[ÃýCû>Œê²©ÌÌQ<È-BÒ ÷pùr¿Vä>dN…6w°‡³¿ u •qwç(sHÕâT‡ãQ¯jϛҬÿg‚úgÀM•Ôgdá$¨´Œ¸, [ïÑV0 °Ðý+8¢ N¶)•Âÿ[]›„"ÿF¸ üX9Š?Æq⇠}]½ª(~EÓÊjg’B0!c£¸Þ‡âqEd ÏfÊÞÄjR™Ñ‘–Y!9; ©³3ɹ¼›D¦U4ATÒÐ0²¦Ò7n&Ó9§÷˜áu×Ð&1>&s~¸² +jh!Rü)UØq’P;h2´ÈækǦŒ´H“^Ðÿí§s:QzÓõF‘k[k1û 4ʰc&1Y2£HËU‹¥K4Ž”Û•#"Aõ] ¡CDœŸíp¢µ*u,J‡¹P#¥¸¨Ÿ;ן…ñºTeôB³ÝPG¨.¾uBqPe'î›ÚG—jgj’ w{yŸ›š:](‡÷,ù*Zt}2fω´Â):†I¬IÈz‘c^•tì4Ü2IUÑá/Ò]þ*qæR˜„I3erIJA©§#×…îЧ. Õîè `†°N¶çâ 4c˜°»âs&N1—µwü*œuª]25a)Ù~»Ë’æ7^@Á¡#Ѥ~ŸdÝ-HÖ”ö¾¸• +*Õ>)š(ïms˜Ìî˜;ŸHPk•&ŠGû¨Èþ˜Âå§J¸´„ý]bwaúN©xí!?­"d0©ñDÉ¿C—Z3l‚}©æ[¡YŒÏrÛ˜)–™\»+û.̦WóÖÔñµ›îϦGôÖLòµ›®ÓÒ›ZšXv…›nצ'¶áWÙ±lèZ^i]ì½ú—-IÌ›Œ¯]hg6ä4 ‹CÕ†îfCгÂöð‚w Â;TÁQyiØÞ¾v¥Ø.Þ¾váØ=Þ!óæ¤OFLuzœ-YT{˜‡)Ç ^”ë†Õ#˜ÞŒÊ1“ £l‹!ÛE6érXS)Í×%£œ”+Âý…‰8è€b3“ȦТ™þsRªÅƒPŸ‰Óˆ ^iàßY‘žØ)àxm¡Ãõ¡xg~‹Ì®r¥Eðp,ƒÄö÷í±ðûŸ­G„87Þ‘4©cñ +#.pÚÄür¹‘ßGÒ\N¹aÞ0…t©3U´M;«C®ÆfÒgÁHJQ>f"@Ï[ ½? ໟ` 0¥ý)zßYj +óƒÊ8!¸­ê L@|@ÇcÌÎO“e‰ ¾aåHÐ +¢æ‚dA“ ÷‹à;@¦ aIŠç4 kÊ =§ú :Ô•œTü¦àe Ö¬“i"¯ÀÒ€mAkW)Cy\ ”+¯a&”½¯,žjÑíÇ.³ûãG…ɼYÈã#jÒfVa…¸@Ú–§Ì Ç¡ù` A4”Y1™~‚½Hh’Ófß6E07‰Ž³‡‘!Ls.|”ê‘j cÅIœ7Ý)ÔpÌaš|îǰ +ubeef;®ñ¬$Ñ4ÊlñµåÒñr’”I¬"f‘ÐÚƒ0ˆ6UáCM&h +‡ŸŠÅ•TÔ9øÈšU„…Ì2ÁMúR‚Âiåñ¦z¨“5f‡NdêẶ—akǰë«Þ.ëµQæÂú=0ÍšDO$qˆJkPcÒT +‹?Ìã ŽÚö<¡:Œ®!DzŠKŸ[X@=•z¨CÄC5C ŠOë`‰•4D- +Hñ–…ž‚ºÙa„FƒTȧ¤úD¤AÌR’ +ÇŒJAUü5ããéòɰÃ7Š¢¥‰4‹£Ê….EÞ””"PØ(^éÙ!©“JrÐ9òȳÃe'FñG N«É0ð}ÞQô=Èb+å]cA +=Cš©JÊpP†ÒÈÑ!ŸÈ|x¨%f?%&^êEªŒEá0ùY‡)”a(ÙQ’ž$C$ +ͰÁ–ó0‘ºLE©ìaiS+&Ìm*ÛóßI@Äç«ÔQTžßD–ø›“ú)wôîÍv>ïÝ7Òñ¬>tu´«C¶ãy÷Üÿ¾zž5blâÊ>þlâÔ6šíÃÞ&>n¢è.Ø.1y Ü_øM&°ÉÖe±Y?ÛU¶_ŽëºÝ¬î/¶Áv¿,»j¿ýÖ}ºÙÍë¶ÿøÚEìÜÉžg社rh‹óûaý¶7'¹ñ¤‹Ëý°·~÷Í;þæèý׈°‰K€ù°ìk$ZÃÕWamÿ6QrN7qw÷a|ï7YÁ>}XÓŒ%Ù'-kv³É–\ Iä&§Úe^KŠæâã[*·Ë÷–ÄðSð÷ r“f.éèשëAž¶*}ds|·· +bp¦ì¬Pqøƒ‚ “?Ê §q ¾v ^ƒÜdïÓqÒƒÑû‰ä`³ LÏiÑÊÓX´e G±2aÌÅoðâæE‡\ú™°ó\å•~¨XX½ ùMº¤¥E©t½E,20Œq¤–Ä:Í—z® +}žVŒµ"²aZqŒ,SÄÈÕl…À”ÂqÍ´° HkQ«BÕ$ÙÀâY1œãÀǸBµ„wL‹ŠþÝKŒÝ<¦—kåŒYçØtJ¿è©îÚ_Êwx³Éš$fÍi´#шØ^êpT&€i6M‚ä/¢°ä$ÕgþRÅσ~T 3ÍhÍ9 Á¼¨Â +2ŽÄ÷ë²×qˆ\ _bø ¤ÜòщRçZÖìèwêßU=ÈŒbæ4‚ZÀ—Fë»Cᘮøh>cYÉð˜£"F × Éd\šöME¸É£«ÒRD]GL 9E_krˆL‰À<'Ä  zøgHVa7Ó.w:â¢Ao¹ëù¹jÎélZ&[ÃÙZ“¦(Õ;Û8ÇP€©Üš:Akt\¤µMz#o!8“€Q²Qò²ÌÚ%H†ò¼´ŠES“Bh\Ñ”ó…š|­î¬›qž×ðÙHŠ8†â®ÇNÒ ¸X9:‰rBŽazèQE´y7}ÑœÙ5röMª$«VŒ¦ Ät¿KNÔJ—ègH¸:{êÄ‹ s³ö$î~œ7©DÏã"sÓT唳ÀN +¥°œ'×D­RY䜕FêbŠ3a´¢êy ³%d‡v@!èñá†=É€Œ0c¾,öéä@°€ñÀs©Î˜)lBÓÇŸ«Ê—ú˜\9öh,€¢w´Ñ±T½0X=§F/B|Vâ¬QòÇì’§F’Ôl·˜‚ŽX·S…ðC”Näu£•‚)`Y‘7¤ ¨?p¶ˆ[ &r`˜û +RßDÑÀ²ÝÐPNhÖ +ŸDa¥U ÁÁ‡(tŽÀA”ÆD,P#t9@Á[x imæ'€Y„QƒÂí¹ªÏžo?t§ªÔNÌȳ©Î†5qÚ"þ63ãQ¡€ß&Q|4‰ÚãàX¯¬ Ëò@ Ùˆñ±9PRD:›8=µø[5¿zS±¸_ÄÝ›Eœ(Lª4âDZÎn}Ö…VÅXEa +u‚Åx‚IÄE°£›1O€ð Ð4»úX<0dÉ̲[æ…% «.£ñ†Z&¢¬ Ÿ•ˆˆT'/‹•&õ’õaêu¢º„]S*së^Qu¾J±ÔjÀƹ$xf‚uþÍ(Mñ˜wLžþ$ŠT3À°zºrRZÒ$Ña€PLÙ\¸TmÀj±Ü#0q‚R¦¤Kéjôb‡€<°N*ÃVa:ê„¶ƒ;`wÈJðêi±©£‰$41ávYÇ#öÄÐ"f¿g.´ƒ'‹ÛÁ÷†l&¥—‰¬i^í!›“Šêf*¨Q¹X¢R+î’¶' Ï®N.¿Ì*a"…¨êCHïõè,ð‹‚Bõ. Fc²G/fÊ$ÝðyC,JçÄÀB$lA 6 ’Ræ0Áù¬Ê̹:¨ÝI¨—‡[$Ýù³”GttÁ­T1`£\"5;ì’I­øi>JÍp\…ç‹ìA 6Þ +^¦ÀŸ#(<ŽßÊ¡2çǬa|—/7 +Ô»7ˆâ…Ö™+Wv :ž~ãn~êµ/~iõ^[/·ó†[Ÿ¹ºÖ­^üôÖ¡o<ÿ.>ìÉq6qi `\mk¤ÛÄÃ5pzµ½GØM^â5Û×7ÑÉ>¾N(vkè«õ¶]›ûeü¾à™§¼o‹ÍÖY÷؇„ß7ãnË.{ûÃR‚oN`ç*Þ] +½ÑêzvjëÉV·s‹{ÿ¹q´[w¼÷ÛÿöÑb*›Ð³Q›`¶yo±ñS×®1thß"²/Ý„îM€Ë|í&eØ$oÈ×ÙÊ’ØüpN´&@›4i›N-I×&1Û&pKš·Iwã&±Ü¤Ÿkž:kzi&k%G]6Õ™º½eí¹Îs‹„bè01.ZúÁNºãɪ‡:ùg}pIÉU.B·áò˜å¬*ÎáYôšæ…‹>À³Ê?O' 4Á5ÃçÁáKÈ‡ÎÆ¬5 0aäÈ©ÄÈØg!¥òóÀÊ=žó,qObñÄù +6)P¡x0±5Q·zB‰Ú•Eñ­Zæ!Ô“!¡ˆ‰3ÅÜD;Mè"šÄ q“ÇGŽ“`˜<øsSUÈsð=&ÿüZáäwªîaðÛiÞl®Jÿ\`# ؆°ßàÎÐpÃô‰ †“¡3”¯&¬×ÄÆ©ünÌy&’dqM^hb=:¬ùš=£3¢eA±«²®­©ûš£1Uä ©]t_U|­ŸrÕ~ Øaä}M˜&ÒÙámÏñT›_m¿°€Mûâ»3`±йˆš±ÃãûÄ*•°†f,7R~Èš/¼9aä =wJÞF¬É!°ôX2X©"+âTr€á/x*[?0™}šÍ¯t­òà>×¹f–ðÊéÜ#½È¦’T7í˜Ç£p#M{ÇŽL%ždB´”ïéà ¯ì‡8±ú‡*—òˆÝÑ(€Õ‹h\ÄœGqÔʳñ€ñÈÌl/Mz½õÎhê“ЛUPW$/Ũ:À" Ÿ&Ú²PÄ=¡—yLö™ê<˜Ô˜1ƒþ wŠà7¡È‘‹ÎâGž“(‡ëñð9Î1³üòßйÔb^ØrÍl¡¬¨twB‚ЛH„²8™ë&8íô4 ¡$Uࣴ™ÕŸz¿¶-2L5•–ƒÚ Ý÷–f»äL]SŸ ºÃè£o¿˜êP\ÁgêM„ô4ñP"gl5Ìlëæp„{kÅ ¡3Iû©^ªWÚêŽ%whó³o!éφØ#ylbpÄ‘ ÿOÏÖùdˆ'&A­Ü.L E7-+ÀÇE<ëÚdÒ0©rÅžSš¦˜ÜÏç)È—R£KÖbªÜدª¢¨r•ætòµÁ­@t ’7È,9GYäÑç+/öýêFÇqý¢èüÐbèÖ~Ç‹4Ÿµhòþ*[ËÄü¦áò +ók ÒÑ*i³(é›y‡ôù܇ˆ×µÉ9ÌöBS›ÍEqÌ=θ™çcñkÈÉDó‡›,8§Iáâ(š®ûÐj6£i4Ë<ÂXÖ‘ÿ"79Ô‹$@úAoÍkH°2—’‹@n@©dÍ£€mGi^ úaúš’ùDÇU~Òââ‰Rqô@3ïS†‰¤Æ½gSWƒ¸á¨Þ­-‹®êÑTíDÌûWöŒvl&H¶hqêB1²(M¼€r“9Û¨ßÔ”cñÐìVœÑ[œ +§óä-JHEŠ¦Ì¼cÐ3Òk(º¦²g É#¨f`{ä1‰¶aÄ&ÀÆÇ5$=üc‰Â. Ùî‹RÝ95oâ»2ŽÑ‡;,è3|W¥Fo‰Ämß‘k2C)× ­:$K[üÐyuÁJdÉL$ú¥CŠÇRçysÕÍ﹆ 0âø_h$W7ÑyöX¸HÒų‰Y™a¢ó2ÅVptÃ&Bx(RBÁ¤$²d¤û}”yËš_ÅñL/r´Ö¥æbõ‘)âÌžµÎ°d§v½%¿1üÌ‹Zêì>ð½ò<¯F$È¦š…­‰]˜*˜Ïd$ªÅ]¼Š¨`&zžÖ—Î| S[¾^PŽ+Cg¶• ˜G’56÷­ôúmίòÄд¿Þ‚ÈÇŸ^×[Ýìϯ]òâ¾Èõ/~~ ÞÂÆ‡®ÝÄ—Mz W¾v×Öà÷$}é&šnbîú\7/`óš6ïóïsóâ×Õ±¬¢­¢Ír{_“ËÚý0Eðë"ßl…¯ö̺¹6[pÙªpŽ›-½Ùø«‡°S~w%‡³z&:åÕ…mÝê?¾öž[O»wÊ[ÿý…¯_âò@6afGtÊkàÚ„·5Ò)oæ{P]B/]ò&D¯|ñw©Á&Øg›”d›¸ì3œ%Ú$LÛÄj“€­YÚ>›Û¦}Kr¸d‘ŸÎ@×ts“”¾e¯¾v“æn’áפٗn’ëM +þD^j|e¶uâÂÏvˆ©u"’êÉð9ÆdgâèÎ ŠneÐ3×y˜,h'Ðõ÷y-§âIDQ +Ü^sÕá* #C¢&S²N(»8+€)KÝ…B¤Ý‡+Ìï§Ù@‡­QLÀÍJâ(ªNS.É/ÿ«Ãæî`º=Äî¼û³1eGm2懌œ„å[:˜:ônUoñÔÐ Jc¾^s<°"{*²uCì¯&—´ÓÌÙÈòêÍ€MŽR› ¹waÊF>Ê*¢ß4©NKÁ2¿ãR9¦.pTÅ¢CofêR7ï^=AÒtAk.«¦ƒ-a­5À#/t;)ÄQ–kÞ0r—_B&sèóà•§¿áããHƒi¿P@O4úyh@Ò©ES‹eB§Ëd4eÚ´—ÙêËl4hÞ¤j|åFÓf£|óª3ó¨UIg£·ó&Ì3Ó·UÁg£óó&äk>G/8—´a£É—¹­õdK"Ãfq»wºFÐÆ¤-Lì©jlØcp°ªW±òŽë¹ÄÌÌ‚AdÔ¹ùEÆÅqåx­ÅY‹Ä\sã˜|]æ m´½ˆÚFjíU’Í—n¤ÛV}·78_ºŒÛÈʽéÏùÚPÝFÎn¯{·ÑÇÛˆèmÅö6¢|é¾­ÆßF p Üë +n72…¯z†Ó©†h^›*ï[.R›¤ATDÙIT›mŠ( |4wM ”Cù°£9q´Fè1Á•©i¨Ùɵ‡Hé!ŸCâx›tª,]âŽ4žà‚²ÉëÙ¾ÄË”¿s{'Â# fB¦.¦5Ùzì 6˜âúºË±ïˆì»'lØNâ·3ͳä‘zq†Üæaãÿâ -=uíq°8†ç¿Oª•Kä4¨ M™—׊Gy>ónS¢>›e¸DÈ2åF¡–+’h&ø¾zPÃ]·&4#¼€ªÉ”×.>NA~)ÍñpC˜ï +NÇ…ÃqÏa´Gs;Qå&±¤*°q,K¦`Ý=Xçóg3˜–‹ó1ö¬0vn!wbõ)Ø•‹}1êK=>Æ.QPjí\†'„ŠÚ”qDï@]ꀓï„X÷½4ØbïBc‹ ™CöF¹l£oö&„æk7Ši]µ76_» +µmÔÜÞdß|éÖ1˜¸(ÛG`ÑdZ9x@¸NùàE9RšgŸÒªÙR(`ÉCRf2)Y—ŽÖŒâ"sÙ‡êQÁ$-‡^k†‹ê!ÜS™fÁR÷håIÚVÁóÄY"“®ŸÑ ¬_Híµ…6 +DoRE¾v•4ZeÞä‘fÝdÕQÚ¨-½É2ùÚ~ÓFåéE jÖˆ&‹G‚f=³u¡Ñ¤r?hjæSñ_e¹°N²71BÓ”4Žx×Ì®%«ÌUw²ÌäÓ g¨RuIvŒóa&OØöÙ$Y¨‹”c8ù&D+6gŸ>¨‡½9~¼÷ÔâSúåu `O¬[¢Xr~ n b•d;_ç†ý'žeÈ•‹Î3Ľ01HЉqAÓ2Ñ"úlºFˆ ¹F"Ù2¤~À8¥>È›‚ Á°Ž7ók#ÀÆ4}ªk„òÃ’T$Ø"t1!}®L€@Èæ2°)À@Ñ”ÐçKØ…“MзÏ5€Rô%ìßgD*ª|âV¨3‹k6¤ŒIŒáz¡su$}IV·÷ÜpØëüs8ä(Ê1>‘#“¼ƒÀ<•lƒ¤Ô„ƒfm +«”|I D¢:èo )þ°Â“Wì·‚½†Òƒ(èM…Ú ¼4é‚Ó˜„¬Òh‰œ>ü…ø :=*ÉK 9 ó÷-UøP(V” +ç‡ñ·PíÃGŽ¡ÉOüÐ Þ8?vHÅkå4î‚Á^M~è—éϲ&ËPÁ#\™3 ²tŠØR C"·6à ÆTˆd©dÐn<|$ìÀ=fÌk›gR +ÒfAÓgqêºpÞøü^Q˜U“%=Rîo¾HFÍòhÙ#;:Ï Ì=ÀÇôM$ ÇÒP±UŒL(Kƒ'Šx?ÎÉ ¸  û¤\ÉÚpeè÷Œc`ŒÊ5KK¼gÐÈÄ’Ç‘‡–Ú$Ár$­ HçK±!MÌ2†bCЗòÈ‹KGÔÑèæM9­‰=.ÒC’Y‘±‹h„Zû⎧)>d02uPhf°ÌMÃ*Aº“ùÓ1Ô_ôó«?ùÕ×ïouùY?äãÞ~ÿî)-O¯óÔ7ïf}‰ô[ïïz³Ö…ÃE·®°Ý:Ü.ØÍÊÞ­ÿe£|jƒ¾ï¨Ý¾[6è§6貓×ý¾:z®Ùø™Å!}í¼ÞÝ]×ê 7.óݳ~Èé½;à—~÷æ¾rñú›ØðC>äßcÍ&"}ºÖ·‰„kÈÄËØÄÖM^CµýÖÓ×È¿¦Ÿ}Ï%6Ç’™||Äìžk†²|=KTù™$u­?^3'838,ŽbÇăáwyZ¾HÞfYe8ðÀÌ[‰Õ©¼UôNÅiº›ãð…XùósO–pãëHö@mè LJEþªà‚„¦†^¼ÿê¥Yãžï¼‘°òx…VÖÓø%õ^,õ{p+äPwæÄþôóãº×~~±+÷ÛwÙé?æþ{:„ÓX½Ë‡ÄÙßÝÐÆY-Nûlu~¹úÒäÞîêš÷zûFÖ÷¶}¿»u°Y-ûeµ]ï‹t¿˜7«~Ýë&úz¿-[ó‡‚í²‡×¾8„-üÅslýË«ò¥ïîjñh‹ãûÐí.rñ£;w»õÊïž{uðŒák$XÃÅVÃ×ø³©5˜1„o¢Þ× úñuÀÝÅæm¿OXË]_˜¡Ý˺Š)Ì{Y«BÙº¤?…ÛÊ$cÞ‹&Îf0éÁDshs³6U ÛĹ³ Ô¦ÐÇgïøO&ÎQýðaŽÖ]âW³™‰·el(ÇÊaðœê}%g£æŸ÷Æl×·ïäüe^`ׂ‰S²~j +CC u?òÐ˜ïµÆöØ|ƒ0¥žü„&G ¬j@˜¢. !^&ž+ßy®+$0Ô‰Æ VZa2Š&`Ÿa"Á«MîgÖÆÉu›¿#×_ïLÖX„ Õ—’ŽKë¡&ƒw®éswZZ~7Õ½„š¥ñBcƒŒ“"xq>ÎG2˜q +8ÓÕÐçQÓ"JÃÓƒ(Ÿp ö± qæììf’áSó5H' ê"Ù/›V‡šÌ0ÎOðÔ+~õªkY™QÆwA5Âpº˜y‚‘¼]d­W+ö;u6ÅŽŒKJG]ƒ¥ì•ÌòHÄáO• 5PúF³‘O[õÌäÎB ‹±ì^Ä”Ý3Ù÷4vý}©ñ«²ä¾„‰¶šš¸I¨ÏZCj¾ß.=ÅBJsÞFr@²èayúâ±ÝI¡r Z™8®Gï +ü™TF‰Ÿ¤\|àIùRå¯x3d Â«$tŒGÚ +Ìx!WVòÑ—MÓOUcÃ@ïrU9¨&ØæzJ¸1>ÿnÖ2‚k¬µþÇ¿ü‹úË_ýõ/ÿáßÏÚíK6¶2õ¤«æK~*O àgùF3"³(<·Ir… œx ï©lÃaŸOÖõÏž¯ê?ýå_œ7ñ÷ùÿæ/ÿâ¿ûßÿæ÷ÿø‡ÿéï>ÿðwÿð÷ûÿï/ÿlñ—¿ù×ÿ‡_þê÷ÿúŒN¿ÿû?üÝïüÝßþß÷÷ÿ×ÿòþá?ýÃüë_þ{|êÄÿ臄ë‡,?öÿÿqœŸó¿Yú_É;[gûüÙ88“Ì5¸Ï7 Çx0J‘ &0¸’ôo—Óï—^†Vô·pêèÔ°ät.Ok,’¨;-I È‘lX"­#qcF¨jHÖ£x.[¢Ä=mç«ó¤YßF—ÖzŒÙ ÅÎ䌋44ämm1ÈÓE¬{Ži^¦sÉFªãõ§5¦bwÕP[@§ìiŠrÓ¼ö²Â%Ã!iŠsRCA [ß+¶ïËô©_"ÑÐûƒa"©ï?w›žßû°žÏ8 ç… u&ÌWÂEËÓR%íÎgváÁgJ5NC¨+M …Üz¤Q¬ë´Ò·ŸyÄUB (<`ëœñçt²§ ¥K}ö4%Éì=M‡ +Ÿ¸ô²‚…ãMg85r´"aÐV@úeµ9›I÷ñÁÃåþs·éù½kV¿7 æI ü j† ƒr‘óçvjCžç*>š"Jð TwðcÌRli"¦ù憶 Ë^õò„Ó–­Qü¯ VšÿÄ+¾õa¹—ÂmœK¦5GÑk]µh¬Èsý!/F(ÐsjãúS·åñ£7Çý§æº¿ñ±ÓÚuáõ±bÝzX”ØZ•Ž7rú9`naúÌ€~Øà/P<@pnóbÒMCœ )zJÿõœ,€}ù(à^päº-ŸÀÿKùòñ± јÓRV¿þÿ8xÅýÿ3«¤®Bôn£Ï!-À¨ëÃÂæºÑ +— +sܼ£Š›úµòeJbó»Áˆ:?KuaÑ£Â@Ίß:œ6^+ŒÅÉqçôƽùvP¢„….¸EëL^-=ÐËÛÏ3šô0–¦ 4-[ÐôT5eÙi)ÒDza&vY°lšÆIo#Ö<_Øõ§nËãFQ’aΜ"‡½f¹lEž:{MÌï~ˆMú/i¡’6zÂoÞ­”bþÖ1Tè­ *‡ïíTØ=¿évB çþf€¨Üoë8¬¢|;¿ôø8Ó«ÛK^&zØìš×ýÁËéòÏ¡¥›ð½½¿{çó½“ð \½fÖ:58vœþùh0”vÿÏHAœ—G〾·5-„sˆÌpr¯¥8&1èqè¯÷ Sãx^1+3OÓ½Ö¹d™Ê_ëŠ B19AÐÐÇýA¢pŽç +|˜žßû°zsðÏÍví &|uφ Fý—Çó|#(ÝkĈðOloR~<Ÿê¡©ñg:5ÜÃ3E2ƺ­ò™ÈÙ8lFÿƒs`do!<\@=ª§+‹èUpûþ`í–8nñi9tÕegÅŸÑÈÆ#\ÎóÊÿƒ)ï?á· KDWL¨@åëÌGÏßï(#zî¨nÔ_`¤©,i`;´Còß* +]‡ªéç¡7Hjº3R”øîjéj­ÁÚg½ ™^ +,9o'hç \Bý†“<úØaÀ¦¤¨ORà!î'’f a‘2Rªbv ì+ßJ†Í7Hª:¼åŠ3CÕãÛ? À­ƒ]ÕåƬý¼ø<ÐS}õcR¼ø‡¬:oàò#šô{ó¼ÿ\þá<ík“¿ø<ê +â‹ÛAŒÃ°ÛA ²s +H|;<jü8ˆA`¨ê ·ƒ@V… }ú‡N…-ìñË?ôfGþâÃ%¶‡èÕ‘áö'$÷ßþ¡£,>ßÇåzÇ@ž£Ó?àé°ùâzë*Ƽø‡Ž6èCoÿÐy˜=ÏT›çý[òevÔ”Øàs5¡ÿàù™§ ýd´_Àçq&!Ðú¢”Óï*ƒpS×ê|OµÌzJúáÕ€Úo ©Žó1, ¢üÏߢ·Ñ.GÁIIÀ)dÿ­CêmYA=…‹`WçÑS´á=ºÜsæ»™Üc`˜ä„Š5m•i +·³ +èÌ¿9ðŒ0yO#Y + ¬ïÔ4è·ƒ3ƒ'¸H^4"Öåw R-ö×]8ñ Š…²§ÀxÀ³å01Jˆ’FMÕÓ×ß÷ÕÙ(amG•ìÓ˜”Ë[§¿ˆ¤ST5/´UI´Û(ø +&Ь*ÅÁsZëL¯0ûoŽ?Œ sÚ·á`Fø~·:l£x@…ä”iÝP` +Bh ösG6”_ôôëUálPnu¡zö£vU—.°b^w¸›ël ç´!ÓaœB«˜BB!ty¶¿¥M!rØòë¦Ð¿‹Ü¿s×G°åÑÛþ\\ø©ùeãÇ~•¿ï­ÁEOðýsïGœ¬òc럧ëÀ¦Âo·~îËÖH{IÕsí}ÕÓé¿çæÉiÏÝ£¨XèÛ?‚•ú`ä¹ÿ)V‚–Í‹ÀØ +§œgEá8/‘"³3|ù€õIÿÊ> ߯ãvœß¥¸½@$á w‚Ý@ÄÈ%–~Íæ§@­?þÒ‡#ˆÑ·'Ð!ý(W€gOÔ׫/À´ebça:…]‹œÞ bÄ’5ª‡;ˆhƒTàé°þ2AJO‡[õ´ÑÓ#ÄF±åøâ΃ŽÙ/Ÿ1Z¢bõåÖ‡ý_Ñ+üçŒpìS€Óòü †VŽóåF²ÛŸn>º2Õ¨üy†·èJÛVŸh1ÇŒJT™úÁ˜å#‹j¬5"T¯>VááZ0ëÈ9Ć\àT(‚â­b4¬«r€VŽÖ@šx(‹Ú8px~;‰TQj˜ éÆïˆné*"£+ªz Y^ êRt1°ñLœ'ý"’5N‘ȠׄG‚'¸5QK-ü®(xûþpÿøŠ Ôs9õŸºd e ½’¶«e%Ñ-üFÔ¹ÿÂ1É<Ñ_ q? +™üéAxÌ>ÕMbyÁOG¯P‚.<ØùÔf°ˆ–§IÜ?ÊÄç‹Cu×%ÔJT)ˆÎ´¢_ƒzVÅÐ`góÊ åÌø¥ÿ”áÁ÷©æ+@§ª7(#¤T€\¡|(}¨HP²›$•ÓYZœƒDOüž^¿“wÒÝkãc‰¸ý{ã÷sã•{×w¨rÌ–ÔÜõ„O¡Þ»–ˆ{íúŽuXç4‚w}Ïázþ×®ïÄɪlsíúŽ•‡€ýÜõ½E¿ýk×w УQuízXHà³>ßßÄ®èp+Uz„û@4öHf¼Òw¼€²±Oú øqz¼DüH”±*ÑwÈøoªµ_1& UÌ 1·ÂKŸQÿ 'Ò¤ºÃ>R˨|aÆýˆã±üø£ Æõ5ò#}wãú‘ÿ«ýý1‰K¿Ä~dÊ*U]ѽ6õË®ð¿yÜ¿ò2Šù~-wpß~ÇƒŽ…Ódéa-˜Å!ÄúŒzÂ߀5#3¿cyõs€3…߀«Ï—µƒ|ÿP†Wˆ’øÖ +rzE¦sƒjRë´6ÿJqïú4uh«ü‚»&æá² ›Ý‡¬’“?àt%œ(W?MÒÃ¥·w¹ñ×Ä‘Û0mŽ”³££-¸²¤È{›3ØA ãõ·nÓóK_¬l{{L¥vxY8=˜Ä¿ÔPMfò{<ÏC0Ý×§Œ¶m;Æ$‡æQÍ­–âàŒ‡ØÛ´ÒËŠY0˜Ôé£ -[˜ÑoÓ§ÆÅ‹×Ã|:@0°þú4% `óÚËÚ-1?ÇWvš +H£'ªÅt™>5ž ÏÇÑU?þÜmz~ïÊ6g+Äô“vŸ÷̲&g¯‰LuÁðC|2âiCñxÜï‚êGA7«ùE¿‹ž‰øpv W# f1ÎlI¤ð…ÍL*÷¢ì»˜ÃîaJB~j¤ÙÖÞån%0šºÂ£þ"ºÛpý\†¾:yéçgÎìžññwnÓó Ö&^æû5ªC”û§wz¸¿}*X‰rÅ’^¸ËB K¬E¹ÿåpà%ØŽïµÇ³éSREbº»?ˆR<5Ñáy9ßEýa*ä4ºêɵZ7Îüa}8~ü…Áv%‚ÄøP“mÞÐMÉþ‘›•Ä ¸ïpdñãJ)=>U‡¦ù÷9uû4eáÞý°¦uX)ëèëIm.PÌtÓÂGgÅi~ k¥Þ ºg‹ö‰aí,"Æ_Ô€¼n~{Pè¿Uÿ]#¬‚w¼XÓ!Ð óf2IÚÊ9\Y‘„ežz…8{\¢`$´ö2y³Kûàþ ! @uÌ3?MU·¼ö²R3üs•@£¬Í¤ïãaúÏ™A ÷»ht¥âÃFŠhЇ5 7 ¼gàFàêÄ›ÑÙÔôŒ!àÚ:<Ÿ+Ž?ä{Z9òÇyñŽŠ LsÌtÀ‘ÕÄLš^LU¹Ê§xGl…n£†ã|\)Mšঅñ0»ãw.´y'`ïžéaêÎÎK§~3‰5è<ñD½t²w’°„|Ÿ\ݳöx˜jË>ŸÖ•Wì­ÏÕMÞ4äËÜ ‘]Öj+¥€Øˆ&&n¯&2Š:O²•ÚÇÈIõ¾üœ(A ;cÕæ69'¤ìÏóƒCð§ÇŸ»MÏï}X©ˆãÏ)O¼óâ5~âyÉdhjÒùuº¬ Çf)¤#aÈ5õfB)BÁ +J4Õ— ÂlíÜ'}NÕ¬QT²ÇZi–Ê=Ã:°_°% ®sæ +T¦KwütJ@3çƒÊ ÆDîBÜ xàÑ Y·%h¦<ÈJHâ~Z»–˹ý©rÒxT¢ 5œc>›ä"’íq®±ŠÖÚµÅ:‹Òç_0›Æ¬V‘·bó´ÝŽ.‰sÈÆQ1FÝ„æÍÔýc×ªÛ +“ð‰H{!e˘ûçÕäáx%e°#Ízœ™Q0cߣF¯xÍ œç=°žEÁl²|Kw÷!(¬¨G<-ŠpÚ耇ùZe`À3Íä‚C£§4 œòDþ]Ë0ðu`΂0ø%ï)¸9¶Ãig%ò¸F!˜ â|œŠ0åð‘ž&’\nž÷o ¸b¢„*æ·å1ôa°œ0’  ˜m1g¥à™èJIµ![õëýyR.œ‡âQCXx±OÓ•G‘#Çy*!_*¯ˆ÷B•.(HÕAð-ñ¡òª¤'FÜ óG8 ÈÑ^Êa£LˆL36˜%yÜ XNqÎ:­A¢!¸4%øcù§$}ÐÁŸ1§ã0¦ ÜŰ|2Ç¿ $à‹I\´üšn[ø¯ì  ©ƒézj¼Q‘\d=kúSŠt°Â5.ô6 :Ñ’¦£¨~©ÇU.€n¼Š$Ð ¸ŠXàr¨HG [F@4tjpšø¶9ñ v&åWM‚˜N€À7)<ƒ­¥‘agmõ€á­Àô"JWr¨[¦üÁ” +íÐ+5™;Ö¡†ôƽøePÊ?üpêEÒ×,÷Ò­á?|Nª.3ª ýtI,0)Û<îß’(€{q µ3–³ˆ_¾Ì “Œ³9;74~ZHn;Œ^# 1Š&ƒo +]¼aÚ}:€8OZ–áiÎŽÂÆ… b—¦³ð,¦Å‰Î®‡ë@%Íc Ø–Èßü?‰.:çýLÍÚ ¿õCdŒ6hRàŠZ°ç{ÀaMŠ"Õ›‡SÎ"§aG¢z…Æ5 +•àóh‹’ß`Õ&†êõiÿºk‰DáCE²3¼¬¡j´9ywÎGµäEú]$Y½ÐB3&Ÿ åöì,RI%F={¢Ça˜#\6L,ÉŸq4fû­ÁRŠ:£ޏ(‹†`22µBÂÎH?È`s@;Ö3ýÍÞr}Þ¿îjJe²Ó7fÝrŒªËa“£X˜¸¥†.JuŒâ/d/¥ZîC…3~|,<>}— á„ù[MOõ]¢„f3Á]P†‘LE@ *àé$m—0k›ç°à:(Êa"g„‰\n”oS"zŽŸ+îÐÐÙi-ê|×:t{'y‚ã»…LkôÓa«ÑIbAú0”gg%„ ¬M`‰-˜µSb›çý[+):ò<qå ”¬WÍ¡;UÍÜoWªšÃxÍAYsð»rÐ_kÊA󣿠THcײYX]sPûîÎAUsˆNAyâ½JW +ª’ƒC™‚Ö«ä þ¯RPî›»ä€ ô¢a¹øÊ@ÙsdÉAAJ(ÝJ$½2Ыä°yØ¿r§XgŽÓò lìrY¯š‰ÏŠÃuDTÅÁÕ{AõÚ¯ó:"ªâp5®4/r•®#â]r˜GD•¤¢~Ur`™™t·y–pƒsŠâ¥ä #b¹J½ÞGD"yYr˜ahŸ%Ù|”tDdkm–tD åYrX÷ot—R^j WéJµrbˆ½K ¬\ñ|ÁRCjw媌Yjˆýµrõ,5¸ruW®ÊÕ]i˜•+UJx­\©Ò»+WÒu¥á®\=+ wåJ•6ïÊÕ³ÒpW®ž•†»rÅJCt•ëª\]•U®8a|UÖÇý+/£»ØÉ³/Š +/¥e•â]Y¾* ª,÷>+ ñ®,s ûpÃ륲ÌJCðãâù(?* weY•| +ËñµÒ Ê2Ï•³ÒpW–ïJ+Ëla°Ò`¡¬«²üRi`eY»Òp•–_* WiY•†ø(-sÅÎJƒJˬiÌJÃæiÿ&ÜÂ}DRNÛ^Ϥ:CTI[šgˆÓëHzŸ!Ú}"e—›ë©…×éóqŸH¯#Ä}"½Ž÷‰”GˆâÅu$åµIñ8BÜGR!D8rIu„p‡ê:’>Ž÷‰TGˆöv"ÕbÂÕ¯éê0šû£ú¨ÃhœÕÇvFc}­>Þ‡Ñgõñ>Œªú÷y½ª÷a´K]0¿žF¯ê£N£-=ª÷iTÕÇ)D=O£ª>Š‚â>>ª÷aTÕÇúv}Vïèª8Zó0ª0hvçÍãþ•—Ñ]¾P5¬¦×zÑU¼ FWýQ#MãÜõGŒøêõÇ»`ô¬?Þ£«þxŒ®ú£ +F,ËÎÇ~ŒÆ£ù(ͤ +F|{ä]0z U0JoÈ»bô,@Þ£gR£2f‹ªÏj¬ +T·_ù8âs˰Èxœç×:XŠ,€ƒÁWœÿ#+ÐdÂqàô×íòÎìsvê{¦{ıLk €!ùd@€Œÿi_·ÊJ¯V +HÒăãã¥7I•1a:㔩Møþå[çEÓ ÓmKâN§ ÜÙÔì ÈÒAöð í't#RôC¬GoUôûß6R' jA¤+ç‚R.!+Ûg­ +endstream endobj 65 0 obj <>stream +K°€&Î4ÀˆË¦&zòO_kkÀHÅ9—¾¾ñp`QÜ)ÓÄK£’ÄñXŒ×_»Mϯ½¬È¤ˆˆøç¨qø~‰×aoâÅëƒsú¢Ÿ |Áð>÷“hÏæ#…¼RKíå1ƒº±™~4!Ïø&þ‚8ÍÝ£¯Qe|’{àJi;ó<|håR)ø²ñ¾Ë fИú™ +ôö43o^ïiZQi?ºžžÀ¨Áyò¬úêBúÀËÆ«AwHaÝÇG¡ø@ÔãOÞ¶—/˜.0lˆø&ÒèÁË«{Å › –‰{5.´‹!«ŽPßeè«y;Ë?’Cöé¾ÀïC§-°u‹û¢¬Á‹ pÜÃÉ·¸Á@O‰!|*£œ~=ØŸÕœËFGgŽ:Îó£PFTð'O/T^l©HwU~è2“o Ì|?‰9ÇxæCÏoŸ6Þü°6×ã£Ö” ¶AÚ)Pº‹:4°eÈä>=ž»œ6(«ådò«IQ‚=C[ZcдÎ7ÈCéøFåáØoòçôÝ"ó™&þî)@ðø ˜æ±Äü\OÓ‹ï¾­—“ç&DW(XbÆûÏÊcQÄ ç[ûþ’KF‚­Iôø§’e8º4D¥À\ã]eÈ|ÃDÇP1)°ìç·Ô©z¢Ç›ñ¡ç=Ô/ ’FÆÅ2 /XIÉ¡q¥?MóµÔ§5 Š{¦ŽZX•Lìä€;³½EÎSœ«;Qp/fü—o5/†Í¦ëÜÍueÿ~ý¨Ûœ¤U¤_•ÅØ|š¡º 7t?OPQB¶cóàÿxƒâM<Ïc2_ÞùS ù °]dG+2.’çfÊ1Ü/ÕPŠ8iãOkaø©›r×óI1ÏçÓE3}>ÌC•æâi¾ŽÒw V”EI¾6ˆÂ?lóF¹3.+Ïd%-AszX/ÀS踂2jõÕ/÷²‚”¸z‹ãЕá‰1#]/ÚûùYœlã\·5HfŠVŒ¸ñÈ„cW`¢u=N”걫7Ïý×}±g¢λ;ÜþÚ'Û§£H!ל~‡eæ`/ËŒâ[<ÈEÈ0ž=Ù ¾Rÿ¿ö®­çޤº¾Gâ?|/H(’¡.]Õ]8!’s)o#ãù>ÏDfráß§Öe÷é>çŒaÀǼ€FŒg»ûtwÕ®ª}]KMôè"Xî”N@ÞFþ 'qF×êšl²ó¿›Áó¹BŸ*HIÐó8_D}x”Å›ò|¿ˆ1Wà™œ?™T#û +ðHÚ»áò᯳ßt—nYØ|%äG˜Û#sHYŒ³»_Œ¼ŒQ¿ nìå0ú+ }•àÅËBõÁê~oô?ñvGõÍ„½ªÊ…¤m$LUoðxãyèsÌÜ^Á[F3Œ3ÓÆÈ»‰©X qßlx"¨Æð¡ª6R9$…:4eà{<ÊâEy\Ä™Îé¼ )BbÂ4Yom(¬GÝ*;°þ.݆ÒÞX=;éT¡Ÿ[mËn9ëê‚ ÀØ +.? PD<0™tè¡›NîÓaTIÀ~ygø?÷®ñé]ÝJë‹>ã`­òu±¼™v½ˆç/%3"à$Ÿ +ËÄÐ√{b©´‹ +Yí"¸vÛ‡N+¬€Á€HªG^Y˜dV;¾fÈb¿`8WRâr³#AÚŒ¦{P N¬?Åðvþã ÁœTB(éJ›pä^±ebXW©ªA<^›£´¦«À±ã¼©¹›QÃYòÓ½‘ÿ¸:!ä˜Û¨úvQ«ŽtY}02†Ý,¤|cÓ‚ j!ïpS@•—aøbr_õbˆÐQÃPT·Ëk‹gÁ4û+0RƒœSÓÅÕ#®Æ9¤w Ñ;ï>¨×;\‡ý†Ø$ÁŸ ÊT ¸‰²[”¬-}c•4X0›K [t ž®EC6+ÇNR¯“{´ <ذߢrø0’7Cþiçô;"æ‹„1Ÿ©£/k…G(Liã]œY0ð…mïY"Â/4OoS¦ß’LR àŠaðfd-Â]F|fØ\Жw®t¾ú"§†À¯a Óöéô¢–ñÈYWwwS¼À–EiI0þ R¯S- ‹>3‚<8Jƒ < ‚-¤¿ÚGó +äk• ÕãêÒÝn8 +»‹m‘{¥ç‘J¥ÑÄ6vgà?ñîÀŽ>Ø:8 sRÆï²±Údó•SCµJAï|+ »‘ ZLf…Ñ!U1G'm6 1¼°Ç¶áú7Úð³;!¹ŽÒd—¬€â¾¼¨Eïì®*B~¸áü>8ð2F!Åšœá#ê@^ ]üƪ¹ró€j’í8|ÎÄÂ’óÕèÛ$ûò•¸™ ­Àç><9û˜|»Œêíø?~«¸@K,¨Eq!°£ŸX,5© ’rE9ÐÔ£FÆY;iCm¸ଠ+T¢bMDʯ}Ôæß@xB¨UH[zç=¦øõ¯aýè?¾þúíûç/Ÿ¾úðöËß=ýíÓ´ªb·Jʼ£n›ÿmétwiNÀS™%*j¦ú>½þjþ,pÔ³Ân€„Ít;‚¯sÕéwožD–ô?çø t¯O;v^;Øô°AoïGvSW%à©.|ýî/xöëïñ칿íh¨uCÌÿ ¦þõëïÔµ„&‰© TÕ~r¼õé'ÿúÍ·¿x~÷͇/çDñï¿ÿÌüäÏo_þåí|êÿáž~ô?ýù?{Îõ›o>¼×ß…ª?ýè§_~óëç/~úóñÅü’_~û‡—ç/./uËêˆå•*W©ªÅÿ‡²hÀ.|—óS§î +G)!³nÝøŽ˜ +«äU¿¨þ=-Î܂ԤiAÐ×+ÑVÑà!óÖלÉ-VphçÕ  •ª#©3Ñ…üôf¤Xe‘há¹F•udBxs÷EÞPI¾S=¦õßÖü§îDs§ùûÿ–}’A;Hàîe¥°úFæ‰[VÇ@Ö‰>ÞøZ¦í~ィ«k¸¿xÊ*âX,ýrï~iÊD˜xÌM—×½Ãí[wk +ªÄ“2›±¤nƒ +Å| ï]³/×V;¹í]q&+àe¢å³’hcÅÏF/´âÁ¯U›fiäï®M#‹£n‡E€Жéá„­fâi¨ˆ´ Æ,‚èEç 5`ÇÂÞY÷Nª$;ø‰t]WcÛiù›F§Â†š@>Z¨Õ Ï ‰7_Qdâª\Xýt|P§V¸LAÿ»‘ÉÁ¡Ålq1d…x;ñša¹H „ºypâmN°ÕØ{Iva¥ 9ŒEÝ/¨üñ³ŽBâÒhN0Í2ÞìAx.íà L>È´r7­°ã¥¨âêÒ­ª¾á)«Î}ãáK|JA•“Â[3/8‚^î Ü®|Óo̱4«!üBe<Ô¸ªvDÖ],Ü729ÌlÈzìØ9’p QÞÓui2—ò¦”‰ß~p|64%bîb}z݆^ÚÓÓ›KRùtÑD€‚¦¡Ô'ÞÝ‹ºODTí@%—Ä6ÈZØ]¤qk&5:\¸E=ÒæÞˆ9iF×$”4å-rí‰ð›sÿ3#i´*MB~ kQÞÝ?>zFÑ7Ç)…c&ñ·ÇÕ/ûüöÃù¬Û5+®…¬ˆ¸:áC¾·Ø˜¿ôFXQw•±»È¨ éÓí +Z‰Ã$zÐ<|—^@e Ë,¿š²æí™Ÿž¼ŽöC6$j!sW:|“ZJ\~(3e–wãŸTÅWúÎOÉ5\c<Ü.»Z‡³&î¡ã">+ÔåRy£ûE´¸xøq •iÒ¾8G,èË¡%c\ÄŒw=ƒÊå£0óv j ,E&I´ U…Ï,š#L!uðÂ$1ÐÀ10º½™Þ—J<‹Ö²ñ¾Y§ë´Sö²DñWɦ¼‘¨p¾x¸é<€ÝÅ…„—ôÃWæd=îˆ|Še?Ød +:4A¦"D¥Ðn¼À¿ÇïÑÊé€+%šäåBTšŽÞŽfNG=9wº“™3wuÚnåtäðY/K+g•“2âaÛjùµT¼½ÑÊ!˜È”5§7(¡F«•Ô‚?]“¿›ë—{üVcvqæ ÎOì-÷Öù»Gl,ùé9 @(]Ø"Þdî* 6.‹1h¾òR×í#>„°çÃìàž»g È´´°-wŽ +jZj…~ñ\äúWõÆ.Ó¶°…Íq¹´¥h€ÞŒaIM²5 +¨´ÚL0PÛ¢õÈ-D æHï à%C= lNæøÅ:Ò†Õ -dÓ+ ;5ÛödYþ”åhÛY‹ø¾bSšŽÁ@†Rä”ñEÞOU›87b»¯ë^Ýûƒs¥>ôl¿è >Ì‹zêâ݇bqBgož>™ ×»¨«û"Óí9¦ãr)*xe=²lxµÊ{Ùš!Š5m-š«` +'fj¶l© Ý6·{¤4ÈØô ›®‰*‡&šR +ŠzP–${†V †Øj +†½ÅÔXó–1U”–§{ +ÿåçvâ2#h§ÎWU´^;8İd×ù^U!.p² ü@ ʾ$»Ë+)Z + +y„ƒ@ V‚4ÏÀ¶ú°ƒq,ÈUJéqxY‰XÚ¨!s×_§mÙ`×$€åݘ°**þ+îÞÙ”°ñ1šYÐJ*º¡]ÆÛsêäEÌñˆ1‹ÄqdŒ‡¥ßf¼¶øåþX?Ä2ÓJ„xA”¡_o©™]‚#Ä…,qe3M κ…Ú®M žeoŸ Gqa#ÐVmÒ“7´¬ŠumŒ§éö*º]î<«ù“&öÛW2::šÆ2MÀ¼s€›gœqÓËýx¨%ì…òÝ5öºâÆÝþ)£{œ^½/>r\hÀž3¥öIœ­ÒW?î.µSœÄ¬lWº‰’ßñ¬š·/ýX§šùfÛÁ™Ný¹úlBš·«Ïƒy›ÄȳšíÑ`ýcÙŽZÅ¿‡†5’…ô¿:é—¤¾º)Û å '§ç œk¸„( —}+' ¶³)BC:Haôýî%W‹ æ)3‚2ƒÌ¥ \†cõíÑ=ÎîÓ¶òIYQ†ÃˆwW*œæU±Ù4X J©(LYðTpÛ¡y}Žew~ÔË0pãv“úU)¢š¶~-F¯îF{\ã8ŠáB¸Qú¤žëâèùY=oÕåg×`­ióáÓ‹|ïïÞRïqaëµÂöÜC0 ¢ÉCÆvGŽ&Ê`}NunS¶GKnn˜Þ¹š0Є}wI®"¥ý±PçÐ ¨À$ŒeÌ?eó*(Ù|{‘ÏDEB¥Enö§9™[Ô,\²Îõ—WBŸ¶î".5¼ÎÒ–ýp2ÞÐÔe;V¼;¾TøÞ¸|AɰĮJºu\må(ãíÉ`ѱ E¦£¦ãåþä=l+»JÓî§ð§H:Á]ÞX¸ Dn†`éb¿"ÆÅ.¦Í‡ðÝ&è &šR¶lãF}Õh•¬%ÙnÄJe…ÞIŒpoÓfwüÄó ¯â—û¯ýÑáw•P~Ê۟㨥°Z­cŠ£4ÑM´ìÐ^L(’ß/~¹ûzã³¥¤*ÊÉÃü¦W^ë4¿hF6KRˆçUÀ%ç× N$åãÂYiY°9aø2ÌELurËd¹]çãE5”)Ž„nl†žtû"lv"ÝcÒ Z–Ué;;ÂJm#¬/º÷g£›–åˆèPä13¿²›aÆ#JAs¢=¢§nøs&}\–ÍnºRÊ›¡~¬N¢Àu¨c áÅ6xJÁpâB3ìhSVáààð ˜ûïŽî<ÅÛÅ&½É½£[˜S åµKÄ3ƒ-ò qEÄ u/~Oè©`Áep¦€ôÀà!ã$ Rv¤ò3·Àã‹ïy¹ÿõŸe=­8Ä·}ZPä~×ë m³ò…½oæ(a¨åZc¤hC|rùêFï³$'Êß(F;9Óo0ےѬ3ª,–Âã©oBZsÿM>RҔ맪ib ëŠªë‚ØÆc}AíÞKl8÷AbMSÉ,XÔ»ö±Ü» )I§N*Šî/EMÆÃ_‡—”úŽí½¨õóoEMßYÔtTªÏQÕ”±O 㦯.pàêKÝŒ(k"¥V_µg¾²¸Y\²º!`2!»n‡Ǥ)¯F²C¨ž S01˽7yL]ÓªÔ8mZ3«œ?‡mmúæ˜ÇGσק#5ÿ†c6@R³ŽÈ­¢¨cƃN‹c̺‘C<Erá-bª¢I„ÿZ¢Ä#ÙêJÉ(!ªÕŒâ´²`:„!‚¬) ÞâdË‚x;jL´1öE*.IÒ"m´îæ )Û¿‚hBõØΫÒR(öAiÿ@6)E¦N´½ƒPwµd¼•È©/å€_IàèäÿZ»•h8k¿Üì?rPOWßßh›_f¬EÑZ‚Åkf‰S€Îâ)«Î ( $OÂûOñº;íÈ3ðæBª?AAÌää…ºyªž6sSÖUUÄT»Û§,G\!d¼‘åñB¬)îöØ?èåî×?d¨Ï[B˜]™–Ãjš¿ºšöú0íÓ ú&få›&¤¿j¿–¶ýì?¨ÙÔôÍ@9G5»÷ýv@­DàâøÙ¹ˆðíôÕt1ëR®>%\á­¸²^iwfˆùáS“œ|=‹‹JV®† xE(ÿ<Ó·~Üjä—`sQD©QZ£œ¢­*<䃞}i‡‹_îþÄgPéÜéñ<·¤kízv·@‹Å~Œ’ JÇ" óŸ.",?ý vV8È[ºÑvµlÞ¨:B$cÅØâ|uíZsgM¸ýÆÇ.˜Bü¾z½O S¨«Êí4Nj„Û΀ÔTrq-Fàù Ùšì¬ÀŠ"ËY B·ÚPgôD?’Ä¥x%FHçÍ©ôâ$-nÓ9MHfÕ4{š;ò°¸ãüáM7U@HÆ7A*Ì]~qÂcs…#¯ì + GŒð8MœMý'×b*09]ã»M›¦ýXË“%ª¿8þB¬ï‹øåþk?4”„OQ–qe±¦7”mè±1gÚÏ>#˜Ì²âýê—û?òY"2S¡]wsžã1\Ÿpšcà°sæ".€Æ0æübx¸yNuð¡üb8G˶K‚éy˜LÆÂªøfFO*Zq¢W +©™¡"2Þ=¥‹ØLBp5œWqG”SÀ žoc„À¿-Bê™Â¬bx“Ã̳Reë0ÙeCÄÜÿöÉÛÑV¶DË2+Yçá˜U|ÌÅÇÚ + ÀB„»ç‰èrÕ ´*Œ‰ ›Ñ|X6{‹5µÂ!îÅ{2ëŽ*˜¹±Šž_ + ÓRüòxÞ]KèÚ<Øw]×פû‹að*p™øÉËËíÝ`™Á/]÷†åU¸<ºN<@Y1Ô¸»&íÓó{ѹLJ ‚!;VDé%Eà‚¢‘lMÇ'õ¬á˜W®âÝb/›+ ª½Ç޼w!W 3äĶ氣Gw +)LQ2w-Zó¢¹n>zÙQŠþTƒMºC&RV$â¥E»Œƒ£›÷KÑÀk‚ã"Œ×JìÀ**ä|8átW7n#t]œêh $[ET´øº&H-•nˆ"±woÊšêÙ™Š`;ŸAúYÀ®—¯ÉRшÚgÊœškeã«ß®ò6.ý…§h^d­&—o±“ÕdU”±ÀD}™¢5JƒÐ¸nÞˆ·-Ìúé܈ØiÔU¸ªU¥ÂÉib^ ™¶…Ý Ù/Ŷ@ëAQf´EQ—ØË¾Àeñ¦TQ¦¡žvnE\†H•¹30nsȧleÑ:äÖ¶9]mmÐåb0c¶N€¦ƒ2.Ãí…­´oJ‘Nlö'Šâq¨|Ê–€Äyºùƒ˜,¾Ü£‹vv^í[ñìª%ˆÔ…Òë\q¦4n™E~¶Í!X ˆrÔÜa2 R—í|iºžä{™s³Ÿ‘µËˈ)kqÞ #±ñÊlëmÙWz‰>À7F÷²LŠpP¥M’:ä㸻X‡ê6}Õ¦Q£g›3?`ú«TÖ¡­œÐ©´nuý!+ë|jƒ_`u ÈÁù ¢¼2ß`>«Q[A‰Bº–óÕ O»r-®ðÇÚº]Y»•H³[»wÞï¡¶ÌœÉ%º®Ž²ÀÄÐj>}#q×rPBŠÑ4B–ݳ¸^8ØmäPŒ"j]‰[lèHs%Çš4Ó8Ñz£‰{ñ%–óGJØÁ'qÛD–už²Âœçæåþ˜qC‚Q6ïRdsŸ¸‘7Ú’vŸøðLÂ|bEØ© Ÿ˜L=Šl|bHûP¯’}b,¨Ð¶ð‰[У}âvq_vŸ¿¸­nÌ—KŒ·éniº¸Äxo7µì.1>[ÆŸ˜£FÞÊ“O †Qœœ|b=šÁâàßÎÚö°ä'>eÏR ,Fg]º=nbÂ¥olõŠfõ˜Ð¡7à­ê,®®x:fï‘å7ÊëYŒ2‚µ-×?vÙ®Ò§÷^û‘éS~‹L=åãóp`¢³Ò!©??qXÏ÷«_îÿÈçHAÊw“åqŽaè<É Rÿ.®úg‰½“ú`1«,¬Iç¬þœØ%è-#«_0ÔGÁ´þFYÉ,ÓúDûÑíÍt¸‘Ö¯Bߢ‡y1¾ÏJCy}?èJUÝLÎëÏ\c¨dýp »ÌEá’µ–ã¥o 0ËÝI1Aç&«í¨˜wÆú¡Š‰Š"œLk£¢Is›z³‹kå )·ì¼¾†‡ü„‡¼~y£Sè‘ןƒ;w–,ïy}ÊR9æõ§¸xh”×g KBzÁd}Á, i¬¹™‚7Íñø]¬y¦ Ü?éåþ|žEã"õ~µ¨RëÕüƒ]ÝV'óú&™– =¶ë‹·À²8‹{†à£"ÎÝ|žë¸·ïׯ 77L$3ø&¤}—c€'qZƒ1õد`y4-åñ‘ðÊDPs^·#õWHì¿AZ÷§?o_üìë/ß¼ýÃó‡W¯¦à‡ÿþö«ç_}xû»—ç?ø»¯~ÿöžŸÞ~ý5ÒuÏÿ5ÿêé«Ï¿ÿö›ÏO¿ÿí7ÿ nÚoøáöoÿôƒ¿û„žò +endstream endobj 47 0 obj [/ICCBased 49 0 R] endobj 39 0 obj <>stream +H‰d—ÉnÉ„ïÿSô t±öå:òÀ§1˜ƒçNØÖ óýÕÿb ‘Ìîêª\"#£ÞþñåxûíK<~ùÛ—ãöãÖ[(ýÈ«‡Ùëñí–Z cä#—úšÇÇ-çb›Gê5”Ñy’ò %‹OóÀ.=´^ŽÜCžUï{#óň¡ÕÌ“¯·ß9ííïÄã?Ÿ7½‰©ôÖûqæb,©¦úÿ¿.ª=”–ZÏ ?rȹö¸êñþíöËŸÇÛ_ãñùõøõÏã÷Ûï··/òþyÄPqŸ¥ég-Çñùþ]>$ùðãHGä_:J +32n§R¦vÕ ’Kè­àVc*Ô´bX™'ø¶Zº’Ñ+a¤>‚ƒe›BÏÜK˜«hM™a”qœ³„6œãèŽ)1ÿ§þøï¿œ'²Fžcuñ3ß:œñ‡Œ·£ây^ëéñ™ÂJ¸ìó8+î'\ ü=CN¸ýæ•É1rÒ’>©Š/ó6¯»Éò 5->£¨ˆ!³fÒ¥2̨=Z¨ä¡„´ìJ¼]G ÍèÓcR7¼k¤KÎ’ Ö6N`«J·€Å‘(ÂÀÞòA~zœ×ò<ɈÕ{/~êÀjÎí¸Á»âåUKÍNW³*ãÝɺ6ðzrŒ´ +AÇä®TD24ŽÖÃÂAyRŠ6ÃêNIZ¡òa9ÎLñî]#'RÍ»%_œîû[‚ŽK–’ +˜“_•A ܈µ6™‘®¡â3댆Ëô% iÄì<ç,2+ O4ŽY–òÛ²­4• +œ‹$° #! QdìGê·QùÅR ZœÅXÄ|ÒóQ#ä`w(?‰LgT%W­¨|„60ITû°2§CˆàI›Ì»¥µÄÜž¯qÞÔ·K…£–º¶^Å•Iªd»ª0/+ê–æÆ$›œ DglÆ6(NÎÜBH­.“~®ÆLíùj…:»h#F½WÒš!V¶Y ( ãÝËI1Ûe¥ÄòõêFl¦*:lñ!Œ1/gQB̦ÁMõYk¸K ¸LEŠW9?ßG‡@n7¨ +ñ{·6ƨf¡(x¿t¬ú¨®&—ÒÔ®==ṳ̀I.˜1—úÂ7”™-Ïâ ¢arvãMrœúP}[ÄÙ‡H§¨Ñ'8å%cQ•ù°UKýñ5ˆÌWÚ–ôy§èÀ?mGy8)*í$B= M‘Ë"ö!ãÊ--9ÙB2”_5Œ š”*ÛA›dUWDˆUØxµˆ¦â€´cb9{(0 +À®chªˆŒú+¹u(==T4k}è¢ »RÑhQ·äÚ I+LËêæP”³þ°\ØJl—­Ñ"øÒŒÐö®p±k«±–›ËX[ì@C†ˆl’7ØC¬^Ŧ٠· +%ßWžIeC“¥¤fºäJ=ó$S=ªRÄßz·Tâ6÷Òb"g¸±MÔäó˜P{Òxm)¸3¢”_žcî†ðâÜ3^O`Š8 B$3ª¬-s@¯èpk±a(²gÝ<8ÁqÒ¼1MŠÔ^zXBNTk_6îe¬n7 ršÎ›1]¼ÞkòYRBƒ‹x1³¯µ1•7‡%ѬÕ!œµßÄ”½2™Ú‘&‹)}¸Áªö„®“êÅã'(¿ÿÄ{Ð>]È é‹ã5ôï¼ü¤-i‘L‡hÞ³‚òåkÔŠR!<–X9»“G%5mWßcV’A)@ š€+‹í|{\’÷Ëþ¸‘Ka>ZMž~<ŒM òM£^-°MèÁënKdã½$ÜòÜÒhµŒU¹K6‚5¿Phœ)^PÌJ¬ „iæ¶×j&V\ÕD+{ÊžXˇHë5«ãw¹°z2o7x–¹›º†uckO“h×Åòûá&É©eᙿ$'zâñàç¡…P\!Ö1“Hªô)’I‘Gï+,æïªƒÐ ¹=M(@Ý©¥ä`J}m3–Õ¤n${—ÜêË“¿xÓ®RãÕЈxB È»4õPΧŒuûz°E¥D‚ÆÅ‡úž›ÐË©©hHl6߯Rx5‡ï:ÙÄåË›dÍËàª2vi·éà@¹ÄõãÉÏÁ5m¢ëР»–àú¸Ab:äÈÖs ¨KG›j­AL½™2é›àÔ/"J˜D€g¨»&®NµPñ^†y3î4!rq+‰%¨|³Q—u†'€ÚllÉ»_&iŸbš` +ã[Ã\ÇN‰/|¬¢ºÄa”B×JÎߣF†îal9%›œqrt'Èé° Rxøí¯»õ!¤w.[½…‚ÏˬBêL•‡sÞš“f•¾§è]3‡‘Ö­gfs㮕¶2QÒˆÎlÑ%0D¬vE³Ì´ªµšƒbÍAxVÜB?âCI¾ã‰R}7ÀÎpf÷eÛJ[òNB©[FèjeV„<`»8Mõ9ÁYÒYw‡-âˆx‚)†qÜ8ØÒpkW»~øþj½ýò¤o2y~Äà[:çñd#7ºJü,º’ê:r|¾¼UW'éêªko忇UEëâ¥fðªfk‚ÿpZ/ +¹n­’‰&-Ê©±÷°UñàÞôÃÒªHG¿<™ÖÚÏoN. Qi<ù¹?K2)è–a€¾²I4ÒTYZÝ·Ôp{Ë[OƘ趸rdjFWçKf“ÔЄ´$R‡õ¸Î“sÝ ³%±½m·KnIžRRhtí7Úº€œË$eë~Y“m9W%Ù†ºR<“ôkÔ¿s€Ú‡4—åû«¤&xÆE$k+k½ºÔä³{Î)“Œ2 µ¼«zêî5÷cx”bÞéš®ÐQa¶‡õ~áôù~ãTÝ¢ 6wø5Z?Ÿü¥‚£KqpØÒðN/«ëéHNž†õÔ\VS¹â¾¦Ë‰Þ-+J¯²/LHñáÇM +”®>è]÷h¿€[‰y}|l_!¶HK˜”vÈÚ¡˜þž;JiÖòúdGøëo_~ýO€)–ñþ +endstream endobj 40 0 obj <> endobj 42 0 obj <> endobj 67 0 obj <> endobj 68 0 obj <> endobj 41 0 obj <> endobj 69 0 obj <> endobj 70 0 obj <>/Shading<>>>/Subtype/Form>>stream +q +0 g +/GS0 gs +170.0136566 -24.0031414 -24.0031414 -170.0136566 46.3515625 162.2246094 cm +BX /Sh0 sh EX Q + +endstream endobj 71 0 obj <> endobj 66 0 obj [/ICCBased 49 0 R] endobj 35 0 obj <>stream +H‰„–ÍnG „ïóýÓj6û÷jÅÈÉâ»Ä‡•Yïä«ÞÕîHÊi—œž&Y,u÷Û}¸ûrŸÂ§_îÃö¼ÍSí!ÏËhái³Qbi3ä’¢çpÚr™±×¬•8gÃcuÄ”ZàÝY&ŽÖbn!·8SÑóÙbɼÑ-ZÓß·ßâÝýú5…¿^6ë)&+͉°çÂmž{o¿õS##G©=¹…ǧíÓ·p÷õ{ +/ßÃçoáa{Øîî òøItýõª¿ÅCxyü¡L9< ‰ Í¢…š*ºVO#ylU9æØÇª}¦83’›UŽÇS +ß]_~þ±¢ð4”tWêÈ+õ[ÊÙéÛ(¡MîËõ–q‰4o=f"†½X𘼇ÇÍ(vÔÀëtÆr¬Ã9<»¾O åy¯M=:Ì0z,ù F@Z£Ï«ñ¸í+å^ìÓ¶7lå *w¹a…{œ4õi±€ÛÅ™ë´W›ö{ŸÁ3ÔƒP#RyždN…gTH®±— Ï2m `/'>J>ŸU—ÄŽÐ%ì‰Ú +ÁÉ[\UŽhÄß©°u(³‰z­ˆŽ±ÙÕR¥4¦÷«‡ZM@rÆa9œY kWǥѷÎ1_ú0… žüÖ»l1ÓK×)ºTRçÄi£Zqëà0 [õ’I_m¸yÞGvj“ª <í—&R6æ<×ul‡õ—BZSHΧf¢ÂµOÊz›äç:ÞØ–5çKO‹3壇ž6?Þ±—¾žÝ<ï«)êÔå#ŽRó\éÓ +~¾”Uk¥­gkìÏÇŠÃqÀް³•ƒƒ\IQ[­+1 Àßÿô ÈüŸ:¿Ú:Ω Fë9Ãö5!†8ÒaÅ<تICoG‡®<ïŒðR-šeýàøÀ/´[nD–©ûÿúþEe„—v÷©á$êxG> endobj 38 0 obj <> endobj 73 0 obj <> endobj 74 0 obj <> endobj 37 0 obj <> endobj 75 0 obj <> endobj 76 0 obj <>/Shading<>>>/Subtype/Form>>stream +q +0 g +/GS0 gs +170.0146332 -24.0032768 -24.0032768 -170.0146332 76.0488281 162.8457031 cm +BX /Sh0 sh EX Q + +endstream endobj 77 0 obj <> endobj 72 0 obj [/ICCBased 49 0 R] endobj 33 0 obj <>stream +H‰ìWÛŽ$5 }¯¯ÈT&¶s}Ý!!-h5|@ ؇$˜'þžsœêêšÞ!Á,¦ºœŠçØ>q¾?…‡÷§Þ}u +ËÃé1…ósH±4ó>5[Ïç_–‡oðùççå× !áO‚vL½)=æÚ[8?-üô´¬)Z®¡Å¤>-#¦dASÌ©BÅ,H‹# äËOˇ¹þé†ùOß-¾ _bAêpÙG,{0ßj´ +})%öv°>¯ë+ÍkXÝ~çÀ¶Àê+ؾ¥/cû¾÷Ò%j7õ—^‹ÀÑ+ŒQíòžãh„b ÄVwñÖï·±zôX¬Ä sM©Ðð\ÎÒÂo?bõ-üL¹ƒ9Ūm¸^×.7dz0-ùk¹}]åð>׺Êã"çY®ïéÅk¿¾NÌ8u®æFÚu?–W +J{bÝ3¢U¤€HŽÔ4æ^©üîEî#-@¡1rÌ}¨¥¼­‰dÙê.Y¬9oðKL ‰èÓRáWªÑ±;èT…W-%|*ðÈ8`µžb;c™Ea 9x\F,Õ‹'‘éÊ1ìû9»[jÅèöÅzƒgPk¿ˆ˜ êìRöïUó4Vák¦~ÆvÿÇô_ÓWNGl!âwȨ`ïêZ » [’)* ïâGÞ@tv«×¯ÉÙf™ãJ¼ t·1,dY>0&_”Rýœ—AÌñ[µ ÎIB ºÙAw8p–bÜOL¶Ël&H¥gì§Å ³n!X·&©!¶HPé΃_½÷{ìþ€^Bõ×`½jýG ~±…;),¯x(é¡B º‘2–ÎèeÞ%,$³f·¬é J6'WXSJ#—Ysï)³µÑ¡l"bE4….ùX•EŒ*I¬TÀ>ì¼UØê€U‡‡!<4½ ŒYtIÊþ(pÀ㑼QL{Þoåȼ Ù×È;8Fbæ½2鵿çÉ}I7*­êLÙq\2zòÆað‡gÃ@Bkĉ\àO3‚0U9ÊìÛ[/#H°1ðÛÐz0—b•”Ymþø™‰¦ì +@]Ȉ  äJ÷y Ð&2s‘×L¿9À-VÄÇÓ`´± ´Ñ|„]=Z›h¨:©l_‘}ÊóLqþ™û tnVICûÏ>—»ÜS +A¥¢†æ|T{Y¯[Å]Çç {àņ‰†ëB¬‡ |Èœì¡LNá+k¸ë…¯ìÕ2q´J%ÖHq—Ø8Î’†RgwEÆ“õ÷y:’>°¶¾Ed¨/ò!V—œ€~œ,º{ÏæqK©U.Þ~º¥G©8Ѥ£ ˆØž:pƒ™´õøúí@rñXo÷.¬1)p^©n.=@‚æç—4–_ž¹¿½^îdëŸÜüÞÂæñ,þúý)àçb±'ì +endstream endobj 34 0 obj <> endobj 78 0 obj [/ICCBased 49 0 R] endobj 31 0 obj <>stream +H‰ì—IŽ$7E÷q +^ÀY4ÎÜ*Õè•Zj¡$4,J¤º?ÐߌƒÓî‘R­‰Š(c¸sø´güüôã›úôÛQß}ÿ¦=Œr¦þÛøãï_?«?ŸÞ>õþUmÂgJŸÖ¥¾¾ãçÿâçß¾>þR¤ þHYO:$gY«s*E½ÿñàŸþxlV§‚×ÕtôIm¤]öjKšBÀ¨:¨÷Ç–²ÆC6jƒß¾ô؆æ0jgФcÉ{Íc„¢‹UÀ¡ßuÊîOD£3?Ñ{ñc´ ó2ÆïeVÛÊ=Çë‚°ÐodˆŠux¨—KQ_'`W‚“†¨-V$OHn‘Åþeî%é˜j‹ƒ^h(šgqâdF_œa#v:{YÚhÉ>ó<tá¬&,×l˜‡óùoÝô6؇©‹Ñ°Ò›01ä¥Ö ¶-`Ùû8­A^bli~ìÚöLò<Ù¢³­›¤€Sæ$#ã{⑦ ²¯ií–†`°yó¾s,Ãîqlëk-@ÈB<Ä-F•x(Þ¤~ ¹ÇüF«>ïO‹WãÞC‹§1z‹"\~¸#%Â9߯h-–1\MOÈÌU¤h.qˆf™¸åX÷¶iÓËU‹÷rF)J‰A¹‹¥µ0€\ -ɬ Dâ*냫“âbYönÜF’g €îlšÂzJ]tk!‹7¨®š~ª.êí3ìÿ©Ïoÿ»Óí˜nÇt;¦Û1ÝŽévL·cºÓî˜~|†gš ’á‡qèYËÊ퉌‚!¸ ªU#±õ(¨¥(·^*ñíø|Çú½”Ïf :Ð3ÞCM¯^¥ÊÕ‚U¿D bwÀeŸó‘§Â‚á}q L«ŠAä$Aÿ…s>r|‘Mæ’Á%ENÇy‰ÚZõ0W#$vã‚s6J‰ÁÂXùÂ9]?w_ykôZ£5“(ᤈ€¹ÇÇzš¬6:1†«½©ò\¤’<ç:¼‰XR ¯›Õ¢ê©#WÂ.˜€{ɬ(’²g›`NuÙXµÀºF,[4C-Q,mã¹Ô‰`8ŽÅÂb—X/öð^–‹+# Æúˆ^0€‡õµ$ Už?Ëi6Ý:]éô”Q°ƒ®Àf:¾-Á¡*sü™OÈ˪‹ô ž{^ØÁ£ ð¨—xé߀w$àåkðÜ!úAéélD·EùР¢S™ßŽu~ +–Žè¥g¿•:Uj-cd‹v‡³ÅÙ:üíPñ+•¶ºQa2”Vò‘½ä‡ +ä^ó»kèEUß Ç°UD"×j~3 Ý&æ1ÐTòW;º­5[‹þ¡æ¹ÙŽ’º6í·R×J=e›‡qõ:¥ì> 0w31ò‘À<Lj-öU° +`©†âŒ¿Ðøs§ü…a'fü†%UGCºøÑíX黨ÅþÚlÝ:]éôt„u°E2YÌ ³?À·‹å(6úÜDß°¦“s¨Ötåüš>§Ž®aÆïH_lôåá¶åzSésã~#ðÅÝ8Töâ9{4³w~¼e:—é)Ÿ¬ÃD0b½çÉ;¥.üÁ…=X™ /ÜAƒÏ/ÔÙnD·Ù‰†Å¤3wʼòxô±—ºuºÒé)£¢Ñ© ¯zËqqf¯ÊÄ¡œyjü5üèÜ$äŽ_üÀ#¬ôÙ†_:z„¼x„xîÒ·z„fêë¥Xknaրނ÷xÐÅ&XÕ¾^€¸^hìr£Ym‚; èFÁ.(}B<ÜgR'1TÓ«û uÝÙ…Æ"&ÏOÀ[ªR­y•¢.Ç,9 CîäJ³8»qž“[8š…4ô @:H ¾à·Þiâ‚`^tA{í«n¡.…ª9õŸÞ¾þ/Àœq§N +endstream endobj 32 0 obj <> endobj 79 0 obj [/ICCBased 49 0 R] endobj 26 0 obj <>stream +H‰ì—MŽ7…÷u +^ )2ø¿u{0+Ûh1hŒg²[÷ü"Hf’ìªì. ´1‚ªšQ™üyŒ/øøé—õé§£~øñEÝþ¸åLý¿ñÇŸÿ¹ý[ý~ûôò٨ׯÊèH Ÿ)E|’ J}}ÅÏÿÄÏÿýzûCYeðÏ* +EûT‚²!ëhlT¯¿Ýø§ßn›ÓÙyü¹%Mɪt0YmY»ìÔtAðõ¶•ˆaÔµÁ_zÛjï 7š&©hµ³VA{ãU4:XtçœNÙrÓ âH[ïzÝSÒ®¿“Ó¾ŠNCG“$×@r2ˆ¼Q–¢ô޹´Ö«L.í?{è÷wkë躵y>Y~uXgŒšLAÏEgȃ¶P›eIºX¯’6˶úE§¬•I]attNvàÏâ´)±F°P—Uñš /Ú6…Þ}pG›¿)zøaK°¡í°lk0ǰ,fÙü’õ:c†g2¯ö褷qj3q‘gbñd´ØbuÌGBØt{híaˆi Ù{èùÚÇ8ÚæöÆþÖWSžmÞ·K®c ©+RTe¨mF΋r YD¬ñ5Bš±fhsÝKdêñg‘-0‚ yŠPNÄds*chhsa¨lõˆuØ2¦‹ßæ)C.j×It«~‡¦8>CBʆŒ‹%©:ù̽ µœÌÞ¯aÉœs¡F “á=ÁwX $÷°aû¼$­H$`ŸŒ? u´-¥ögxGyÙX–¡PT˾çˆì˜Lœ»<Sê¨mº>)Á§S‰cÖðñÅ;ÕŸàÓ-™×ÛÇ{¤e/÷`†ìæ1Xþ>€ÉO„**ÚÁD™eâÜã\$N|ÞìñÈ\DìùÚ®j¦Z/yd*L²ZI0uÙ{ÑðR\{Ù%{\kNkõšÔšµd! ‚ø.m¿ÞþUíÐËgøþ§>¿ü|YŸËú\Öç²>—õ¹¬Ïe}.ëó·´>ÿ»}†ù9œŽ/z llO>œç<Ÿ—í3¦¨#ÉŒPæ’N²8ë“SÄY^rRz«¥"áü‹H~¤—5´œ‹˜n´xgª,;G9²h›µ$àýЃØ.{ž-‘â©z®¨½}ÀY›Š{=°g‘gËYÍMÞt¦+’TÅr‚ûPùÄ“6´o7xÅK®Ëõ&¿~-Љ¸$'fkwÒ¬•—"¶3Q¢qþ³x›èÆó¯ºm"œÔb/JðBC;±ôªD,E”à +]ÕÛª|õ“ aU¥åŠj‰nª«ÖDcÍX”&ÙÖ5cɸÚuÑšf]2Q¬¦ž¡¬jºÝM¯K­SµW/:TÜ=}œp¤Ý„c:åÑŽ<º•Ç2ó¸à˜VË“8úÿ·z]r=W½<_3îã(Çò€£Ÿq¤•Ç¸ðø ŽvÂ1<ÄÑÍ8úÇ´àXžÁñAv]b‰µæTŠ|³l®àÝ{0æ +cVM*#H¾ãÊb©,æ·,îVbq¥9‰ÜX¤,¦G,âÍ®Õ+fÝiíºäzG®5¿PãcMv(gPKàx×IøNÂ?‚Q:hä«_ïŽtâ%ü=3iæ1ÞÅq¦1v +Ol×%Õ‰Toò +ÖÔaìû Vwã ‰v&1‘xÇD<¼­(¾qáã{$>eº.½žu]ä¶è?ÈczH»‰š¿ ã¤ýV Ãäj&"-Hºo­^—\©`F[_?”ð™13õõõ÷Ña8m<á0HÚfØÎYE¤ótÌÞu¶®á µ‹qm÷£æ[ñÂqA‚z M¾‰|a'µZ×mÒÏVLw£Z¼ë ÉæÞÕvF›w=õb—R•Z‹Y!mj'y¬ P\|k½ ε³9Þ‰öà s1“¯Hê¸AªVk;îC¥A-Öuu®kõßVç*d¦v°b,˜ßë¿U³q=)f—\ïÈõæYY ¤3Sö4ŠÏ‘X¾™Äø‰áûÕ¬K§W,|[‹§î¾€Í³5YÖn"&ã)€ñ]Ë x?­.±NÅzcía +a޼C»u«'i1öEæxp.«É¥Ž0îw¢cšíƒ_h yòQ->u†1L0ºó»ã%×¹\o¯ŽÀ“àúU¨û‡8I§D†´'"Û-¨;šDš„?wiA2Îþ¡ß„ÿ&"ÓùÝñÒë\¯‡쾓ø‘OY¾Èø á;Ö¯K¬§ª×]7Ña ß‹Åf'ìl'höiö÷YŒï°XéœÅÉu©uªVÍ®üô¢ðõ—‚(®  +endstream endobj 27 0 obj <> endobj 80 0 obj [/ICCBased 49 0 R] endobj 15 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 300.0 300.0]/Type/Page>> endobj 16 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 300.0 300.0]/Type/Page>> endobj 17 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 300.0 300.0]/Type/Page>> endobj 18 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 300.0 300.0]/Type/Page>> endobj 19 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 300.0 300.0]/Type/Page>> endobj 89 0 obj <>stream +H‰ì—IŽ$¹E÷~ +^À½Hã¼í” UKj¡4,ª´êþ€þ7#éž‘‘¥ÚˑȈ 9ã Ÿ_þòæ¾üúæÝ/xsÛï›wÑÛÿÎÿü}û›û÷öåí«wïÎE*>k-ø”˜ûþÀã?áñ?¿o¿»à<þ‚“ÔŽÞzt!×£´î¿m|òÛ¶Ç£EüÚëBq»÷väXÝ^´õØö–ŽD»¾-C=|*Ú.GlÕµ£ÕÌvGèÅ•~ÔœÔàŒÀPbp{êGOú<—¢ÍèW¦tŒ´žûÃûæj<ª¤³‰é0:»›¡ElSœ¾]‚kíItté2›èž±úÐ×óŒíb²ùöhž£OCÁ0€†°WöÆZr>Z Á2{wÄØ]l¸që,rq!QÙt= 'è^ð娭iÌ‚sJ6†uIrø^9Ôf+º³ +± î€UzÉ—vã´X×4`›©áy² 4Ì„å¢Ýá2Û|˜$ų8$Ö£yN0 ñ·ÞÇ!úÏF›oÀ/%_:TœKc[½0¤Ol'oK +ÄÔÏÔ­BxrÄi8]_G³‹…G”ÛòöИ¹€¹/œOÄ9[“ŠG¸ñ\x6Mc%òíÕ†[ˆõ,¶¤êÖ{À2s8§˜î kˆ:ýêãq>ü‘Æ*±¢†0Ãrmv˜®û— +Ÿ¾S0\A[áCjÂkPSa¤ó$BéjÈ)š¡õÓ0üÁÇKœ·ç>GÕËÅЙUÂô 3Áé Ÿñ¬ ±‰jÊË n®}àº)Êe”e8gZ¦€ãVn8eF(¸Õ¢3M:\¯½âñ#6æÖ•×#L §%#ê™s Œ¯«óiv:¯ÔxiÇHË‚‚µfòó‚¶%Ciù4Œü—/¦»ë8;Ž‘ngÁè5KM v'<‡Àqyºÿœe´š“ƒïgì-¥5&_.4àdж£½Ñ®ÎÕ.…àâ^)W|]½ÅÜΓyŒ€ÂÊ3~=6t¶Ú\mQï°ŽÆÆÛhrÝÎ^óú÷Øþ±ýÕêãÛW>þ¹¯o¾ká] ïZx×»Þµðÿ§þkûŠjˆ¥Î»bá]±!«ë-ñ¬ˆY«$¬S0òw¹”D®Ùe|±ÉàÌMð¹J|«F­TEÏðöêÈyÕ~CÉa¨UKÂ}Öb0X2íVJz|rS![HØ$^ÈQ[ã%63ËÂcKùà#®O!T2* +Ž‹Ä#|yU4 M‘bu_X2¾ü8/~ŸŠâ†õ“°Ìå.j •½L)Ⱥ´p)&qjZ8ƒVPuc¸Ê +}ñT¤eÝ:e µ+.Ô¯Q§‰ P1CŸJðB—¬ýGaÙp¤EXšæ he•"ĥŮZ¼vóÞJL«gÑô8qoaj®¾ô®×ÿÀõÁ¿°afrê©V©½&/<…E†ò@IÅÐU?=ê åLL"GGÉЖ!˜‹{$è˜u_ßYHí‘Â€Õ ð ]¡Ð¨ù¬åµxèOfë†8¢ CÄá­ˆ0AyH,éSHiªF¢÷–¬" ´ÑßÞ§«ëVrØSÖS™^KJî¯SÖÍè£gOjûAÚ ¨ü^¤_)íUlRKRA¿ÉJ'Í*ü•VÒ…Z \º·œ‡(`BWbÉe“–ƒ˜µ¼*þR\Xàœâ²M'(3Åe2{ˆK#¸œÂÒ«Áx®°äj ,»B‰J•KY¥—þt“úœÔ³WQ.dz.´aǽæ)Ÿ±§HY}¤qS mhËé(ËLâ̺¢5|„‘ÑMÌ|®a%ò!4¡—¡dætS–Òƒé“δœŽøbnДž9«iMé +ou·Å w/ð*ÎRz[*Á¾ó§Òêfõ«WÊ +žŽ:ÙzNÏ:4© K#LAj*a(Ò0®KâUµ©T“ꚇN˜¢t¥i@Û';U +äV§P0j„–LŠJÊ„‰l¨„!HÑ&47’¹J„…ÌÂà5 ŸÉª›Õg¬æ5±PeaW¨‡`ÏÏ×D H•C½ùTyÖ¦Ñ †×{»ÜzòÒ¥O²ôY•*À`YÝ©I×…g7b¤mDeQzêÒýI˜îOÊôY˜*ÆS–îït©ÅãÒ¥u|÷שìfõVÏ©¬bÙÞ.=5?‡g^· Ë6Â4YX¦¥Õ2qårFø¶í–ú-Jµ +¸<®>iÆånÅ€ÔJwöùØVd&¼q¹û„šZ™!YiDæ®uU‡‰·*€‡˜¬Íäô¼óø˜e~½r­Öa½ð­œ¸Hf~Éâp&~e$ƒYvƒ‘"›ªâ’ô‡¬P^iêŠ8R¾h6ƒëÄ´ONŠ…i*‹äfX’‘°4•E·ÌLYà€,$MXŒÄ/CY ×{aa©ÿT?ÈZ7«±ú í‘ã[C|©\ýˆK¯Îø{')L±¦¥(š{/(diÖ{W9±Të;Ñ:S¼iÖk?E¸HV²j¦XMCV¿ˆÖý½j%®‹fÕlK²þŒº¿qý×F8†„ol áñ*n½žTq;í:0oFíðÙæL !rtªWÜo³ï–@=KA̺±oLÚT1#ª©TÅ„\¿5¹¸ñ3´£a:|"àˆM 0"°9¢ð€få©RÄ)ä°‚¤q¨#ßò~µsŠ® +p¬3ùDùÈýu%¼}ôÁ‡¨ +Êq€£¶DJˆ‰3+ššEAùlÓe  iIÖ1ê~²^x ‘bä(jÚh¬æžSo“!ÁLJAÑFÏC±+zѻֲ•ƶ¢Ú••©ÍÑCi¥eIvÄ^#sÛ™8.FÔ?rO¯ë¦öSÔÌÛþøë›Ã×áG) +endstream endobj 90 0 obj <> endobj 91 0 obj [/ICCBased 49 0 R] endobj 87 0 obj <>stream +H‰ì—ÍŽå¶…÷÷)øâðÿgëv•³È4âdapfá×Ï9UE‰}»Ó¶—„Á´nQE~¬:<üò×÷凗à¾ûþÅ=~y—ƒþ?øç?ÿxüÝýûñååkp¯ß\ðµgüí•SÉÎ}{Åí?ãö?¿=~qÑü‹.åìÓìÓÅð\oîõçoýü8’/øqôÕÜü,ÕÍÇ1ïõî^G¾ÏîÐMkÃýt6”âžGCÅ‹Ñ ¼Ÿ ãâs,®O¹ £Ð“ëC¢àK(+x}TŸ{]á”{#ùŒÙXÐq'âA 'f0’Ó·fÃ=ëP¿òÓµ5 áë<_²èìqÅÍ·)7ñ‚0*£“Õ× @ ¾å¾¨Ù¼‹†^å…:ýìòXŒÙ\«>ź5ÄÔüÈIÞé>Ö„–îgÄz‘>bŽ˜]ÚbôÝd!VKÁœ1Ø +¸G,Ÿ8Fö[È‚ëØ‰ÆÕÁНOœ-Ñ—4Ðåô½ NÇH†Tt$¿¡-­²Ìt"3[v-øš4t@È­Õ€'ºäK¬Ý÷ <„±Zjêlé9ÄX–¤ù÷ø\ÍÕ²V;¶(t,bkz{%JìQà¬û²„×ÛnÝ[ƒ&çù¶eîÙý™Øh)>b]¯'P¹²*bŒ±($FCØ+,Viã”6 ¼Òf”ÒŒŠ ¦9¥t“L+]:kš#±á§M¶mÇDØŽJ |ÅÃÏ9ÖT¥%f?[wçÛøgÊÕ÷jéF?ÊØžÁzŒ8¶^VÃõ¡«%¡ž%žÌ2¬}—.†din€‹) PœHI¤•žÏ GAÅI>dtÅ2µ +9cƇ€o"=SßBVg³’ ŽX‡91¡¼°~YuüØŠY§vÞž@ݲÎV|}ãlI3fša¹QT=8¢éµô䜩iÒ»ÈKëR‡ˆ›ÂÔôÂ:01qŸ ˜Cµ_¶DÓÖo2_f¶¾C3Éž*+M$æ»í|Í¢Õ¡…̽éô½ ÿ^?>þ¦›ÛËWìZüç¾¾üåÞÈîìÞÈîìÞÈîìÿd#û×ã+¶²àc™õÆ;~`¤r>»¶³‚äÙ¸€È¸s7‹x>‰^˜%XÐ}Ä2gìMÄÂàS#Pg@È&2¶J¦üôÈ%hfS2·!ê‚€"å¸3ÇÍ¿’ôX&Á5ºˆDÕ‰ óÔTæÒCµµAãÈ»cf='L’©‰,(Œð£ N«]åȬ§Â +ÊöF $ZÅkÞìN·Ø‡u7µßKMsïÂÙ˜¡BYÔºBÅ/Ë$ Š;¯BŒâEdM¾,{myÅ›Ô]­¢@Fî ºÈ²35-X¸cªŸ`%Ëëƒð00²SÚ\4 ƒ¿ÓM\ȱÔFC¸É¾LpˆÉMôà¢#·ÀQ\sÂÚÊéT'кVM/eK´Øöœc ;NKè*á1Œà}M«6µ•\“rŒ'7Ž»¶èNLÍ)5ÖÄ¢t•((‘YVñªLƒDbQ+NE˜e+É&ÐdPÉ‘š,ŠU¤`“RĀ̛°BÙ Ee#à.;ÒªP«Ìwrv#ûCÈÞåYL~XÖf¨°‰ïjó,Q-I–µ"«nM¥˜iå)Ç>U«NJ-©%·U'¨Ym*¶³*›lµ:Ó~«NRëºp­šÈA—ƒ“@Ã;`Æ}§ ª`Eiåxhqb· ¯¡3««,[ý8ÅnZŸÒzÎ.¸5| _¤…MiþXå쨉£’Œ4ª¼ 8š#e—GÍÉRÅQ†#ÆqgÝ–!gp¬âðT„F„SaäˆôJOE€Xk|à”ÅuVîì‘ÓÄ¡µJÑfsBÓ–ÆPé"*] +­ñó×5i[)²n8I)Vô9O7ûãMéwPú(›`S''ʶßu)% +ß` '$ŽÂIŽ9Jj:„”øâR™åÓ#Ô~À6(*‹6]³Ãä&£´flŒc!”ÎÛè ‰g8£#pú')t£y:+ÖN1땤ò鬘jÁkßžP~³?Ù…SÊw%¯N¨¹ÚÂ7:þ$㻊Ïu⡊óÇ«PMÅãyà/æÎÐ2 íRòåÔ–ªYØÅüØÕ¼žfá”óãžÿ/ƒuû `ïí +`bÂ?:òÉ0\¦ôxãJíÈ3Í–ó §/mË4w<¹†åL—kPgjàhNÏ`ìKîÉ•šc µåÌ’–åâåHŸ ©kËÚyç³»i}Jë݆XÝ%J- ßGNoƒHâ.úÉí¢—q0ÑfJsoŒC„|Ou ñÁ?vÅfTò«úUñ1–mÀSÖ°lCUݧk(Û”þ™öˆí¯ê¸½A#ÒÇ[ã é#HåRæq1µæ[ùÄAt³¡É‚ôœK¥ù<Ð/|Â(1?ù„d"^Ô!äSËE»«J¹œj(ÝÉ™’CO©ÜîPË€I‘O•ñ,.A£0ºxQ/RïJ÷Ú‹¹„¦RžÔ$LÑò®;GL3 ˜:äÛ‰–3‚˜Lñ/ªáb‡ÄEˆ9HÔ†ÞO`—2êFõ ªç¼èj2ý`ZåÄŸí\æé +ø‰ÍLZÑ,jl¦€´ddæ ªð`Š#ZݸƒäÞø‚å=Í”QÄÔxfè{;&¨ä›ê +Ô† +µâCé„+9u¡“Ùu¡]9¥OíúMësZš]úáÅáò_¯4Š +endstream endobj 88 0 obj <> endobj 92 0 obj [/ICCBased 49 0 R] endobj 85 0 obj <>stream +H‰ì—Ën7E÷ýü¦Èâ{ëq•mZäy,äŽþð½Uì‡ÆÅë` hºYÍ&‹‡UÅÛO_.îéÓ%¸/nù¶—‚ý¯üù÷åw÷ÏòtyîúꂯÒðÛZů¤âÜëÅã¿^—o.º€¿è$7_SîNdø’¸ë×…¾.kñ)gÜ®ÃWŒ³fÏç[‹—â®ËÖŽÁÉ´—RÐŒú6š‰-ñQ:{÷èÞ[Kñ£Š{yc©¹©® Ì”qmƒ–ѼpÔ=†!x×£õÉUM˜¤¤zè0U/-ª©Ws2—B6|Q|.†.ÅÖφ}Ñ»eB‰#øXiÅQ|Á zI¾g6p[|&-4¹X!-Zðšf Ê\ÖÃgƒÅ3 `°V¥¥/4ààx)&GXz@)­êK…U˜ºÝŽ+âŠÈeòJj °æÈK;(±FRcD#5ŒÛ¸^ZïÒº®˜q¤µ™'y”xÎÆŠU‹·Ó‘ d‘aÕ0Š )aNð;4SõËc+Ü05HT«×zótPAÄ›Šqð ¦nmämc¼#â€’î ”ÌuIÝ£nÌæËÂùA,5º$ë>¦|z wó© ¿ +èDØ(63Іx7 €~t/†zXäK|“r$ÄnÐ: ) Qn†ˆríʈÁ¯ˆ²õÍ §¾ARFâŒÄjÎYC…œr2l«r¢P)¼¯¨˜T«Õ`™A³Jq¡ËÆkU`Ç;ìbÈN/)4[aUål@ñ~`=¨ý7µÛhà  ?_Ƹ)ðXž^²Éâ€ËÊŽâÏ:OrÙ>X癑S4°Ìóƒè¨ë õÓ4ƒù±iþšôFa—¡€Yѵ²×Y蛩†> ý-ž*¹†ß©"^–ö¬'eU j{tVé“}^Xq×Z¿‰‡ö®æz û d·qÖ²\¾œr,·*5N!›‚PµJ¡8±­&)®Ë¦"T¯ê¹n2Bõª&Êd§$òÔu~uÖÉmת¦$vUAtSU¸©)¨an(5=c ÛÔh6•”4ÊlꉗE‰¹CNP@è¥ß °«÷XYdýòéâpù.ÀÌAG` +endstream endobj 86 0 obj <> endobj 93 0 obj [/ICCBased 49 0 R] endobj 83 0 obj <>stream +H‰|WÁ®-9 ÜŸ¯è8=±ãØÉ–‡Ä +!Ä‚¸°FóÿUå>óf '½s;Nb»ª\ùáOß®þøm\¿ûý·ëõÓk\vƽ˯òï9ïaóúñekÜ£æ5ýŽâÀý:w|žŽÝ™öLžµ.ϺWŒüãõ×ë_¯¾ýe\_?_£ÿ×âÿóº~þÂë?àõß~ýtÙ5ðÏ.Û Ôu°ÏÁä/jàhvG\onr÷wÜËìzû=ôh7æbp–Ïí×;ï“ûòÛð÷ÁZçúzÍ{åºÞ†ˆ"¯¸Ý7žÖ=ñ÷Àœ·íÛÇÔÜSÜÀ0¾.ì‹3¿£ç²{¬ãy¶ÿz½ÇûÁÂ[§ä{dKá$ó`¥‰ýNqöA¶9+ïD0oâ+ñ¼ïð>Â\üÇÖ|÷»xî÷1LôºãàÃ@ö‡i_GÏe›_ÌÒÎØóókúØ8ža½¹t~Tï0>lÉ\¼×Bx„º‹ ¬sŽÏ… }q{iÄ J°êÞ ÉBŽ…:]Œ£Ì£@óL`îè}ö>ÏÈda1Çô òÍê¼Y1faã$Ø70ŠËØO'¨' ë.E‰|qÏ9•`r¦–l·ë90Ž--‚оõ…†‡2»YcwSþŠ€* + +xÖiœèÔ²˜(@ÁEh!`¤ïë…ä,$Öqx;×é q¢_ g…Z÷ ÕGö±ñÖð6ÀÄ/ñz#9™˜¹îÃwˆ4Bމu'¾È®¯×ß^~é×¼ü5A ÛyÆ=¿Ò¹sÅXªÜBµÅA[³ŸKI¾íˆ¢ŽÜ*SÁLA[YÖvƒOKaÏËÄ='N éZGÌÄÂVO6X¢_–Ï 9'±€äíãX7g)µ9­y:XžIp 9ÄY8ÌRÕ<²‰ê$(‰Ù<k ˆ&ÞVˬ²&*ÿÚ‚æzŽQÔàÆÈ(Ÿ7Œ¦ F•IˆåÒÀÛÒó¨þ]Ì´SX¶æ:áò^WÀ—›_‚¹"!ɨꤘòcw.wŒq¨ YjIÂÄù𺗢ñMÖy¦‰}ã|æ0Ù~—0a ¬½rJ¼ÒˆpzÖ”yY2 ´2­x›Äû&S€~¨Ê<Û‘>P•éOº>Í&f›è¥)¼B`¢MSqVnu†Tê@"Vª7¦èÉžMä<¯'ÊMþlH6N.v€)‚‰®åý•ÑÑàÌ5E‚ɶº0F6UÈ‰Ãø>ƒâÃôm¹KF¨Ôù¡]ä[ºòû>l+[…,éiŒÐ!4ÆÓ1‡lŽjk;NÉ\d˜VtI-&k„ä@Q·`2Rçôìc žqÌè<»2"Êç ½¡lÿ<—ZáÊžM~‚ðÖ¦ОìWh…O:RG•lJ†˜³µö½›’;…?gåÀét^µÎð§ÐQº>fZ8{¨Š7±j¤qäò§ƒƒ¨x;,j¯WË´,›5Ú0 ÓúA 2¥›¨fû][)÷οöã•PzJ{(·Z‡ÝÿëE( ±Áö\¿á¡nÓzöQsïIq-²€š®Nô¤Ï¡ÁË´¥n`Ã'|kÇŽ29M˜L·÷Þ-pˆs3Ÿ©46—sˆ )4ívÑÀµ=Û}óÃæC.=ò=ÙM7…"•®jè¶IXŽ%bÊËÑB•¦K=Ue|CR÷Ûñ§KŸ2ؾ{·aí¶Pf–#ÕWPÙ@•’/ôÐ~ ya®‘0‹_X΄r „ÅÎõÃÚ7NBlÛ­ëåqÙ zh`må‹· +<®lÌÔçµé2Ú=èã˜ڢ ‰_<Žšƒï˜ìöx²€Õf’é<—:èy.'íR Ö*1èºH9öèäD·§…P=]æ‹U°@ˆ!ž†åò)!ö<êŒVÖó4ˆ =õ’>ºŽ”\Þ÷ž. ·a¡í0嘩6æ›àK†F†æ›[òÌoKNoaÕñ€™öW*è›jèè’¶¨þû9 +t‰ÃÑêSE@RÕ»Âu t º“Å# ¦¼S1wÖùØxØ£Déái£/!ƒýh<7ÆéjCÎ_·ÐÔ)$Ú¼O…h&Y)ïÉVŠÑ mþˆæƒXA,«Û÷ÑÅ‚ÒoNœÑR\ò®ø0:<ÀçxP-¬)2ÓiZX'¿@ÈNîÑyYã¼û8˜¢6?½ËEéf I[0ÔEh¶¶=g¢FžÎ#»¿!ÛÇ÷Z0Ùô ˆý~[¼EÑÀ‚‰6q¤ïýò±+‚ë3„Õ¶¤úyG‹WCÅhrš)ëß„—;š½Cs­b6 ùø~¬G©¼ÿÔ8¯~ÙI}»‡ÝdUnY‹‘æÔÙòOjP#µÂÝ“‚nÔÑ“uyS¸n ñL#è8à©ÊÁ%€<™"^’~ M6„ÛÃý²îß3[J}öT‰…M:F‚l5W{ѱ4\ž½~ÖC6±4©ã—®˜ïbÖÇ@V [¢)7wÓ?»S:¸Ü÷ì¹X 0ösÊ !Åê«z1gÌT´6î¦Ñ½Ê;L:ZŸ -åÖ•‰#h ®Dr¸²ªT¥ÿõð‘ hhû mÿ©åi’”Þ£.Ç»:YˆAWWdÒÚòš:vG.ÒÝ` ¤_ærùŸ÷t™ü@\úíƒ,R'IØêóyäªäüî­’‚y›)qñ²Z2ÂN}G?`T´‘ý”^*vØÖŒ£^$–þ%jfŠAQõtR=ãµçõ^PØ–£ZKÛwÐ;ä_iaý0¯³ Ù7O„´Äeê²uÏK9ŸÇ |QUí¢¤Feõå:¾;JôÃJÒ¢ËnÛ]Ï Á4Î×—†Õ±–TkG œ u9›U ÍO¿Ù,©,6¶r£pJ'ÃG°Þ™$éDÈôY×ê©vß.£53èÝ<=+œßn,!¤€$Íz%âè~ 5aáùØèúP Š,ú£Ù­jÕËŸ9ãf^¬Ž+Q¡º¿KóÓn¡ ³ÐN§^ÿ¢´ˆó*;ºÜ_ˆj^Tu{-œr”ÄàXâÖ6Œæ²Ú€tó¯"Y’†2 ,Æž#ÒÿrâžbÍÁ<æÛˆ +4ŽB7gø»Ë?ä@øÃ×{~\5ê‡u¹ú Ó4piæŸM³:à¥çLµ…jÆõ¯˜Sƒ/•}›píñ¯_®—#X9M¸õXéuγJÍn§Q. aü—£WÏ)éº;Íuª@wn®m£+!XS8Æët¼@Oghö"¾-·=8¹Âß9“Y¥*èƒ.™%„Ê;=ú2ão&ú¥ þžc–ĘbØ×€Jî?Z O¢»-^6YG«\0´Ð5Ù´WóË"&#¡úƒë·üvYfRˆûrHò±Â¨ÞD€µÀ '«QŒÈDL£*\ÛøiPª)7ÎHîaBz¶ôqÁC/¶íIÓù£Ý7Ue¹ÖÁiUö°[¸ÌaüÌr§•OÎpë9“Ì—zëëvÉ8}®†lã=Þn°Fÿê²ÚxiO!°ÓPûl;Ò)åþ Çk†^ýøìë=^c…ýôþ3ñ­7®êLZfÄeQ&iYR¨å´k^1”øüj¤^܉²’y<•X+ð¼ø³Ä¶Y}}GbÛ®~z£àn·ÁZ÷™ýáÒè‡vüW‡W‰ÿñCŽtt†n]W %i·ðš;)®Ž`ÿþ•Óìy’,µö¿l¨DC÷.ÖcHF«Å—O|T7†í»éiÓjsZ¦Šÿ®ŸhWbÁ±IîöZ‰\´l._2"ý4‡óU=J·°§k©Ž;-§%_ƒ™Pºu³Ô•üÓ‡U<œ×»-îOÆR×Õ‚³ßµÅ¸ëçµÓíF‰;=Ű\â”®+EßÅäž¾Ì8Û¶Üd$ Ï͸¯¾ón­bVíº›Ê~Aš|Gêîµ'£v}ˆ%ÈÜÓ:fÿ,÷óx°Úö[Î…ÝýÞV A‹»ô Ç6ßãkxï + +ĉ•iÖ¾ø‚Ù‰™±>ýzÊGÏå|òóçéíÅêÊíëÃüƲ3ò)>ÙÕ_Í™ÁNV»sˆ=ÇQmÚà«ãe"¼–”¦[Z_®qÒ£«Åë–=b^ö×È“xê85}ÃMïõç1¦HÄ9»Óå*ˆÝ#*8$ ÿ·þÀãBfÂ,M¸ìmû¨÷ ìã=ùƒÕÌî½²üTSköK(ZºaÄWNhé*-8ÜzìvëúXþ­šj߆åB»¿îs‘ú·¡ãÉîñ+4·'DÔIK§××€¤ÂûöÔ!ĉ +ñêXˆ[^\Ñ6HŠOË/6`ít´'>")ÖâO@êÇÆãŧ]¼ò$ŠB(ûGlíÇÜíÍbªËZÛ×ñë— `1‹c”#ãóßfp9µ +úß^°»‰ ôØw²,˜ìJ:hi8úšBÍø_}¬ªÎ•f_%UGƸJµ—>u%Vvê¯'¯A Jª5Ež§ ·HÁ]÷ÜëŒI%ÇN®hJšáÿËœ x__é, Qªò|&cÖ¿qÈj%³¨Óùm[B||X̸xŽvæ µ·¢û³s¦}[蘿¯>«&Ö 0«‹Êétoå<ŠQCzäst‡ït¸œtmÎ]™>)£}äÆf-g2|¸>J¥ÂÀàâ7xK AñÝÕlº¿VŒ{îàäYsXŸ_mžkžõ è»‚G⟫uãš—ÇeÚ,ôcµ&ÓÏö|ZªËïn1ä¥úVgT‹‘ó3Ó‡)­ð½5ø6èk0 UQ§Rín†Ê3|F{s5­ÓôYõ“œ/­Ø.­04é;6×\é믱¢AœÍú{zö ãE©À5CX[Q3µÈû¡Lw—>Ù®@ãeq¬‘V=°åT@DórCÅ\IK 6°¥c’‹@Àur±€j.nDG›ò‹5uqÒ–Áêý¶ {´h³D‹þú‹µ¹Z”ô”PDŸ5gO7دé¦@;®YÐ +&EëV®hrõµó»ª%(ʤê=ñÓ¥¼Û—D‰’h‡õ6ù¼Bw’+QÆd/X¨Uµìùõ?¢+aDW‹hö¸Úƾ,Y´vxuµÏáÖ +¯.¸òÄKê€ÚL\Qa´RïÇ¢á͇·ºïbkåSHˆóc«eTpÅꢟ‚}‘BÓÎÉÎñ÷ÌÑŒ è>øß–€5§Å"vKþ¦yÛôZ`Ìå +Ÿ´²ÛX#þd¥.û¬váí¯vʵ ¬F Òbë‹I~Cʦ+lëfæp8ѽQ±Èê +ª$wjêx/œÏ±r­NmÚÖöÜ{sÎgÕ=ô°çÅ骢¨Râ峈»è1ìHG æ‹yìÏç“ïü ÛtÂhœöì uKN@­ý8Úü³ý¾^œÔ—¿ÍËšÒ ZHêb2tb>“eƒW^ -ñT³¹`¼›ñ™}ãñpÓ&<[Ø¿º‘d‚í;ÆB÷ߨ ÑÒ×–cûÙ¦ŽÃ¼‘p °Ï6ÛÊQŒÝkR%xa1ëåCï¿qÇ ¥Æ·Þ)_åˆ`&hîÌus¦jÎmŽ–iÍUê×GVTvé2¤Ñ‡zµ4#˜^õœUŠÍ §ç“Ù^ßÜÛè–n€Ÿâºãgu¤D‡ƒk=U|f6s?-Ü^ wßtn Õm¶û6ùvÐ7¸ÀuPåPWGꩺ¸Ëo{¯c +ZZõm=„,ÅP\… 8n{,t~|+àÅLlðñ-Q5gáÎÅ&C“ü¹/nsö1%¬UÔàèÀžŽpŒŽæ9U]ަY‡À]\yA â ÔÙt­ ê=ë5õ:íLGD¾æÈÀ{i{pµxõØÝÊçö|ê£=]u7êŸîFñ©: øŸ½GžÍMÒN1}Ýô ±§6õãVJ5m…¦KÕuÇ?õ­جîÐDqTYË¿“ ™fØ)8ñu§‡C’Šõµ?±ó 2?î[°ºÔ²ËJ|u¸ºÅk”§ ÅI EXD1ô!DM\ñ¸*“øëGO6Älئ + a1Ǫù¥ÝîþГRî½~˜ømÓ‡ÖˆíÓÎÇ#×&D™ µuG ź'–ÚjèÓ+Wá–,‹Õ BÝß8jj¬Ø"¼éyã$ö¿/w]’ëû½Š»;Ì÷Ö!›¡\C4†îP|ù7 ŒõwUeWežsâÊ-Žž?™3›Æ8Þç¯YÙ~YÃ.ÅWªcSø£‡ñ§p,²írW_­Âä±¥›µË9ñt&tä”|ä¡õ¸Ûmñˆ6¥³®¸Œ=µ€,uÌ¡ŒÞ0ZU-Ÿ´‰Pœ0%¶¯õh5¾BrÉØ·c–ÔöÐâÐAj½‰4kÝéד¤‘¦‘Ò"T1ù_Öòö¦Õäç˜æ­½Ö‡:Š’Ù™ÜšVOÏdû?¾íĈè÷?$Û» ‘D+ ðí͆SNµò R¨X{<«F™^FBŽ …º¶æé~ :ñÓã™ê«W÷d°á€Øéw¿ÆU†ü—ÝÒ°94®(NHÝ™Œ´8]Їƒ™‡u›RÝmZ`–wøˆºÒ“,AÚŒðÄ©=¹‚Ót=V:Øg}ňŽ×“#®;a¢)á]‘Ê:³“!`o4šNÑÛŽ±Z>N7\”ÀâÑ4÷äÎÇ.ê+ÇjÞÅUÅ1åÿìÑîwû×Ãkp ñT­åC½ïëœÑørbLå‚[LcC$Yc&>ØŸÍŽ$Çi–q!ÖLjw´Q×÷Y£{æ+@%hb`ÖÙUŒÝž/ÙVfö<í]a4b¿K¢œ¡ÒÜõF#¤ûÞw$¡ )>¹xy[˜ú¡ +xQuËJµ‰ ¡¶bMÂÛ"Èbs¼bg.áo×ᣅáu$ŒTFäg'm9–ªâN¥ÌhÜï8öô|ýþÿÇ¥¶Õæ…^3Öý&ñ'¼¨½f«  ²2¬jâe&¹€×ÃnÇÖ_²ó¸¯Ç6#no-ÜÞHqU®‘µv›Ç2<”ä“qÈ@ó{hO³£”§ngH:>l©TÝ_±DÄW¦Ð¢ŸØú¬š³úhµ»¶z0æ ¨m.¤²›|¿ºvÓ“óò½¤uYb§-õ(®b‚ÎWM¢;βVßkÎð•@nŠAïcøñ8Æ6·óû€tžá¦ÁÉ|Ñÿî$ˆ6:"Ðöòže@ÖÈæ‚r‡rrGL4¨ËàW© ­´ë¼7K\¼¢ +Úî~juອÊy$;i˜óœ×λbN™禤Í…Ö°5Ö“LVXÇ 6—]k^êãÌ祀Ž:|žèlP=ÆÂË%o›7ÑEˆÿ«Œšä ´$Q›9Ô‚çB‘­³Žk›hUPΪ=æ¸áò@ùÀBh"®-¹)XÇ«:+êÕâxô¡Ö£tIÍ16*s2”ãe8ÒÜhmµ_ùàÚ쉲D;·.;ix’îSêd9UrEÛɪ s‹j-e¿Ù|’TNbÀŒZ|7œ|3î•_,,{Ôµ%‹Û\À…²#È)A×ÓRkfVA'Žÿ£’¡à‘³ù,óµse >1¨R׆ƒb\Ku2ká xb‘Ê!êN€ £,,ÃË»8rjñÐ"©®r[±·Ã襓*4ÿD`qÐÆvBk)žæ²AÝsÏøB²cý°¨æs'jŸiœÆŽQÄ^iì˜Iv¯:&°=±ÓbðãöZLd7R±Í´ø¾t‡vHBm¢åÔ«‡’0¡i?—á&%FáH¹xAcf½H¨¡ˆ`·ØòPŸÄ´Ðë äÛ|0mgù5‡׫&&ó¶Š…}A4ðz~_:Á“îìªp^*0Lš½BazÁp×îÛÑ€…[j–†²Ž¬oß‚&DIÆÈüïÕ0BG}T—= ÕÇÚŸu½GYB‘¢¾¶ÿAa¯g1DâÙ0©RéÅåAÒˆã›GGóµ<:úèuf9æ&FŸ”Ȩ/s <ôëKZk&²}Ç"'˜É–JOBªÓ!à×׋×c’yÑÔ Û +Ѭ‡$>g<Íà™$7üNƒÑsœ'œãVÞ,4Eoš/Ëì8‰HX Qã÷™Õ½¶àÎÒí”Ëtôaa j‹…1襫Յz¤w·v_'ã:È_y2mêðýáLÓP#š7S,NÁ»ùå#Ç—¬À;¾Ýp3n¦f5qfŽúå *ò°m‡}fO8b"BºöJ4Wu{½ÚÔi²Þpgܬ§¡2h¢Š0ý6bà™>}µ>7±ILûÏùg‡¬-÷?`‡ãnv•­¾LÔº…ü×—$l–X\ѧã¡éz–›YÐfu+&wØŠcŒ´ç cãÄõüÄLKÃ]‘ÿ¶¶·ú¢Å‘=JÔ‘££Q p÷g\îûWTùâ8ò7IQ0îÆœö¹v8Ö ÓF‹«¡º¤çÙõØ×–ÓÂ(5Ç +RÍ}›׆oa] |4Le<^¼`¶Æüè5ÚmOÀi[[©ð˜<<7°\û_Ðã—rKÐw´°v20@~ÛIb,‚85 ÝcÀÿ<µ|Âežhe‰'½ 5UeŒµ@©š;¢j?êÁæŠ ß,’xW\í+õ•°Û™.Ëõ(qò|ÕáuÄ›àÁ`}ánÕZ׃M•÷Η9Û3«åDßÇË¥büž¯>žJæPvîè‹;Ž»•þîø\¤”Œƒ|e¥5øC²(ÒYƒÉòÁîÃäý„í$Û¸Q'ó$rèI½ÅÜ$®x“­ÿ\q¤¶“=¾‰7÷hÖ¼¿¸á 6XbbU‚™Qéç¦ts_ »‚ª}l¨g8tHùF‡dkä®i·ŠìOO!2„ÿqRUËz‰ßÓ*Í8›Õ;¡~¬ÁeëÅqš>u¾ErtJ$ZúØßMkŸÉ=0u:“ üw{¯âèyQMJŒf¤Ø“:qì 9ÃT¥oÞ‰A“ÔÍa Pô/‚#°¯`ËÏ'ËU»!I’ƒš!øâÒîè®*¿ÔQD¶TïfÓIÏ^¼(O>ÕL(i»‘*„£žäRÛCšªö+¢><@f1E™Qq#ò[O‡¶gù5žžu½ÛC…Jxäj¤[®`ÀõË{ZH…àwf€”ô ?š˜õÇXõbŸ'žu=oÕ<þ­E] ÊqŸêÏÌŽ™Íƒû(ÎD¢±zIôö*ÇDîÂ{Ü^Yr«]c5ÉOÃ.áÔœslVTàJÂ@gØêÚ{©uŸ¾^&Žôºù6ê©üYš +¯[ +?b»ÛiíBUc’U>‹…™` Ø7g0¢ë 0™?”<è=5c9¡±šÛs(–àE[šìpJšït^”z!oÌ1ª¤í¯/k #–ãµEjwˆ6X…Ê1-}b¼)İTR +”ÔQ釹)¹C1ïwH‰w”ùô„í¡ßkëm~hþ>ŽŒ´YÈ´, \ô¤&uj›¦IåE±g,:ºñ«K`|ºñ4覆f ži±ï\™9ý­D8ܰ(œ&UË^ÜÜLyJí†ùÕ:V¾H\é§Í;p,× R&´9žbs¤Z¬­HX¢Ÿ[+º[›„2wÔÀÎ[p¸% OŸ`5ªW.y®F‘%&m¾=#‡°€¸&p(Xºijú¨ ¦h½Î¸ÈsÄÔï`üIö½C'¼šÞ©L4¸&„pbc0e¤g›&âHn¤8'w0 Õ‡†€ NXÓéP’—ÒíWŸÅÑxWÈJÒx“EâìÑ-ñ;9ã«ÚóƒèÒp²lãŒaÖäxZA +v/imàü¼±¥!WÖ<ä¸jCÙ¬é`âãv¤+Ë•Löªúo«N6œ\kro4ºµ}i7ÅXÊÝq¶z´½£~Û(K˜ÅÖÜbÉÜÌy6uç1+­hD${røÑä‘^ç™ÆQ>6½rsßß«Pq—ƃŸ&h$PÌ+#©¹#ÉñÓ‘¶<Çä›)‘fÕ/¤æ-e£¶v›%|ºÇ]âʨÚЩÇÓ¸…à ’³ºužzø©fS‹Ôt©ÒܪŽL©\eêË»Œ.°­Ç GÍJZ@ã8uÍ߈£¨6¨’Rž¹z‘c¾žt¶Ki’ä•l“qu†N²I·.·Š¨Mö©v²Юóõ !‡_înA§Æ÷u­åÀmÕ¶ºóŸö n}Ä"¶Çéï\{…”Ë6ÅFÕE¯)b½¹ÿÒ&_ŠIAÓ(´íÈP&)Y„/ÇXŽšµÜ€C¼¢È&R±¹h¬U/ÛvŠ ]ý§ïBh´Kî°s¹iƒ&ʪ)WC6–Ì Ðòx§Ve¡‘[Ø@,B;álr=(Ü&6ö¦Š¨Î¹Õk;WÉvä"@kþ<•K82աڑ哼Ÿït,tDRÔ/|)‚. Z V=0é&*& ÏÈ·‚¦N§HaŠ@¬ucˆ†Á$~Ù§vjëkôwÎÛžfÚuW'¡¥k!²¼uÕ×[×3Ú¼áäIô&ÊfŠvÉlûKUŒgÙìúÖ +Gº0G­{Ö{ò&¿EÙ +Šÿø©C5¨Ù!ÍL©R¾•GéûkûN9Â?²³æü©jnë…žD‹þ„n{C}΋¨@²Ž¤{×Ù ü’¬½¼„ +Þ­œ^£Ž½/'BZsM3Ò ,RÆRö‹ß[¬Ê‡#õÓ{/·ûú)CÊ:ÁEYÇMž} +W ü¸­[Zéκaëõæ¬A¹Ò…¬8¯"‡8pF‘ÊÚUÊ‘Êí^•z49ü|UîGàOÅÇåŒÅýÊ~Ç…[¿>Ó‘s+ï{»ü —Uçñ<³î}[í=îymc ˆÅ•?ÿ¯•üüøßÇP^ø÷íŸ}üýͶŽuÓ˜à‰¥þ>ûãÏþÄöƒó ˆ¦Íg^Ýà'š¨Õf8”4ßè^&ÅK\ΓG<òZðÑ‘Û÷;Œ¹“¶uµ¡s1Å«üše x;Ä9•Q¥µMÐMp” ¹=S‡r•)ý,–A²†T±l-­ +^6v¶ñ’÷þ"OõLëQ'I©O<ꌚά¯²`ùŒ@—•ÁÇ’Æ Å¡—›Ï¤BlÙGFJjÌrT^Š1% Æ-Ńx¬=Úp$x¯%R0¦äXg¢ ®'ˆ7†ã“V&‡Ü̱{ æÕ³±‡‘;Ò&k*žÄ/ÒØgðÇ‘ÄDò£Ë +áè×–n“pÙ¼ë Ù»×ÃÉo)ïÉêwfOééÁêÂyŠ£·Í0É +ÁÏ Z™aïnÿGˆ¨ÜA|5zÁ£¡t>Ø(ga3Ê\§-¿fíÙõNœ[\¯J’Kªº¡Ô±ï‘ØÍsk€™¸ÒÞï7ÒÅÑ*ea„ŒŒm²œ,Ê)fé¤â“ì9•{¶j±²4­ø_oÛ_~¦ša·æ±"#eköå€3ø¼@§Gl€Ë°ð!gp?*'Ó ½S'½”_èZJLï2$ÃEJÐBĪ'ápÓÖ‚fÄ yå·tñ<ï#ä´%’]¤3´0 Àc``¼´ûžòA}«®%7„ר¶f1G¿»üëQ +ÐToM̾Shxs÷h¤øú[f¼fÓ%‰‡/’ªˆ‘=V +[Ã"PëDë]Bd@ø£·çÈ)ü>pE7ž¼üMHÆ{â£øeæúÑºÝ +‚¿L +B4°9¡MzYþ°õáçüÆ*¦ØdüãmI“æJa´Ù‹VÞ Ò†Úw³ïPãYŽw¥†ó³…v€‰å$¼¯ÞéˆF„3\›¡sK’Gò…®´(n¦§`à¬â:9\pÇt`UGf¨èQ×Ë&Ìk,RF`ø÷]¥ÅÈqÈÚ5›Û§¾cêó¯õ­júWÚèP·dààT¹²Ûo:×/Èns×D¾†Eúñ!¥0Lß_Y¥Ç¸è.éÄ‘*‡y¡‹]Oí/úZóÖ h‹ªR¯Y£ræZŽÓu=ÉXkÔ5ãÓD€@tOèdOŽÓôá[& ·¶Ð\|d¿À½^qή64N“»ßŠÛ¼"›eͽLK¿a“ÜAÖLi—ÀÞF«ÖBx\‹Md£³"' +]˜»Ó¦&Tþ‘BhÝ +ÒR"ws¿Ð¢˜Q¨ÌÁ‹61î̳¥š!²FEÊäfÖá³j“ØO1ï^s¶§p­†eAæz¿ß·„èfD ĸ±d¸¥Ìg}&¿>CØnÕ ¤áRdWd³Ð»=Tè3ÍÊÔš'+’R¶l›Dt‚Í<£3Ž7ò«Ñ­®z5|Ü”÷àX’ ú–1âVêÝ[+tãNYÒ5Ã.ïHésÍ +ùÄûF¤Uíf Oz>ùп§ŠT ÉÅVôI^ö¤ÑŠ$½íPõÏRm|Ù|¥ãͨÊåK©B:UP Ô‘ý-ZÎÇ®M£n<ÜæÅÏ:zZ9µç9Qùªsf‰üûHéXŠO.2·Œ´àŠÅQ­¤7…ÖW¨À¶Úx!u½¤àõY¢aÜϬ@Ü(ü¤+CRðì…멞ÐW 2–OæÏ¿lWYŠe¹ý¯UäºÐ<,ÃkhðW¶Áxÿà3éUÑ6E*ž¤+…"Îpb>°Œ¢ÎèlŸ.¦J0$$ÍŒÀèùPÍ&½dFoQg…%êÃìMõ¤P{¡ßŠF©ìÃ#ã“uÔ +îÕí¬”ÁVp‰+yZ ÔIiù6 §üF±PÄâƒô¯õ$øî&ç¢I£ÂéÝÎÑ¿“ôè)ºÆijïÛ<ªâŠÚGÃ+áÞm)ŸPìR C¢±ÑsSNbOi“*Þ§§íÀ[áë:-\ãtiÏÆGnSCŸ…Ê€á†K]ÈÕ<;@£{Ÿ¥²³ýuüÜè2¨äWeBZÔàDU­Ò¤O†]å +˜Uìv>{CbšµÔֆЇ²™(©é±úc|nÛhyõÚU×劥ñ•@âŽòo~ø‘ }„v¤òëÕ¸ j€²ï +¬tÉÝ~uå*¿"?Ñœ‚Rw4ir„ÕeGµ*©øÚ½QµÝY®HÖñ"Ðp0Öt͇áñR¹£H^aؽ‹,m +óî@Ûv\)dJ÷bèºå£fs1Ç`eÅ@³#˜\­@9qûí3Ÿá*p2°GŸ5ËÙ6šg+9Ž‘ µøŸž³ÍšÏˆåˆÅõ¾E£ûŽ}ål}=µõå—Ë"‹ ZµÌ©;nnåKµøÓµ~_±hÊ¡rö•ŠNÉÀe+äÁº±S%3`Ч0{hgÚY€*’‡žQ╬q‘‘såoºu+Ká\×17%(”j×gŠé¨4ÆNýçqñ'æÒ‚㊅?tmà€‚{]ë,úÚåÿ–¿HÃøÚFĬ듵]7ÑÿŠÁð`mҤ͇¤ ðònÍźÞÁ6³dGÓÛ’ÕkF“ˆ…,ÎóæwiLi ‹¸÷¬1„ ;>+¦´-¡×9©£-Æ9&v³ +úþœ‰‡U k‹³½k¥â¾/Ô®C.zÕã*µ!»ÁºËSJ¶íö¸ËÒ£ÚüiÅ"k Ìœs¼o‘0м+Ÿ%‹¶° vT0Ë€¾P­ÿ.„ä8°…SM¼Ö_6!…ï¥Püೋµ•åãvFÏ>%v‡2žqc³v­ Œ·èÈF‘h·çÜ“9Ò¨´oÕÛƒäð˜?…¦çô7%–oRÃ1°>k†T%dÚ^–ÑüørèœOhH›SÍ=ÓVEkÐkE. “9dþ%±ŸÌ’ZgD¨ÀаÄ_dæ•UÖ­S=©ŒDüºøc‹ÔðÇ}_Þ~—ù³fËêÙé ÝidGJ-kÖQ<›Úµ–ê’—õ<û+eUJªG@ Ý)´ÁƒbD-^ YY·ä|*ÅÐñ¬ãeçòŒÜd5)É4ø¼è?V’ ‹ß?5Ùô³õ”2åYhd¹u´fý¥& +Û÷:²_ZpO=§î¾”Û±¦ÊyQ†#ñ"Ìfû³3RÍh£á“¸œø9C±¿¼s(IpbÑ£ñàò¥DÿÕs½åW@ìù¯kÀ)Ö´ÎÊvdè<É£,Q™ôd<.¹Ç‡ë²I ô—ïRü1Ä–lnµ}Qä¼H5z±xò¼; ¢KÆš¤+#ÞQ*ÒS*ó³ì:óGynŸú¸v…úš^ÏuS)Vsý¡ÖL ý¡(•džþÞWÈã‘K3Ò]¹V ºÔÞÙ1Zì’•â®*,ÚÜ“ÒvA"²ñÜߺ;½ÔO `ž°¤½)"ç¦M{õí «]¢¸¹ˆšB;ÍÝŒe(Âà{eÕÞŽ^ªg¥®iK拜Aû­;;°d ÂFN8±f™iOzj½eýIÁçIÍÅÚž„#µ¥yžýDlWÒžÓ‚î}%f4å-ûSr‚s†ƒJ, ²F@ʈUÚç±KßœšÚ2H`Jè©Z'†¿ ÙÙÎ…¤*õVòÐÏ'IwÕ‰= gðø”ëG†âiß:j™“Ò¿)ýËœ’®’SÓõìæ$ êziù’Æ5b¡3rùêÍ©&`Õ½AHJpÚWpŠŠ–"&10_XÆ3´#:ÓÇM¤Xn}5üK;M±-kßM@…­6ËGÞŒ×jOªÝ•5³v:ôƒÓÙ$ÌG;žýe¾ûù¸åÃôçˆnõÇgmGmÊæ}ª·Xê?Øâ-Ÿ~6ÿR-¯ìD¹ò,Ç÷þøÇ»Iò0ÿo Š¯ÿüù¯ÿþª_ÿê$$0’Ѫ<Úâ¯ü –e+ŧ£¾È¯M¶å›¿ùËõˆ!*‚9¡nR]¢b;ß­va—ˆ‰gÞ†äRW§iúâ°K·A…K­=0ÙŸ "EÊÞÅyìÙŠLg ]+™FÒQ•ЇÐÕÒj,ëòÉÛs@OãXuÓM¸˜vƒ:'ºqx5”ÌÂ0D¾4Þ,;¤9?Ö%ñojxëðìF1Û㠊˨óx£:X˜¼ükz±ñ¶F¼Æ÷<"óðiû¦>¸2çN‘‹€£!‰TªýºÙ–`Éà•‡4Ñah¸xCަÀýÂ.Ä_®E>Fqr¹·XsgèTði +ãx$'ñ\˜>Y#¾Äl|ý®aô.`þfಘ:3¥ˆnýJéHaAÁq()ÃÎöc†ñ]ò0?¸Q½&§²r¸›óÍg“;øª +¬/ è!qr1”¯TÉÖæJJA9ï,÷-MÍSñ3è«C×Å, ÑùüÐ.ÄyOWßÍLA%Æ)ùf‰^Y#áØ?™°F +Ä·!kÉ„ áioA¨à^ì*I`÷Pg6 Ç( ´¾Åóò°·¥bPÖ9Vâ0j–|8ØømwÔ{«A¦Ä &NÝL´À\ÊÄÆq©!˜~bÈÃ| ÉŒ„õ‹ÿþýpÿ¾~}àÔ¿£ß”,ªS‚b#ÑOz»A€(5á_ Ž• L1Ä´d*öòEüßýÈhÉn%Bñ§Üånþ ˆŠBÐU„Têf‰›ºÂH3Ü"<©MíᇵL'áÒ2÷3`šê‹à Áæ ŸêH·Ø–éÐØRÏ×5fÑyÅPU+¬ŽQõËc³ÕOÏ_íÍ‹2’ +pY-£*ÇÅ¿Ÿ?^×Ô°Äü­áåS]Ó4ÛݾTBB—P²ê¶Vˬ5š©æé5¿oòÞ1sax«†›ÒX®š~pÿ©€Œås×p õÄÉ.³TI’+ˆþ÷*rÝø<,Ck(ÐW·@hÿ ;fžO¢ á~³sËÊ·ŠùÛêKæWV柪S9"H¾»×t}c2Ü¡S–ËË:³ìíµÌët“c{ÐØïS„Ì) +ÝxŠqøygŸE ¬”ÀýšÜòäi%R7±¤”Y^oíæGµR1jQö6iÜ3¢†t¬Ú¸GàÇr< Ëî kÅŸ©¶Ž³x¹Jü·,Ÿp$¼ºÐ"P÷ëßö´À7þ]NÜ<\庽Çq]qÚ}?‹=‘‘aÇ–dR™qXÝψAÇ.B¦;óPb±a¹†ð±Ü-$øLºÙµìï]iê ½}ÕRGîÏêhmÄÛ‰ýºÙaS1®ÇsH½¬¬7`8ŠÊ²>@%äÚǺQOªÿ”#èYv¾Fz +Ó.IÉq3æJ%ë‚íìØxvèïÐÞÞ9ú2öKHNŽ_|*¥MþOò“»é]0«ÂOÒû1YÀFÞ€ÅW­w‡mXNñ…PÅLF„Ò;ÔΜâ&ãçöšy@Á›M’¿aüY+ 5\Ħå÷©×ÉÚæ»½Êê·šÃ/ +l5h»$ô¹R•oÁ]ó +÷Õ†¶öúhé²®³<œºþökÒ{( cÄ.é^p¢÷¶2ò·qB9[¤ÀoJj:½zUq|Þ[OŽ„þZGµnç­ÉMKÉ‘åª=é’Ð-VõeiÚ”‘cÁåüÚÔXÕÂ˪®ÜËTh……ÊÔuíÉïøº¿“­ºàý¸Œæï›UEØô’Méû‚>„¹-f~ô.€fsëà@ôÇ{yû ¥¥Šþʸ=7ðå{=Th1ÏÙ©/Á‚ë b*-^Ø|EzýÎç]•üP)™€$³ÍQ[#L9# )ëE‹o€§ÛhnÌÌúG•¶ìëzvÂKe>|²SŸGnÓlAõ0ÂÆ:<‰W¼cÍG‰×Þqã˜âÚcÈGìêÓ`ðÏ ´¬ËÞ°MuÔáýºAÿ‰)ŒXPEðóe•SØìD@Ž s HDæøÙ¤§ÚÆ£{ æÉ óæžv2÷9b’UøÝu&òE,ñ…msG¥Ž»™9Š.ÎÌÁ4ZÒæ)QE‚£JËz»ßI¬¾ŠØžµ<^ôfûÚ𔦠+~Êj\Žhÿ¯´ýùÛßû›šQÒüßT÷ŸýúÇoÿüÔj(fÙª·.5h•yˆCþe¡´4âùJæv’ Ԅò7]/›‹ÅuâÁhŠÝwÝs0í'OÍæ¤5î‹J:Ùš‰Ÿû7º*ã„ò_[F ~8çù„gX:oAQl>d`R°§û>Ú_™™ICþÚgýÖÐoë;yRS: ÖxÍ¥èÍdX½×UäÃ*ÆP¦VX¼§ ^…¤.Fâ'.Õ-Áu='UEï¾w§r»Ó&Õ H%ìÈü@Ü«0¸:%oEÄt.¢§è+"%}|\7²r'è¬}gá%zrØ©uvuÔŒŠ k+ÖKÔû²Ñí$ ™ó,Š+À>cƒn«vmÖý>ëÙon]þuÄ…ío :KaË<8cvÝSšûÓ,äqÌQ4ø8ý»¿[GÞ²=eÅS%ÆJèËô‰.õ°”ôP§#7®¹kî§i?ñ䍯—n8ab"QÝ=z6槉Á¡\ÎïÖ]¢Æ¯t䜞½·…b+´QÈñØü¶ï] ̯Ð5Ѓ!bäÞf°Y;†7&­}3HË4qGLu%ƒƒ 3Õì©-™B·ÇÆx¡rGík}<§ÜÙ¿v­Õ1K¨gßȵ‹ï倿S ¶r@‘šY`UÏ?—NÔ9 nR£Œ*Ç"Wb:±4¯’jß™çˆTœÉ×~5¸x¢Ô¦+ÓIU7O³²ÍÔº¯ Œ XÔÝtO¨²ô}¯†P¾IÒØ)ˆ—Ë–G”¹i¢WЗ‹½Þ•ù«9úDzé ÷°q³%Ì|ç ü¿™2žà$Hç‘]r ·Á@¼ýúƒvûXÅ2ø–;¢}ÖZìòxšXö?¤Ú·ßGsuÐ0h'Ï×`‹ÿ8ÄW5y¿îüŽ-«¦Qpöת¢~ôfr¦ßÿrã´SxÂ$à®jcr8b¹Ã°KŸlÏMÓBŸ9›BuÊÑÈÒ4×spꆂ»>çlàQµàMòðØEŸ jz§}]âé°§j•ãÄӭa¬Ûñ°±ŒW›ƒßL/dÖdYÆÃ»ÁªÖ§° *‰¡âjÑn~tl6zÂ!yÀ¡ kâîËB5=ñžï;T=¶RŠ©ñÌm$ž¥¾7<Â</‘%;D!adóÆjûqà]ï s©øäP›O¶ü¼S¹ Fö*ÛÃñzsõÞ“,¡Šî +jNR©bÌ,q¦LO|/,£¯'ë=/Ϭ­½õ½%×}gºPËŽ{ÚiììÐî{aŽ5Å ^õÅ%Ÿ\'"š“—î>¦e©Ž®}ãñ&oÎi/he5S^Éìå5Ð,Š—…O³!"6ô¶àrÞ@©Ð”‡©…©­Ój™o ÿ®N÷%¿˜‘5Ñ®/Dt™áQs­NÓjßHZAmX#ýë5@8R6WdoÍ3pf à×Û¼ é‹dè}”MäŲ¡“4ŠÁÜR¢ ºO^[d‡0‰$ëO€‰è›>VìÂÈHEޝL>‚ŸCÇÁ—¾ øeÌûúß^vcUµ¯¨‘RÕ?`2´(D%ù;1©-ÐDºóTb;³BwºêÖeÔ,=Ÿæ“ˆ¡% +o’ÚXG8¿šG~ö#¹‹r+æˆgU?/«Ö"㎭†¾?Ì¡› ÏL­Ê[2˜Åª†zZ–)4‡Oh1ö-ž.aR‰râ?—Z•I«è®ã˜ÆAƒÜŠž¬–œ°vˆ¡@?5ÃdßõïBëƬæ”Õ£ï‡jÝ=ÝhÍ7̺Õõx¯Tc> €åÓé±ßò™ý8¦¬à¢ù QN€^ãÉ6<<$%Q°R.c­f”7'àŸIhæß©Ñû¡Ù2:*à«Ì5°ÊÜ…þô$˜süâ—9zÀ·ÚZ! îCãrÞ“ñ8aìñž,J¾h±>xÜ,¼¶ Ù{¦¦zÒ™í×gÄÖ°J Ljè÷{á~{ò<¸Ñql‡¢¸¿ßÇÇ“¬á AÅŸ-o¾9|¶ƒ\ œ¤@„®n)©Mßl*äá X†ÂIî$92cgµr‰"@|Ù7Îô•¥º°´ÏÌJ°sš*7¶ i%ŒÕÉôq >¥#–þ‘(ÛÓ¶ÍBx<„€¬³¿h¤yÜ’4{î^¨ŒD¥Ÿb¿îýX*[­_#…Ä—1 6 +¯¯ö3U#Õ +ÚÍ“S™3 –+7>¾B¢åYÖÉX¨4Æ55ÝŽÔÛŒåu³>àn!ðK¾‚™±/ ö$YõщŽ\1xÔDñeh¨;ïŒéƒ†y"Œ„N6 Z1Ê5zÝô²$B1Õù(kC#Ýb$„³#8mÂÔåTwÒ®ûud)e[']ô>˜>%Zï¬7vóiÜ}ÓŒç¾Ì´léѸdŠø|dô|\SZ¶œ\ +lˆŒ¶îÙÔoá=óF‘òÆ*è)Q}ާn]Û㢴aÿ¦¬Ì{rÒ81SõÌŠÖbrFËïõìäãfE15–±Ä%ä¾z~/ëc‹, xR³ç¦yúƒx„Õ,4Þ×'W·Ü˜³{^lYóOümù©AÝ /DTœƒKQ¡~Wf[…E„¹ÿ•¢ÅRkÀÀW£‰;¢<ôÈ@á­Ïîj膃ë`(±ÀØÉÂqЙ.YØë f9˜; µ€‡¡f/°©S¨ÔX›r­ë‘Ÿ*ºlóŒÏóåf ®Tü4œjÐ`óµªn_m3š'½F…/­Ægê·Øùì2»ÕûȾàÊ* qýîñ¨ýÚQõ„“ +þyGXTM'%ðvE™4ÿ~š\(vX]ä;òaì—úGØ ‰Tú¤ C ‚Óç6³U KÒäÃÞÍñ[ðl oÏÄ3›ÖþÖLˇÉ0zl–Åu72;·=’ ^ í‡¡…þá“ýƒ,Qòøpàø³qG•厲"‚ð ôbv7Ó3’J6lŠX””VI×›ºå2†Ï–YêÒÄÉ‘xÓR ò¿JÖ—±}íqϱ‰‘ÞmÊZoãKÝ5™‹”ä^Ü„ko{…hëà<Ù/ÏÛ£˜7ògÅ ÔsŸý 4¯˜#‘x{p2¯¹èŽö £® U‡û˜ ë™J­?Z<ºª‰vÚÒ¬ï# ¡ÍI%½ËÚ£ÊO#BlÄ*ªH˜êÅ„Õl’(ƒÞÔ?¥‚ +“Js{h¡«Æ­˜¤Ø6Šê43úû7¼!XÔŒÀÛ´ÿ„·Ø2¢ÍRuãúG3v$ €­ß#d°lZa™oG'DŠ"ö„ku³,F7h„—Õz&R‹ÖÖÛŠ gêÍêt;ùêGvØ‘šFxîŠBp7·¿EôŠ.îÇ1™^>=ÂÖb©ïÈ¡,8AZíWnb“À§,¦çGüÏ€êÕ£µ ·¶þµa5ãÍN¤¼;Æ¡Ÿ­Ñ\/5£!EÿD;NÅM|¶};Ýc7pâUÊÍDhl Åæ²r½hFŒÆöH¡ÑFZ¡¹SD(‚Ÿ–/OÆ|ÚE¾¨¢•V=ÖÂÖWuû»¿ÿ”E~™Þì=%¾ÔV&%”gCßÞä€n{w©MMLI„2PôÒ«6ALðà˜ª•]7(lMë–Ö^Þ\+=ØþÈ8FíÖl6Ë“äcgùÜáÂ>ž‡ ý½Ívdd5Û`lDcUÐeÛlÔVhajº ,áöa”¬æBn4!®2[+%/ßpauV¤yìq +ûxý?í\ÔøÖZ:…»ÔxÚ@ÒÞ“[0ê8 +O6wÇssê±þÈÞì¦Ødå+¨±ý9AÊáŃ©ÐƒöìÉÎòv¬#&¤­°÷·|YwëA~_;Ûîp¿åã¼£XEðàz÷½î }ð÷-"«ó묞œ”Ãf£tÞ­f£´ìí3Zé%œ>J¸Máz'?ïçì½ßÞÉ u áy 0k˜Éÿ=b+f–rX0®=&ˆQâÐ0Žû¤FaT½“*Ï4A¤V9°.>Ò$?">±C‘ eNóù5w';nJ0^²õEh V«¦0ÞP„ðk˜ZÜí63I +ëÁB®^?™#K¶{žc.#©Ü[:Ø·žH˜@o”¨®ò¡ø¿/³ÔL—#ˆ¾kÚ€LÍÃ2¼ŸúŒ÷ŽQj®±1~iuýßT•~pŒ„WI£J˜Ã‰CBo³Áè¾Ðzv4j¢¨3&#Ç”áîx`¸â¼ÐÖÖV‰'Q—m:âÚlç•ë9Xþn¨~w† pÔ‹VczXmÓìKªfö“ÆzXÑFNPÄ‚¹ß›×©n}Öj[ûz¶Pæò­Ç +¡uGPÏÉ\Uy÷–lÁÔ+xâ{ókÅ3-Ðdeh¶Çª½UaQXô•Kk<Éõ~Ñ´}=6=Z¬ÆÊkqš^ûMû}´V§Æb5Ó@OÚÅrI# ~¶»mæ»­«=–ï]¶gšÀÅÕcþص»ß°OÝÖ­¹kÛE‚¦C>VÌÔ3ák&Uœ>²#²Ï属fJ$}òd}~¬á¦M¨\íe=¶m¬jV%d´0÷Ñ×µ:ÇEmþ®Ý·®§ ˜Xý»r+Åž±À¬¬²ZŸ¬ÇäêO>Ob7½jlw»Ó–X• n{Ö£­Ü`NŽ;'äÈúÙc,+QÅ]LSY^:%)nkn½Úñ’…µ­SgŠ2£­ý¾’rS¹úß’6g}GëTDNö§½ý6ZX¼D»bKäõ¡×%hÆèÙÿÕgûªWíÇc¬‘õ´™p{‰“Њÿ÷hÎÔwöØ…W9\£ÎpoUO4rÃáó…Õ62Óý'îÎN;Ê߀‡¼„c›^d“E¢|i¶lWì::ÉÀÌrT§8vÍ£tÞH¯ù.ÒjǽwW½iê¶KâK=tQ@Ò]+޹ØÄ^úÖmkö·^tiÙÕÄk°ïíï’Y +žþ\a{ÖaS—ì5ÇoKg#>íÉnf*†íڸᦓbFÔ W^]Í€"§zM5ÍAè ã«I˜¯XÒ?éÒªóäÞYªsÚ<¼&·£°ï¿}üõ×q?‹c„Û>?ÿùý÷|†÷¤ÜÑ+÷Åcª|på‡ÚÝÍ;뎄Öã.#o8QWrØà*fËìО-Žž;úe²áwPM去Áñվ泗.ô ‰Ê;Vþb<‘øC½¼ÏöF-»Û5éu€»ÀN¥\Õ5ìÒJÜÞÂ]Û% Të:jPj;ïêΞØåÓ韵ÆXnúòéHkŠÞÍo@=ƒº{ê-õÆ£¸ÕvÜ“(r‘IÑÉÁXŠ9ø»ûZ„æõ0±N4G,Û"©GR&ibUC_Ž3jUX²U7ò¼*1åF 0úšÇVÇ2BGfC`<®mx+ÀeþœÎ4Àh€V¼,þ +Th½Î~ìw×ï"$´ 'Pž¡–ç¯0 Ànö¢53NKï$ßëç¿0&Ao€Ñ‹{Ýñ{ mI© &í%‡:âïý”àŠ%—)žñpÛmÚØo}‡ib„Ço\–t±´a¤],¡ÉªÜløÙ4ÅÈ¡cSÉ ;V}Å×]— a••Wx>­F&Ç3ªUm¦hON·^¹¼‰B‡îÄzk-A¨bG@øÅjK3­ÚYgŠÇŠ:ôƒy[û>áa¿Ë´iÝQkô¥FQ÷q(…²ÛøA»L’ÊNôð•ò6”ñ[%­¿à€‡¨T¢gMÙÕáB£¸Žuì]¤˜ä¬H*`֠ݦÕwåÒÑÐ4kÁ™M^tEo°Mާ>·$æè}>š9z¦·“ôæÞQKÜyÛU]uÁ½kuPTÚìC¦ö®ŸñHé¨z#›Ò;Bªë½ýÄÊyÌÉd&&vÄiqPôq/×KyNô”ćʳ¡ð8ûв!Gº„Ls—*mÍo«‘–ÒÍ oÂÄK3Ó` £c‚©û¾aÙš£'G”[ÿ1i¿þ_ƒ«AiÚƒ¨RhÒU¸Ÿ7hÆ1 dð¦´4¶Àè°ÀÝô³ã;kÈ—¾Õ)‰õY/Mêwž8¡ÙW­×_žaP57XÙî¶à¸ä^¨˜Z¶”ýtâë{ç•8 θDAM¦_æ…6ëËÆ·:¨Š5£ãËDRÙ3r2×z¸§H»ÐŠ €öC¯ðJÛ÷ÏâéçÚvU•ËP·cyýþÀß:jãYòêmwÙ€êN|YÿoîvEDõj|Ìì][\[ލ+.Q×Ò>çÛãYúþ_ÞU(#Ù¨²s«ÃJ‘N^5΀0pœèÇíz’!¯Éô*™#Ì +¯ûQDg[P‚­g›•þX]iË1¼¸KçHÄÄ)-'`Á¾-&ÜŠ™U¦˜X­û8^__ ¸qZÙ#áºsëž¾8†/žëÅ 4¿5©u]^._$Cm[]-FþßßÓ »+°¢ŠÛÐâôíE{&¨uoíÅ5æ24ÂL13Ýð–ÖÃH·èÕaïçÞˆ8ï1ïßG›¯^Óºð"ñ­Bòñk \øÖó*ioï§ŒG‡› „¶ÛËêºÈç¸2*Õ›µЪÍfÝ^õs¼z·æšó‰;ýª¦iE«hö§¹íòå^ZÕëý”¼ö˜ä÷i嵃¸#›UY‘IFÙÌ¢¸Rð˜Ƕgþ„Ñê\PHüò¿˜.w¤)bçœâ¿U–üŽ)BNAÊýcúky)¢]ïÌzX#°0u-‚–¬(èã´ÊóÐ~†¯>BßÍûŒ’¬€V³¿{IHÚ.q¨Õ­U÷¾û•@ÓÈ6F¿sLBìc>ìûü> bDä­–É«UQ ž’õôÕ¨§Ì¢ ë?ŽÇOË•uRƒ­\ٗӪ׮*Ëé³gñ\dzõ±õ^ãQé[úÚoÓŠsç^®Ç‡t‡KifN]ÊSTŽl°òËÁ“Æv«d$ûX™åGÃÛ´QüÜàgU ê +$!I@N¨Ìe8¤Ÿ#É0ɼÇCJû—‹BÚm?ãºmµ.(‘Î_;±ÍXZ¬Ê® +Ä!~^<{ÿ™ˆWÉo {ކ6áM: ¦LDzyB,WÐè=m9¦ %êHÄÓ) =³—Ë΢ïßßÒ“öoOsd¸ >5Òǰ/ãƒ9ŸE³çV|=¦IpÇܹçCظÊx¤(Ò€¥ÒÈaÆië#’—–¢×¨±F(®©›³L¡øŽƒ¶öœÐ¸„mª¹xzés«®½ŽjR7/ŒüŽ4„è$>à–DüÊ -ü +Žá«ü<ÖS•,#ô})'l7-09bâĹ jÛ¼©íKz—ɼèÏ"/?ŒrðA’½ªìY<šL¤£Òîh†Žª‘Õ„èH[ÏòçÚ§–1Ò‘­mCÄ[“#–ôÎ`_”ÀøÄu›dä 8¼mf³nÂétJˆè&f±óƒp~1ŸŽMÇAËÎಖՆS\±ù1±í”ÙFí™§k€æ¶å ¿¡îöæ"ŸYîæ8LeKW£ òÒ¶ šíúÞ\ú›Îäìä¶£H{’îÐhîÓÅ®GƒhðûÛòÐ;Á$ïL)Ò)}Ÿ­^hÛãC:»2Žª’¾iqoóxŽ¡I½»:ta… „¢¦Q§ëá^\O]ñ‹õ–¸ø$=îñ诹^,2;˜½—kÙ;åéž %9Ê8Ÿ”Ú6çùÕÅn×J›Ã"–¥c;/ºM€‰UCe'³vÊíLÇhmÆ3àâ¨éøxþ8TüüõãKù/Ûà +endstream endobj 84 0 obj <> endobj 94 0 obj [/ICCBased 49 0 R] endobj 81 0 obj <>stream +H‰ŒWÍŠ&É ¼OQ/P5))•?WÁ'c–=ì4Ø>ô–ypD(¿ÙÁxaièîªÊ¥Šüò¯×—¿m×_þúõzýöj—·ñ¬™×¯øßÚzvï×çËú~–­ËŽçhüºŸ=â<9ÆÆæ“¥=ÖóòÕž¡Ùÿ~ýrýçõåëÏíúøv5|Ýø=ÆÄïµüº¾}àóßðù_ß^¿]v5üØåßî¶/ëñô‰ >UClw>½ÃYvÝfg\ñŒ=ð4 ¿ú“c\¯ÛãÂèˆëv›&¶î×ý™$ŸÆq½=óÖÜ×ÝÇc¹°æÂ’8Q8Oï>94Ç“îˆ>ùu`û…í »Œ|¢q…'òëûéïžO"-÷Ä©f{vð±?Ïß9|ŽÇƒ§Z8§gó”îOK×s"i·'Xg†-,å(Ò¨%‡aÉ@ôƆ4#¢@X¡B2nÞë`Œã:ξñw´§1“}=­)‡¹ë¨x€Á§ÞlF‰7³œµ6Ò¨ô®1SéómšåÏâ4êEW‚¹s×*‰ZeÅÒq¦Úifźþ{ÄÓr`c‹ zÎïùžÏt„þ„ +²‘¸®ô4z޽•@¡Ò1Y¤8bk„w·a†¶Dâ8Ór”–3ðg.^0(ÔâFR˜p„¼T_ÿ|ýô²‹?âì\å ëŽ\‚¿s•2À | &O@¶¾•>@pÍŠ3AÈ™"¤wß/èk8Ôf>nÊx5Zž”͉DŽÝG¬²ˆ +|ι@<°Ú±Y¸4Y¥¹˜ Ç'v  +¢º¸„T¸çÉUèIHÍý g +!P®Õ²¹Ž1Å^¥t{eÏË{­ç™0ú,trÂá^å® ƒ˜ Õò‘ô¥!w2IO¤è jTcÆ¡ÃhÅK_v˜ÚyæÄao¾´M/î†Hg8 kÈœóMÌUû°Z|Á%ó:¶EUdiX…Öâ·‘DÅ©?F´cŒq, +ÀnÁŠ:€qJŒIžMÅùúÀÐIe¦šŸ7S ¸ŒYzÈÓ(çYÃ¥·X· +L˜’ÊQ† _Xd‰kÊÒ’ûˆœq¢ k-”ð!Š!tµ£¨âÈטTsl¦Ñì#‹­¢Å†± òXª©#4œ«t'T»C„ ‰%ñÕ(^@íäL/Ø ~â™äb”ì&Ô!/4£Ê:V.¹B.I Ð_eA° ƒ´ïܾGÇäÒ#¶Ä_«Mí¨¹%¡HM¨vIíb8—]0‘_~œm†Ðm¾õLýü áÏs©V’D<º‹>ì!\.<ůUDG¯ÓØ}ÀÍý%ÛÎÅBŠQ*-XcR ¸O@‹=ÏJ€0ˆpá iLØÿsÌ(@‹°’`–w¼û!Zˆ8ŽÓHØ¡×Å$/ŨbÑìÊ"Ø Sr‹_˜ÌnšªDU8ÇGT‹(H•ÈѤÄZóòdd Ì–éê[>ûÅ6«¤‚ÑéW…`³ñ ŒCÊÙ«µ  .ÁW²jO•%ŠM{¹@6û:}L2H¸•Рˆv9.R{)ÏÀä>ÒCjiŒyì:¸¥Åä¤2!EVZE€µYkW}§œ›•†M¶Ù%®³ýÖŒÖ]ÞŽýKÎVÝb&êõCjòÆÄDW-ÿвìÄì!j6æ;i_äPÊMäªVEàè¥r‹ŠÂÌÍ~lMðM²Óæá’ĉöÈâèÞfçB†iBë çóM®ø? ¬~û~ù‡Þ«°Ù{íø±õ¯IsÀ&L“Á¶r[ˆ»tBŸáˆ +‚@$i?äfBà§,:j…ŽJŽE‡+! EóFhBUÜà’Ñ'—Æ¢Xþ 'ÓÐÀÄ\*@«CœÓÊÝ%û½SFQ;J=LD®ƒËç°Rî2àSb5ÞÔ“¤©=ÚË_u)åö<ªçÉÈ;¥ ì+E•¼â§ëMgËaT–ep³tqgá Ö>ò«ö œp¤š£`Œ¼I¨ñ¦,úGuUº!Focj4óíšI‹$ïS«),¨ —¾KàŽZѬmöÎt§9!›%`]–SZ«Œ"JΰÙô™C”PÌN¦V +俌,·@{;1w¨8ÈI-§¯Åàõvø)/LÇœ§B†AiÔF°ï–ý +á£(ïŽ÷ÆsÚ¹ú90úVò×BkÜ ÎÕ l±ºá±Ðìõöv8Œhs¹t£ íú–ò 1Ø® +ê øÓÚ,f¬¬aéÂS׉´ºÄŒ(:dz›Üݧ2ŸJXBb.‹KCºvµn¹½õ¢4Ç£" Ï‘õvú¾×±tÝýŠÝÔ˜]ÔDׯ îFjfÓê>Ñ:q‰$Mu:ÇHÈH«¢ôÅV·ØâÙfjÑáu›6»7+Æ.u]Œ(T½î:‡9T×Ű;Í h##RÓÅij 1|ˆáÂn~(·Ôz?ôÙ"T°+U3kj l y¬Zuú%Ç ˜û8’îqîÚ 1´¨¦gÕ¦Ïs¡j”œ±½í4sÀ&Ò«C ¬]:°Fi=qq—wËOu&÷ÓKžÕ¡.4Ii÷ ót!MÔÆ!ª{Ï}ˆ.I„" );q݇jʱɺè©W9`3Më³KT†”†EWÔóûmÊt&wƒëhÏ£RɆ~  mëèþÈ(:0Ò’päý`§£e¾ƒ¢ÜÚmï E"Ù“PFÄÔ~ãŸ!îXåÓy‹„Z"p:ìÁ^Í$×d´—Ds—Áá3t/Çó°Øôàıƀ“þo©¯"ôiòæ*P¾eÍúEBکƬçAèÐïD=ëv³¢™éFzS"÷uDšêè†Æk;¦íROgýx®”¿U*¼¦W§Í(=´^U¦àeÓ”PÞt0¹srPÔ5\Ê"k›JZŒj°´£.¢ýt/aîKêÉ D‘jóæègÁt™€h¡ëp:9",pU÷–,¿–Õ/ë2D‹'·•Š©Û»aú•)$&ïQ¡-2äE \Í /ž^ÊàéÇÍ*»œ‰­Îuu”þÄÊÓjYêÅVÝx°o‘=¾«ÍªFÁÜQȰ¦zT±g™ˆMµ5§ᑽ‡ŒÃ@…‰ f‰±\ ¯#ã*7*€.•à„¨üœšIŽ}$¨Ó(Ù–^s$d'´²îuæ§"œ²ºØaKÔ3Ôµ½cdJâŠrêÚ†©‹*òŽ‚ÚÑà rêWÔ”Ò-9奫,„¥€²»ú—¬“²j».AÀMˆ ¼Eþ/ñþ¤ÞÄ5Pçôl +¿7[ºr^±œ)³¦ÔUªtOK6^ö_ÆËË®‰¡¾V‘ça=r³÷ï6.À/Õ©vÚ’øó |Áˆ à‘pèBÕr{nu_£õÍ£ËCbØ$tg±¡éFÑ—…wÛƒê©0šóX$÷ØÁè:ËvŸŽ­ü›Äei l­/@%«™Ê'Ùåžô ù/‰wœ(ç)He|Ôek¯µýMûÌÐXëb©W Å ç‘ù|óÒ³lÑcéж‹IT[ݧƒ¯ê÷Ù2;Ñù¤·dD $¬§Å[å˜^FµðÀ×µ,ÌŒ–iùT3ÑVd¨îÃÂÜqj†i[i¤ù3¶»g:ÏGã·;©¡‚e½Ú Ù ðLÒ:ïèš…¢Ù-ûP]ÀVu]Â9…n!À4ÛÛð¨†è©D‰_€‰óS€Ï'åø#°g//ÖÝ|C‚|à®%vé>W‹‚Ñ=›¨>A§Ò×í¦Õnl»c…í@–—µŽ÷íüqÄ5Õr[i½} D/áANp¸ktÒ7œß6fÅÜž6fiÖˆö´cà:Àо PÙ^Çì÷¤Ì늹·™­í%Éq-ãtÙ$¡bï|bÅOƒÄ#çÚÜWÕ £¯>G~<qÒQmݯ‘N¹ŽBÅnÅä·Å² ý±š|s_%ñÅ»RÜܨ—élM ŒÊjÏÅ“¯¡óÓk¯WG_ Æ4aº°­$>StHeÿÙäªJ[ej.$øKKmIõD‡lZ¦‘[cäA’¦ÊÝåíbñ`{àÙ<+Ýñ ÍÓ-õíº´ J{ûæ6…ÉÈXip½§oOwês|¸àqÒÓ¯ÁS|Œ¢"Ç¢­-'ŸœÞíƒyBöÚÖVð4T×±‘üißéÜÅPžô¦–—1PõÞ¼>A'‰#×Û ƒN¨#K¿±n–Ðã7^FM_]hLok*ÈF°ub4dZ|=5pr¿Ÿë>Rú‚š¿óeŒL Ë+>þ‘³?“M2Ñ܉ŠZà­nì‚£ÑÄ'zÍ‘Il‰kcÍGò±s=ÆÝ“+nÉÚì’Ñ—¹rX"! ýöTÝx§]ÓX5ŽM¿Ôc¿<þ¨žk4{çq7!‹ÈødfœÇM*µÞ;j ÑøÖü2VP¼ zÕðÕ~ÌX8kÀ”d£ŸÈáØºêø1j0p=Ã6ïytÄ^­ x8¨8cDkÍ íé®Ù?TÚÁºÆTv[Â)ÖzOùÏMF*˜*&`=q~ý1GLÜÝý‰uq$ئëó ÷$Z߬‡4LFÁj£›u…c‚°êiÔìÌü‰…µkîÁ*²‚!‰«Ë –¬X@Æ7•ڴщ}'ä–õ½ñöå´=OŠ5DÓ1.`±•\ž =Œ¢Pƒ UNSjãv2Âc3K¢¨év.¨¦F¢‰u¤&'hö¬;‰t3;Ó›KdJ}¤é=´øÑÖÚí(4þî?.*EkÐجêcì-.ͯîõùkà4ñ‰í9¦…|5‹^Ï95 o¸A#°âÆu’7H†Ã(û£+íãûx‰0a—Cº¶Ü`ópDë¡H“ÁGé înL{V$ m÷™»4â²K )HS‡âŽ“87R‚ns`ÒYÙ#iByß4“Uã­Úª~©Œö \ë2O—ð{8ÞµcFG<ý+èknD­‘øåž°ìTTÜ®£W§cJðð).Èð* ‡/‹ââ Ãw»û'AÕÜžíÁtÚêx/€l Vš•}?&[§¦†@€®ÆÊ-#xÍ }Œ÷Qª\¼–y+š¾ n˜W{ƒe‡›‰Þi|wåb'ë xÖnTÝŸpá†qÖtìhŽ'$Ô·íeH´¥³Žá¸’ˆœÔ/dlI6”|ÙiÎpÞó±R„ k:Œù rîàºìÀ´•X\ÓØ>K;B>hÜðWp\zžpð—銋øß'†±¶ÿ¸±WoX‰„”ñyö3Ògç˜Òo[ñVÞ>Òjƒ}êvÝŒ³ç.ýåLë‡^“WîÓD´0q¤­÷ÂíćÏ$8k5…ÁËö¬ÁtÄÂ*îPÔâÁûz±i|E™Û‹U÷ã™9 Å/žøC±zÖsš‘ìãñnÖ£éä€"Ä¡ü„¿mC‹ãK±›,Ž©ÿ²¤Ê02RÚž´ Qä¯'Õ aI'u[Lé¥ùÇŸðôk„ÏÀƒH&Á<¦T­Y'›zÐ n mÝU†‰ËÔã¡Æ¦Ø Ùˆt8 º=`’¾h9 +Ï0—R#eÇ„ž©Òv_oÝ›EfËiW4áüz_MzEïñ0û‹wlÁÇeÀoÝdœ_õù–Jä,Û©ø|h«Û 1š½ógOšDJÉ78èÓì8t~VZ¼³Þ[­9z_ûR)Žk?÷ìžáj“I-¬fä͘Œk·AŸ˜Úºs%Bÿ ¸;W…Íõ­'p2 #)±¸û›‰xNÍúYaÆÞ×{ØGò†ŸÈÉ­Gõ½ÓG¨é¼n}‘¨ÿ±©'TwÆpOïéycAD¿I|Û½˜¬Ë®ÄõËÅ©ÈãÉUs&ù +Ín{)of½ó8£„ŸõsßeÅÞä÷Gxt¿VŒŒe„bâ´§è¦Ôâú‹uÞâ“ÄÂ*ßp^ç«â@›‰ŸÓÜþ™ S-)"-£×ŠÏæÇÅgÖçIxæúªÓoDžÔ%:ØŽ:³«£¾°_·õVcÉ\¸ã§>Kó·[g\¬ÜˆRu'8ìšåõ¶æ9éQv•¤‘ôâ…AÕ‹(}Óì;ŽÁ-J½ŠãÄOꮫJœz çÙ³/´Ò”$1áµæ¬tv¾4~¬|« 왦kÚL;]§ù—i¤,Æ¿.“!·•îCU¬xÔôk‹ål¬ÕÂóy›vL”Ú?H6®ÛhñŸ\ ý´2ŒËz§ój¾2m«36¨Î2ÛðÈx=¬6߽ޤKeªWÌôj‚SKˆ}]ÑBµ®1Œ×¹žkÕ´ÚÇ̓ÅÛ'Nƒ$ðe\í ø¢³jµ˜*î¡~!ù5V××JàÝÅ|V›z%Øo 'ª6'Úüþ…ƒ·ôu޶λZ¿.R­g¬åi*÷ƒ„»J1‰›+’ •ç{WFÝ +ñíö^÷ñ¨ECáçc¶_<2úµ¿Ðøn8}¿Pto~™ø@ ²ý‚í ÁWû³Ø›Ú×ãVŒH}!y>aœˆE-1+#Ö„ê^ÿBüN]Aå|×’‚­ídëtæcc5á +s&ðΑ7Úah}cØEðj $÷<t¬“ZÆ‹jóÖjêàÏ¡¼ ¤•p÷@ÎH{Üé¯ùð£#FËgÅý‡2^™4n&£S%üº79¬(G nN¶Ú]s4PvnÇ;«xnÀÞðƒeUêÌíqÎú·kcõùc5 a€^?¥;ÿvP©¨CKœ‚ÐÁ4ÚÄl¼‘踢]\üÿ&Êjö^‹ÝZKPPgj§nk¦S]VM0ïÓSy<%Ú¼#Ôõ€DgMÖˆ›¡Àg3)Kþ‰Épcá¸6€Ô9°’† ]ûådÕ®ýšº`ø=3 ©>\~Á¬ýwXϾo]¯‰vH™½º×Ej¸$u œ×ë¿‚²’HÕ<`O±LÔ¢µT”#Ò Ü]³lW´:¦ØXËA¥ó®Ž^÷Ú«äÍøš‹`Q1YWq\k;Ö|èË“ –k+v®è¬QšW-39ª‘~UKUôÖŽH›ÖÖèP‡»n‡Eÿ.÷küª~n`ñjØýíó`sAå5³t“ÇFFg'…íK‘V‹íyBÍw:o$Èž|¿ˆuoö¿ J5¹=žî[A‚åï.ÓÞlå ‰“vG0âÚ<Se¹=ALìþ¥œÀ {˜‘Ä ,Ÿ{š¾AŽd/ úý[ý/ãå’\ËÄйWá ÈÁÿg=oªÞÿ´q^…»vx"oU±Xd&pðtø>¬NÕÐŒJlÃ'°6­ ÷AØêþÐ^Þ—¤^°“Ž¢h<9t…‘“E%e¾pF ÂyÙÊv‘P—E±îÀk4¼/Ó5ÝASh%STÈ[Ž‘·º`¦…™U•BRØ|,mwÝ}¡Ž^Íó§¤:ªŽ_'RR: Ð ß®•#!>6Ù®Ú•Å«^&.ëV9 DŒòfV—wMã²}H{ÔdJ]Žœôæö¨v½a~˜\…äܪ/J Ç<†ŽµŒ4Ã+øzþ¢B€›u¤Ã£âÓ1åßIÌuòù2tHœ¡¶vSŠ=’±ŒJÄsþ"^ß/ÍÎ ¼mǹ¦]ý?ò“3Jc4­¬€ü3ùiÕ’¤'W†ážRó 5Û°®²mÇùTk9>í¿6Ñ„¥kª¦õŽöE•‡.*mî šS³œ ¬ÌumN³¢©3‚¯Vñ7.óŽ,)­49VöðVÌ–x¤^Ø÷Yþ oF½0þA­¶› z6waÂ8@tW2ŸÕsÎìRg#Ö ~ã|‘6[m·ã¡ä Í9^vj¥è'-Õ‚ð#=Ò¥r›y¿ö*c§PIåó»êQµ´$ÓçÞf¿×æøÞãìoëµóvÕûÈ­ÃܨîÜ '¯¶ã¸ùw¶—3ÓéQÕ^Üø¦¢ Õ`}èsÜáK\2Ž›µ:¨ßD7-hõ¿ƒ¬V<íoúÁoB’—¹YHJÿŸäĆs-Ãô2«œ´…àÜ6¹¢?ÇîÑÜ…õ1/îìšÀd‡¥i¶».=ŽÒ°ûð Kî÷o(}`¬ÔŒTÑkó< ¯y¡J‡ÄT1C­ŒSîˆÝ\-pVÐéF¹ÐØeôÕ`‘êÇòâøºâ¤Î3šŠÀ¿ŒÅÌFyq¶ûE©%eùÒ—Ý}):kTà6ÒPU¦©k¢y‡JYjâné/|®é;sL.!£b‡ˆK"jY| '’’õiP­ìQÅì§¿Ç7&Úóëï“jño¤½:Güg½šê–SU‘Iv¨Éjc8))Ñcx½"JÕÍ#•UU-&öñUí“×!Ì6§ãM(D¢JCÜl1’(p~¼w¦ó$ŒÔ¡–ZÊAˆúZ*þ"T³9c¶è†$'¢‰ 錓YŠKYíý‰5%í×ë G†Úâ8ÈBv÷YЊUçVó ?èKâ³L.U6ß|zT?±IÒëôNqëQÍiMÓK*kÆÜдž~ÓÙ¢W¼äÁ¯ÝíkP¤HÖªN$¸f‹šÅån”nìÜ»ÚS>[êòD6™®¶nóÃÔ§Ú›û4û­jlÇ÷®YŸ±6¿sO[m@úúxñÉhž€Àô*ç¼>1köê˜FzÍÐM;ó¡ª7O0„Žßá—J%h•Íóº•ïxº¶x²ÍèZµ±:Ëšuµ±“ªw˜IMe&¦ïg´z¢ ˆÞ© %Y¢Æ¿M5¶1‘¯/ZQu}Rfb‰Êb7ŠëÇ×OáùäR¯™Ta/ª8—‘Š^€õ@»×câ76ÃøçeÒåÒê–pÕTY¡¼*uF-{ú¹2ézf¡]¬Ù dïêg½{¢7ÇΆìÝêÚ]Ù·í +1¤¾éQCÍö޲To]ëTO,T)ù1BqÒÕ¾öA‹žùTÐ=N¨=&“·h ;±¤è=¦sZ-6È’1%·…ÿ±,ô‹„ØÊˆ:ë +S4À@‹éò^0Á è|z$QÓit-T×öyáaÑæ2/%ÉDÁǨtRš<«ã·Z\04l°Íõ#â3«ÆðJÚÏ»³n6UtÔ%!]Ý[í8Ë)øÞµ}íÔ›{çõŽÌ4cPçæ0»ßrû»·Ç¢îyîäE–æ«[S[6œPS{U+RÉ(Twè,Ǽ \;“.RJ­ë()ÀGiËwHcëãcÓ.gtB—oJ]«G.ÍcØ·V'gC:ÐŒØÏÑåiÛçۚȕC)è1­®ÓHâ¦n¬ÒM{ÓôÖ»mªuJK¨QÛÚ¸N»~kG:¦Å™¿;§õÂí5¬Nû²ò›œ(r¡Òµp®.B;,\’’/cT•t@m]¡—êv¹2AH6¶Z;¡m+}–ŠsJRûo»@u_’M3£±:”2ôŽNu[èKêB{8ãúê£!à“Q0ø&HÍ,¾æjñBZ´…Ÿ;i·ñ‡éM[â[·)5P¦ÑÉ(“jöO]êÛûª»Cê²½ÕOiÅFN2i&“Úh¾ã@ ¦‘@Ë RgˆÌ¤Ç€†”¡%e¤¹…¶u>›Å6U|Ð_S»5{Úð<†Y›ôåBúIú·©²:ôEMk>ûû¡4ìËÔâFRk-îÌ«íõŸ%Ñܸ—>†Ã/5Ìðݶ†Ú(Šk•Jµýé1#e9òÜl±ßa]8†ž¸zU`g€!ºRn̘\À“‡ƒS3Œà# îh¨C|nÔ]q ?‘¡9g} ‹>Gø†td[Íz€oUÐ×ï‰ÒÌÚÊÅ!ˆ‘êUY\vL?líQá†ë²i½aÔÀör\ÓÏñ¶£uN´=+áç9Œ·¬rMŠ`èŒ+{†¦B8ÅèM™ü \¶Èw©ª^ï¹ÞM éõoº©0MMׇ5Ô*kvúYCàU|‹)VG£Ìñã·8É L惔ê+û±#ý’”/4£oG#íÞÈJW5L{&˜µÆbã[ ›¨Õw ÒðdH>û˜ùÁÖnY`˜BϦ2\zWªx¸î%ËÃC³†7W£T€k†6q^ݶfìÏ)[W©>€©ù¸¦eRÈ-¶¬{¿Üõ8Þy,!š´•ðàr«¦@ÊOzZF®ƒ„É(ÓöMFãIþÒ;+Žx\Ò“M–YÎ#žg­ç6-Ær¬‰§boÂh¾­lßÿY ó鳟ßÀö5ê}pÓìO˜~ؽ¥ûÍØŒµÀ1M,fRT-ÝîÍ)Žú_½pY4¹†ÝYÝ»i + “<Ooìç60Ï™8æc–5 Nb¸ìâNçBÿ>IÉÀ +¸¸eYã5ZÊFÍã"ÃU¤úkÄDÈvÓ s¿»SàÊNÍ*_{®/pêîó‰ªð¤Q÷]¿Þ%ă!ØáÛwËìç8E$í4˜§¯98Ñü‡Duõ”ö“ª“~­þ¨qÌjF¿ú_! +Hm­ÿ’ w‰†ÛåÞÁS/ú³7¨žÖ'ѳó  ?‘_<q¶7sÚÈzç’qGûš±\?œ9*Cmæ»Õ+µ´ÏñD䲚W^‚ð }ÄøïÚ‰ ugÎññ°mLÕRöÆ‘’8ëõ^`Ë%š¶jÕvIÆÉÎBµ´<ëѰûv]…Ük;ò¬Ã†×Wuzgš”×;ÔÅÎÇíµ¥u™**ÔV7£Qó7óC½3Ôq2\ŒúJ”ª-íeÔÅÐy4ý윹»Äjq¯Häe·4ŒBÞܽGäôÔ©Oë]ŒPçÍpìjF¦jtª&,LwYa%À;Œ =¹Ä%ã{rz` UÞÝç Â0ÂÏž8SMÅã¼܉Œ'jh¨ñT8§ ÿ÷=9]¿}§9#MÞ„•Î]ºtÒKî„ë$®ÜÈÞûGQ¿¶+ž³ìÿe¼Lrì¸ z•¾@ œ‡óh+ßëxüòðªÅ™™1‰ÿàÁ‚›d[«YÞ²ÚΓÁÆÔüd÷ZtÅÅÀ +^•íŠe$j|Œ +îO+‹£V”TžpÇû¨¦ZÆ—-…–­¿ÿ§‹Â{ÍÿîõiÀz£_ØTÞÄ=³Œ¢šøñ0ã%N‰”»˜1¢cöZï ØÃŸ€«Mío»³mk!î6Ÿ4¬ú˜{ ³^÷òŒÝ¨³žšxìYä4(´± à¤a܃9M@gÚ4½õ—“ÔŒ Vÿ`…óÄi}eíÂ…ù e¸ðAÁ\Ñ]ï÷¥§$@Uz°dާü¾áާÂ37gÔó ãAÎ3™t§ÂeåÝ«'õΧZ‚ÙBÖÈLKݰÓÃè¸ÏgBø_Vž&-§ƒªÇˆå]€ý¹ø›¶— ¼{Êj—Ýd2?H”ur`y^Xœú6ü§ïq +K¹€Zööô™ÝáÔÌñþÒ]jŒpWͤ%¼ñ®Ï@Ôº\¥ËÊðá’!2 TÆJ½&qŒ¹ª¾Ä0¹¶â¢ç¢"úÇÚñÉO>>%Ò²x +Ãf0˜‡qšíð:†H’„Øwš-qPhfÑÛqß+#Ãáè6,²ÐÎîx2<}4»½ÜVà +GD’ÑyË‘wo]i©ÅówÒæL€ïm+WwŠ:»Iéï÷Ó.R—R%ŠMŒú£Qø—£¬¥Âìû«ê5õjó_޲ø…úY­!ù+£ OêV*,W¯Ã§ íñ ,¹¡Ì:ú«ª÷ØöqX­j[ö÷¹w×tef¾Uø-\è>QXÒ™ª³’M– T™3OýÂAzâ çͤ8lBFB\”ËL½U5$öm›ù]¥¾Qƒn½ŽŒã×6ô;MÏx1¯™YÉmQ^ý¯8jÄ8Ðlu±ÇøVDCžDãÐ_Ψ• @@ç³$ÎŒØC««ß._§ÄN+ ɱãn|ìÛµcس ×±íW&YŒnBSÑÅ4XÍa¥ž––•5ŒDýšù†¯D«Ml½¼#Éþô˜Žƒv—ßHÝr01#ñ£<›‡ÂÎxK†/¤}Œ2†ÞQHåpú¹ô>¹ÅÐjuçºÉ#æ3'«²cO쀱v–õ«ÅSOg ¥˜VÅ™6JÃ&“%N†ºœ²²õCU⊵‹®éš9$ŽL*C›)}ÿ~XÆq?ÿ;ÜÕ¢mUv°^){ò(ªó¿¡¨ù8 Vu§§H/5|Ä.!ZN¢Imõ¨ê°Å}Yݧ/;«™!“  BÚooG?fwŽZž¢àkËTJ¹úâ¢BD_ÙUá°Û[µ„ËÈ:‰sÀ#d +ÖœÂj²Ÿº =ÕÖöeÍÃüðI4JZéæg굺_õŒr‡éj øíù~V×â#™ïa°èf±||ü¬*¨ÉV½è­zÉREX§«ÄÈYïÅÓ…¿zs‹š3‰:Óó~VóÛ…9]¢C»šNñ¯Nï¶'©ÜiTÙ©ˆPƒåŽ“¡+úX„dǪŠÛà2´ÄGž¨çvàÔû‡ù°<ÿÚí ‘îƒºpÁjëCN½f“Ýr*s´"EÆžòÁ©O°ûÛ±±@#VÙFü”$Õ£7l¸ØÑ,¬"{ªÇ†yøIPâk”øÇ o[H&”í¸èV”b†/TzFí¢\ª˜¹~R˜¢Sii§Ž—=7Û/ÛÅ„ÏQ°%*2à’Ãæ›$½zdÊ56"À@ú{-ìI®râVlyd98°zd«FiÙø0²Ã™V3c¯¥{ª½°Wôå\¸l'*`„–•cˆ‘oèásëò L³cgÈ^X4¨×kκÇÖÞ¯xˆÙj¨[÷ëKÌàF$z~¿… ®$—ÙñÙÚ_—M;™â¡Ã¦02-ñwmÖ­ž`õ•íÕ‘޵†#8¨$ 5u©>i7¡©ŒE3‚\) W")˜íž H”¾ OðßæP©™vN€-âx!‚ùb ïK”úÛfò¼XRŠ# ”„&l¶ +#ç=ànð”äaº­ ’¤€Â)0 ´$TõcyîçA|1Z¼¶Ê(8ßU«>þzØ(@µ:L§–¨L÷d‚œþñ ŠJëã×£­>z3%­4üà:I5•v‰ÊL‹’ÿ½™Ýj£ïéݾ‰î„è_òÀ¶éÔ•qØZ…¿Á»Ý¸ ‚ѽƆýðpŠ…MãtËSáߎ—+ñwtýú¾–ÜA\DK—õ—”š:ãyôƒË±—Ž‘ÃÌc33Ÿ¬7’*ã ÇÒCÐ3Èd÷÷a¦F3sÔxgž¬yÞ5ñßC÷a17Ìjê)‰辩GgÞQßÖŒí†N=&¶©¼ê“n3ëÌÛÄÎkefÉ”cù¡Ùù3WŸÚßbtžùê [©]óä˜å8Ý%;˜G;ýÑ?ΈŽÌ–Çz„ Þºð5˜j½a¨Ê²{ä÷Óó&•ùÞÔ¯Ú0å +fïæj .†^^/Xclj¤jþʬ#š{KÅÕPå+œ |ÜÈÕèv–\l;ج°Ì“YLcÃ_MáqêÛ6F¦Yê$34®—zGµ°Žµc1pÜe½Á³…ð/ê3æ‚Åâ/«o¢LÏ +äu*g3±ÒÜ ­™–V³L4|Ñr x¾Ÿbšu)jGM f ùë¿1d¬jLå¸û?1ܨ¢º2Ñm÷ö k­‡Yó×p}ùª·Ú«‘ê`¹#WK0ÙK¨×–(ÞÇÌs¾àÃMY°ºÆ…¿ú!y2„–w:Ñéïf¬;Õ^÷±¾÷Ñèù±œœh{ŒÏƒôÍÔ–ôê$®Ë%ZàJ¤×E ò(ˆæŠØÝ^Ã~¾ƒzõ¸¾ÃÉÇwýHå[p¸–£´ x@Š<ÐÿûnÃ?^"‡ÎH¡mŸ)L +ð†Éô„ e„=Š.«#¬ñ¤zêVð‘% |®ƒ°êÞpcúàG¢_cnÇ>–üÓn4OŽ9À„ºîѼMKµÊ&=\Š‹95"Âô*l—¤©ò}yÕ|[‚Ž‹ª5ÂÕ‚ÌNëÆ4ÔB—:Ýаڈ¢PÉE1½í¶çÛP\žàUÓgo‚#±¬,Ò~#Úu§ËX_@*ýð=P늨Þp—Âq†7z¢Ày·g00 z_] ¾×²²íà"'—#q4Zû xBu™ED¯±;Àš\m¬ð@¥]Ò¹»ó€}¤]ØüƒÒf»ºÖ³d–GýÄÄ5 ¢iêOÉÃmÝÈëŠÓšØ‚ÛUBw‡ •¸Š°ªÐ½HpAwI (–,„ŠûµwïóJCA¡-T| êwxÓSÓpçãî ¶Ó.‚B @ÆäòTÝ®~Ì-Ìß“©-WØ#|ËNû¤ŒÈYV&ÅÚK*ƒ 4×b×ÚÛ¼HY=0A$Çäö+‡õ2O¬z¼Ü·/SŠU•¢>]€ÄÌE#O›¼lÝü+³£LA׌D\g€“Ø\“âu_rEDLïë±E"ÓZ2õ*¿’ƒ5ΡnÜ—¯ˆ,h6cd€~ú¶eÁ‚èiß“Ÿw´ø;#M6§9±ÆíDÍ.ð¢ÔÉ" +<̵µ¥hºô$j ÷‹›ß*÷*T®sÖF˜Uá|K0ÓÞŒMׂŽi7ð€¯a¢T"²TqÍEpÛî¬qa g +•L|a€{Ö¬çRƒæ§¸ í–g,Z×´}s‚É#QƒwËÃJµlî ô¬i¸w¢>Õ‰ËÊÊDfÞ5·@ÂÅFê€J¼³OªÝGã‚ÝÂëuP$F¶²Ï-Ó¹ºFЍ¶<ô®h.‡õÆë{‰]ÕR ?w fÅ Ó$ d‰±ÞÒnN2…Yu~—–ÝÌ~Eîפ² µÊÖüЄŽ—ô}ã«Ûïž%iÚ•i'¢SÁ…˜îqý1»a>Ç{ßDc䚆¡?Í Ï·ëá”)Oèj¶Û'ט<Å`MVXÊ*þA_¾28x9n3 žå6á d¤¹‘÷è¾2¥¾—1éÔ“Ë4-nt­›‰ÍR†¿ˆæ„öc +7 NÜC”+g¨PèòöPÄ!‘öÌ—'@¯a2hR[›¼ó±*ßù43÷]Ño¢æ•Ã:]=á(Þ¥]×]°[ànù¼ÏÜØN áÃ0•x²Èû<°à*Åökw°lÝ£,¿Ti÷š¾"îq±‹‚ªŽg>¡Ìæz”áV„ýAIÀŠUù‘ Ä?”§= "âEåy“‚yÔw á5­6v[Ù‚Ö>NTu„iK/ +n$|iªƒÂç4Û–’x|%-‘Ø©Ù>¡<ÛìpÍ Š¨5ú°%ÒáÅ߈ÊA”Å|N<_r$ÒÌ^Z&²RÁ¨åÙj/Póc5»·™…-øñ\¢ýaqŸŒ¼B›Bî3ï,îä"Œ°ìc;lð—ºü†ÔË*äø¦`o ±âbáŠø 3#“•™`u˜§cäâI©7n2öqYä©Ü˜âÆ])¶Ö«`Q~_µÞæWeŽT3ÂÜmõÍLÜmitŽÝ¯Euƒ(3_;²b#‘릻ša¬Ï6væH]G%hÌáÁ5oÊo‡Ë´ŽTq©3øb…mÛÆ¶¹©†­’Ãâ°Æ–)Q¢lE|Ç¡Л®óãÆ`%Â8:.«âí­q6…-rT°?\VùŠ|­+u:Àõ=¹ tà5ŸÌòøÀ ½5áf»[7_)Q º‚Àî°:\ãr8ÊÝú¾¯›¹7ßÿáµíÇÇ÷[†åÝá]ö÷Ö·æÜKµ»;©%ñæÕp®%õÜqâ5½`¦ÊS˜,ÉÛeMª|ÁA˜ôI• Ò“LGæö@³é×ø¯Öð +Ô•PÍÀ qØ%:Îê"¿Q¯š+¼ìö”ô2`&ÞíÏu5ϸÎ@o°”x†5‘vÖ5½_ûX'a÷Äzíþ>ô˸C!ÛáîòGøËÇŠîwBÝ~ÞÝkÁèêw÷<¥FñgóýS0=lD9®ÊWz¦ÏÔ mpzn;TT#[UJ ÚÜÈJͦ­gYº£Š +ÝWÝKýUè´S˜…Ç‘ÿ´«ÔI¡cnïo¢Êvr’réóçd.—PZ¡…czˆ2Ã*ÄèÙ{žîr­úø@<ꛂøàqUÞÌ®Ã{˜•à« + ¹¢,ºõ d€ô¢”ÿD±Fø‚^¬aÊ€I€¾zÇC˜eË4±}'*Q*Ÿrî~|™4J°¤Œmw¡ðJëùXéq» 7ëÆUbŸÈ‰ •ìEÕiДX*³m™·KH™2U™LÀò•)Ìö¶bfËBåÞˆP™1žøÐ}íŽùB ÛŠÎ)c´Áf¯-eìË9‘â¼ßx‚2ž"í‰úÒŸÇgVû˜g„Œë=òñKëâ¨tÎJGëՉܥ®)fnÉ#¢öÈ+z†}¥ç¢3â1·Ô!S'ôn)䉽BÇxœU»–—Žç-mͽ|¿Úé3^BSçµeßvégfgÏmAÝ­{TÊñ¤Þ'WXÙÌ›iŽ›‘Âb~9Q˜.[åµ5V +°ã7½ÄPÐQ‰¹fù}Ü´v¡ç„91”§ç™³XM Eòíœ×„6ø@©]cSLäµÝ¦S}w‹9¸ŠPRÎÖO¼^¸þfl˜þb›Ø52- e˜U܇‰d6Ã?&ô €yâ)di\…÷w÷îZ˜@«rb×Xƒ0VâC^%¹ N4ƒæÔä£SX> +>>ÿ„"¾•u{Z“«÷þ–Ôœ‘d&HLʸ,w«=Enµ÷nµ«žGª OA« ëÜÍØ(Ý·s¿Jõ)ˆ$6(®‰lÀÃl+ÑNZ½£l©Èâ¹óÚw#È ‡-ÝËmuA“û y_[ÆR×W#tÝóUÜ(Ä›ˆ@/ßÃ`^ùÛ‡á[ד˜‰{ÞÙû~—¬v—dv{´-ßA‘h÷;mÔ8-ÎI=wÑy 62XZ“À´z‘Øfg‘1ŽÄÑæ¹!Q)WÛ׋è3XŽÓY+Ï\LjW_÷8}Ê põú 7ð|µ¦â€( +-ŽcÝŽl>5Ÿ±x#Q×õT?%Fyó…Þf¬I*è=o¯ęóî.%Zåëæë]õÛÙ•¼s ßs¤¥šp¥”Kbß,ÀÒå:!å7.—ÌðžRÍÜ „-«6³eÃüþ¼_Ú™¥zñ"`x°ƒN;PDC /2OŒÇœÆ'h8Þ X 2–ñ;#½©Í±Ž±©)ø Mï)%ÑØ$"þ¶ê.WŽ ¨Jž±“‘”zðŒ$öµ=Nm—à¼{Q¢GŽÍÀkù/Ùå–cinÃà÷ZEo ß/ËÈÈSO€ ûÂô©LP/%Û¿-‰õÑ„ÅRóíZã£â€ž±žÔ®í}¬¹Ç¢üJÿ¼ëf +ü=ý Hå9ßC ½5wõïž';»$Ì‘ö=or&úÓÕõµUÒµ×G¾¾”R‚ßîÊú-ö(çwiŒ¸†å3åÓŸ&ß~*lß·í£5(Ãißz1Ø4¹8Zk¹QÊÓ_²UòkÞøÆÙÁÅéqL«tNt|<“n+Y%ì—wPÿH¶òf ^ûͳd×C”Õˆ˜8Ê«8ò åG¼*ë)ýa=‡¼ÜŸÔ'ZÌö¤|îT%Âå»TŒ ÎRa¹ ŽÉ?>_“P§‹Ê¥Ã"gß`i:ÄQa&û‹£•õ}N n®3âSVæG Ÿ%×íYS«×d7€õšGµ@¶ŽÏ;'ÁÔ÷mº-°?ãÅ«sq¦‹žF!× WèýÖ^ĆÆ\-2Ÿë’^\¾ ŠN°ÞSwwK±ÖG”™sªkÇ}›œ9jýò6Uš®õnúùHzó9ÊùljdhŸ·†µØ®ª¿É“Ÿ_ÿúúç—†ýýøïÏýGÿýÕM2rÂ{Mâp£‡þùÅO’4"…ñ£˜Ç~aíäÒoSúS +|(¡P—g÷“æöG\:l3¦Y~ 5= +9~†¤óÁ4—+íªïX²U¹tHolÔš–®…£¯åFS,ØeSâÉL‹üu7cØ}eÐþ°yÌìÂçÂÚ^Џà.ó ÷¯êI +^µ’^ôŠËÎÄ"ŽíŒ[ dVuÌÈŠÈ£]45Óš‹õ2¾Y’ZoHè7¡¨ûd9v‹‚¥²©žžãE£Z°N$s{S®’û~EÕ“œÍ2™§õwöŽû ‰5Ë\…Ýúƒ‘£Z¾ë(«¸†¹“Ù ìÎD}š.”9æ7ŠÜúp[ÊäŒr²0¯›Ð÷GWu[ñáñU}ªHö. ªGÙ†Ïù§³f”iT'S'öΆžæ«!â¼Ü]ò¤KöÐ߉Zá½Ïžè}´ôÁV-U¨…Òsâ óÉSŸÇ_—Ýz$S?ÙÑZÊ!FË%œ<Ù¦ ö&ƒ¿•[´Nw܇¹çÏ((¯æ'ìÙbOúˆlvûè%xMޱ²°`Öä➬ï3„.Yts¢SÑá‚Ýœˆ'd×д<Ã/ ˆl˜ 6®¶×ÌJsÁ-:.\z §_öXÂÌŒ‹ÏãÆ¶Ýh¡nÝ™‚ÞÓÌOçQñeÝ‘ú• ˤçÛ|ÁÐȲ<¢ª<ÏŽ5ÛǺMv‹z칪d®ï¯2Õe:ö4ÏiaÏ‹ªKa3˜á?3m RˆF 9^¹ÍÏY½Ì€•2ì6‡9ºC+Ò˜§­ƒhRÉU~Tp¤åX‹› â8V{€-Œ]ž’&KÆÇk¹*»\ݪ¨…bæå·Ç¦š‘™AUn 6‹¸¢g*‘BO1—{¨´¤•jÑÃt•• ³éÙÒŒk}ÌëR9çüv ?fc«¹žª¤ù½ÊÜs”Êø:<ÌéëgeþóœÂmÖDí5žAÇŽÊz×/ýž®WsˆÔ§›¬ÏƒäT>67´ì]/D÷¸[ÄÉcB˜FS‚ +Ã*)õÅ|ûŒˆÑï-ÉÞÑ´¤ è13Þ˜£¶L&òz3:¾‡#_öDD© îÝÙ`~á?+|O½2 0©#KÛ>ç.êDÅË/ +‹2cú½¼®7Ì\H×ê9Îø—rxß¶öy‡´ kú®‡ +º;"]7õÕ¶ñð—«ï™%»Qḛ́;ß*efù"–ÐflÔ“fðä‹MüÂÜY;vì6|S7 ™ècÌßöYnૹì,7ùª¸ºÍ¹îÃùy7ù½''›²¸è*›í-³n_¼+w¾…Ê¢Fu v< B¶üi) ÙÖF­ü9ãP@§›ÒmƒoÙÕÚGõrž}RÞ"ÚOsGBfÕýh¶ýÉnÜgCïÙà1Gö ¼±OlKé´ÏÜŽ!ŽueúúíY&Œ“¾Å¬/§¿#¬på©gXð =˜.‚e1ö?²«$ɖ܆]Åè ÔÀóxûûþ[c ²ÊöªB(é¥D‚ Xn©êRéˆÙÊüô •fî—,"Ë¿¹®/!_@â¬:¡Ž²_ÑÙÓÈÝ>±‹¹Íšâì©+êÄY¦ºÜ$×iòÆrîðz›ÌD–‘S·aiYG¡—Ç•çñŽAÌ~­çúïëçÃÚÐò½Ã=D¥¥à/‹Ë˜ï!=Ko®J]CÚŠz; +¥—~9ƒÉv. ÎòeØié¡LKJdt±æx>²¬Š&[µdw2Vl'%ÃÇõà &_'²‹¼¥ý$ø8‡×3Ú3œ<Õ\hyÙîµFNjëòúÊpiVr¤!i^¸DÚÐJ†s0xšßŒ§­ø·$åâÛm¢Ì_Dqdýtü«—ð*G }xÄø¹<:õYÕÈT <ÝH»¶ÐŠ(¹ÓAK}¨û`}²¼Á•Gî÷™ðÖ„~Ë-„Fäº×þX+‹!ªòÊW[ì§ B†]á¾>7•Òê*óZX9€á¦©/Á@i@£ÍY!ƒµ¦=R°€‡‰´[["ß®î‘ +Å`' ©Aþgr#›WÓTG»þÇÈéÃ‚àš­»Ù­jÍ+¢"2ßo¨–›[$×—vk¡Z“°X¯ùNÜ3…DmH}ÂiZ4Üþ„+BÈ’«‘·ÕúèÚÔr¬»…ë]#KB¶H¨Éd­Äf¡ópRÅë÷i/ô1íFQÌ]ó–s¸Ü¥É»k6@Ò÷TM”EÛDÑMšï²·ì0¤²Üä9ÇÌÁa¶ïëIWÝèa±ifé:€uJs<‡ôÛаQuæIu¾Dü3Ü¥!ì•\ˇ G¼šNYQ'È`0Vmè +Ê‘FéDw#¾ª)ßIR‰’àzçß×*Ý_€Øq#ié-ÇEU½‹€M-Ôµ¿Cå)‘¾wÈJ¬Íõ>óq¿3; +;tiFydŽ €Ÿ- 5‚²kuvP=y7Ê}Ÿ‡G?ŸN¥n ñ×ÖÍ.m`‡z³$» a¶líÑfN Pd=rõfH6ÏôKÝìÔÈË3Ã[ ]>"÷JBIůšÃG_cûb“mÈì”é"¤IÀLÇùß^ÏZßi`ÝúÈ ¡·g¥ùqA¦˜ãšËÐ|{Æô¡ù~…ñÁzÜwÆKåh¢/‘nú)àl_½Rhhµ}JçC»;é{Ù1PeY®Z=B9‹`yJ ‚wCäZ…n¥¡®jØüAïÑІÊXt]J+J. 5½Äè»lŠÝÛ^î©”£ª!T]»ÚkÊåqíßS2þ8*'…?¡'‚Èe¯5”¥Û=XMšM<òv¾Zo[ÆÃîëáé­Ë»>{JOæù9!ãAÚë7i¡Hòäú¤L9Þ_ýñóãUÛu#"õF‰$G Fë¾XDJã#_¸–Ö­Ê*Cªz¾€ó]È~ed¬¯ª©ÃÝdRz$¶2“ #‘ˆŒ¼¹^éÇ3õß®ÂFo¿úij«]»-¶§\¶UÐñ?Fº#ƒ¤†¶4Ö¢àÒë¦ÒwýQ*Wã ת¸ÚJ®u‹žÕ‰ÑÔRæîíXUÍA TšGé[Pi.‘|½6yÔå8ªIæôó½l˜K:¤!h6ª±”)È4Í»M­€%­( +º£Q"{«¯ðòìùŽôÚqôYªõpíh¹ªwÌ.ƒ+¨§wœBÍÀ‡m +L4à ƒÇÕ?·zzp(QM=<è0µî雹ÉÏq´¬áµ"ú:p˜¶iéÔ'ØÀF ¯ÀùhüœàT#NÅ8Î÷Ée^ç~y?ηÈ+¯®š-Ü kŒÃ"jÉz Ѻ2 Ñuvaª9 (Ö%s†c U&pÔÂOã-"£IH­ +g?×ÙjîÀ*j@äˉX÷›Dì\Y³ÙÙ¾ähqÓLë:)eiw`šG@䟈dmÙ{ °£,Ÿyóí2ç ”ÿ1ÄlZxÑá•7§*‡‚ȧ"vSÀLëù1ÅŒÈf˜©yWkI,Jfû=U:@n½éÅò\gU6ëíQ8¼¥÷oÊ<×Í=Öáh„¥ÀìÞÝ$xŠ ¿ø›Gÿ6#ovWÿ83™šr‹“c ŒÊ.?ù×@+WQ>Š(ïK±ßêE±‡ë]€\?€ÑãU};1¯db†§³ûGæù”"t_Ð\5`…/g•Rl_nõX1Ém<›î¹X±yßµ5ªéÝèòtzÜÙ÷AÓ¡£âÐhÈ +Ì…¼ONtÅe‹ (Õ¨¨ ×lUâ×󽀜ã-sç"Àë<ïHW¾W•Ð ëìaüŽ{ýyÎcÀ¡r,[˜?ÿOŠç@qó YÎéyõÊ–¡füÇP°–sÑ®ÒxY ‘æíð‡²B¢þNÝLHð¯åª3 ;ÕEé4âÒ(nyT¦å´/ihöÚs)AIÿtp܇ºÏÒóW@h|"@mÀ!±%ƒ™,üz8£#‡ØìÝõ,ù§æaV¡èj) í±hH·#3…ˆ‹ßð«nª Æs¥ú9Õç NCÊL%›5Únc£Žm{I+jðƒ ÂrÕleŸßà«î¶…li )©LÿÚÅA6 +ÑÎTëÒJ®Áîyß÷liYûÇÈQ0€d+ä³¹ûï]Ç<ƒŽ%…tÿ~[FŒ2©D3*âÖ¡±êF†ý.¾†£yk¸3™`!ÃÄuÊ,è—.ug8QœTtŽd¼ä©é]‹Ã)>Ò" sR9´´Ì8º/£\“+Š/+CÖ¨Oýˇ÷9HÑç 0*éfU§®Jç–åÇšÞ³~%®ËbçwÅ*”žõú¤’²þZ»•l@#\ûuP¹»ôÕ”LÝŽäRb:4!ò*flk­Ùï”?LDýaæ§ ·’:ûWrŽÓo€>¡õiÅ Œ P(H-eJHÔàŒ™xçµú‚Ï› t8£‘ò—¹°£j )úl7ëÊ`F“Óƒö´7ÐG‘DÁÉãP—þ'¨Š²ë¶ø•^#Ø=þtÌo˜Ü­ö(p›-¾Y£]6”×›÷«ÿëg.I +g9qo“ÈV8ñ¦»Üþ¸Ú9þ’̘æ¿ð›nÿFBõqB’5¢n§y‹@PpÓƒ€Î,×6²Òëc¦ôz!€þÒÚYü~@ÿ©åWVµ¡NŽßµ^é sïWlÙý3sT…j‚0n•õªëŽò̬ôëߎUÚO‹À[ h¥ˆ¼U~d(ºÝ‘ZøÏµT-¯SªçµTÏ›­§¼æìº®ão`éÚu]íNìõ‘ñ±®Ï4ŒÙ33‚¦u/[b\ÿ,åÌùâ´ûû¯‰Êy¿JnÖ类Ìõ[í] +d¦&Úójsë¿§\Õ½ÜEu]%›× ¯ý[_þò4yøúzq·a Z»öu݈LDb%úo×c}!iÛ‘Uç1êM?]”·éÌý$%þRÕn“>éH?ž]šº(†_fjŸÛúX£™0¯ìÜþ3~l)ï1ïÔtî>‡èéóýöNëv.osÁ•Žoµ{ã–%=½Ó²Ï¡PÏ8ïže¢h»­Ñı̘ŸØ˜W‚]6õå<àxGÞØWî«©´Kš8ü‡ †j^²àúŒ'ʽ̻ÄÔ³7EhÂ=W/45à|´±¥ 'I>‰u²BÉ|7='kJ¿k¾‚"´êt¬¯Çû@,ÿúúç—DJD(8Mþækßÿýñï¯ÿ|×ï¢?õ[`\ø5™s¨LüõÅ/¿¾þ8é_ŠN=„çäÃ:L)ô8º*—?@hµ üà„@ˆ¹^kqU +a Ù`U%ÄV¤épûR<—6õrËW`OŽ» ­düe§ŠèVÒ°ôaj¸7'G3¤¶™ïÍêË·6 ÏޞǤp%©'_ÕÎ6²¢ìû-6J‘½aX8Ù S”šqÃÛºÛg¤µ­À[ã'ÏÐ jÓ錈ʴÉaLÅ2†€Õô#š(… G¦çmˆ…d¸ÖC4ƒ)v óúe`$Ì&aë!ÑõXÔ.?ñ¾Ñ¯V¼~˜Ÿ‘Chu”ìƒq²W^L`¡.Ÿ¤V#î@îí˜n ~|U>»¡3]ÌöyL›=µQúTsó&Àœ‘‹4áç—Þ¶¼_ÓÊŸ¬ØÞRM#:hòüsEôº‡“ìˆÉz~ÓA.p ðkF5¤¬X@àÄH¡QŽž|Æç„šBÔÓ§ó ƒ$ÈÍ ¶m;£µÅ¨€ 0Gè<¨Xã~ 3¢ûÕ°Ëg&g¶ÛvLØôÏ\V +A€Ú yÜÒchŸ”´“a?Ê„Âëø.v}ŽÄK<ÛÛk\ç[¯Óו‘7ˆ\ÆxV?>IÍDL—f6èç9x8«;ÖmÙlHcuŸÕî¥NHS©~g$ \Ë Øš²í Mü:¢‘°MaVZ̆ TùÄø +EÛ÷Y¹8÷MZxéÅð?´÷Ó¬Y¿ùów¦$ø˜ràÿD”M|R”oNå+Ç”û˜•‚ʯô%Œ1Þ&f>Y Ë»’%ßlW+g Í)|”¶Ë8Ó~Xšôtû¥‘"†¹ª;G}Õ„²g-&íÆe¡Ê¨Æa²ï”ñnx0íJ „/DÉö6ý¶º=ö›J“ ¶'Ï`f¾õì%êÜóv(X#%Aúà]ÃsÆìû%,9’h={Ô̸[l;´8ðÅ\–5Þa5ˆv¹L}‡ÈR¶Ùi×v2v_FxÇ뀰K,%8 +_ÕsBœvB£iPyœfÃÞàBÕkølntÝúx رb X+[«†H)S¡uDC›ì5ü%·¡¬!ÊnæÔÐ8›‰³Dª™h5²ÂUõÚ¥ª÷„»7&ŒS(†vHªÁŠúÜ/V ™Þ>WøqºTßûWó Ķ3‘ÉÀj3cÊ€sY|Rœ6©úP·Ÿ¹d¨`–,”­²ûºYÝý*`MZž ÙoC(#‘™jPŠ£Ò–yÅÒÄ6Þë 3ÝÅš­ ±Ç@€Z +ÃPßç"£Ÿ…MÍ@¿#ãa:¦tk¸4n]3fžšžE¼†€1nØj(’`÷âÞ Ò‚r5gaŽxäZýÏ9hŽÞ¶AºK9ÙPB­‹«Aß±ÎIÛ‡Q°Ý©­ßfÎ4?ì8eIì¸î]¥5`QËZ 5¯4–O|1Žo„ZmÉ#ø?ÑÓiIe<¡ÚÒM½§˜–+­ï2ž_v;ýÎTs¢öÍäþá<-²¸ìùú©$_¥s#uÂr½‡f‰»>ËöD|íÐ0˹ÐòÄòÕr¹ëæRX¿ÓVïÖ5R;2žå‚#‘æ;>Óâk åjûyUºIˆŸY‚d:á·ôf¡÷¿2à»Ïâ b ûwJïoN´qXUù7Z)úÈß^”¦®ã›+%Õ•`MQ¯ÇæKy9·¡Ç™WrO×cA%¤ô+NzžˆŠyú`ÿ¥c”DýV|¬°47¿ŽCð¨Ääêæm7£:Œ¿Q¬<Óp/@eBìжǨcÿî ÀÂt"¾;õn…ïÊ¡¸¶2Þ ºåáw§jüF›6ì*wZ£žþM/@»ùt7,L76´¥| P<`9%"¾§Ú W ˆ¸#OMn¡jò`So€Ð™«ýš`•êËÃpZ²öDT°«T5à}ZYL£ãp¨ +Ä?Âý-Yh#.-—· mÛ`€á¤¦æÕ%ªQ9¤oÀ%üøZÎ+ñLòYL¹Ç+wÙ† ߢÖ;Ý(.U™­æ+üC»óÄÒÇêÀ`i\`Q³#!É2kÁ‹á½×†H7Z}B?h#® g¦aZcî FÈ«ff­Ûw¹ÑÕLÙí®îÚ¹.eÇKgâíjp¨Êdɽëq||>öa|K'Nz àǹîI`;ä‹•è°ÕD÷}ªy~ä^zç¶Ý¬oKzâž·3W‘ãp¬ªÎ¶[_oßh—a£¨*¯¼]_%âz•ßaBì½6Z÷µ0©:+`ÍsI2äeõx<ÿ¾ýø(ÿ¾[nïN\–…±øÄ‚ñZmqžÉuHX‡ãúñ¼~\t¼k ‡µHúc‘ýxð†XPP™Þ}Èeµ¼«¶!)*dÌáañ]Ø*ãe.æûHìå·—åóæÄh­-ƒ ¿c1>âÂR¤èÁ«°¶ÄÌc/Þ/šF®…&oN±sü».T,õ%³)]~5ZéZÙ®)\ÖŽž³üøîÁI¶EEX[,±Ò»ï×Ïô\m<ÒS¡îâ¥wýŒ†3Î mAx«‰!i÷ÀhšÔ¶U‚ñZ˜“ЊlÐÉ’ÈÃ6<F+MB¤­‘”`6lgùžÆ:¥4è±0vDªsÅd¿èTsYÆ“Ào*\š8ñnFë€%‰ûÜ52™ëIX$Õß•tÿõnIâÊ=àvè. ÞÂ`” ØN/3¨Àg¶^(ü„•pÑÓ:!U–EºJ†KXâR³ }jƒþH=>d­³3eø —©ä{ŸT»È¼,ØK>‰B¶<'Hp¢0„ùWDļBÇ’ì|öm[,±†Ø ±à +ôòÐ$ðR¼zÒ´€ï‡lçniªäóWŒÚüÌ4ÇßžgT°Ž¼kH€-µ³ÁÐÚ¯’þxÔÕ%£÷|KÑ[Òï‚ ^—NGÞ•·Æ‰Ý¨¸:›„8LJFéb˜qŠÙ½DýÖÛ8 —ùòÀ=ÑjLvã #˜t4æöQ6…që•«™†gîZÖfkª ÑÐu%|šÑOSÄiËi +Ø9DT4{K+á|¦$¹5ËyÚÞ¾eœ:­(„*›Y¼¾›È¥‘Ÿ¥óJk'1 +ã8 £›-º>-![§gš-ÆòœË êHé:ì·Ké©yásÒðáÆ †’b£#ê{JCM`¤ÎEjZ:û…#*ë’T<’ËØ\B-Û$¦Ïö¬™{~Rý{aµ7"­hdZ²¦,’û€³ö´8,ÊSçÀ?­¶­¥‡Ëú‘ØÉ´€­P ®£®ek&çèîÓ]\ÒØhÆÐx•øÕ6Á£¯lJÍÈBpýÆg]/¦¡ÍæÅ&Ááñ‘Ó$feÏ—Ç%ýüdÆÓZcù„øáÂLz°ã&ÙŸÁÝÓOˆqÉaîªt™õkA¾PîH®\ۛˑ'ž.#ŒîÆXÖQ+Bl +4º…8oŒþ£ßÈåSìòžËÔpçÎò†eeNXëCÔó£¡vBïË(1¾¯!÷^_ãJHÊÔ-ÓVqUÇZ4ñ67‡·ÌeÚlDbø4ÇÅÌ~a†Ù;4NÛ²”,¨L¥ñ‹qŠ´®…•~àxÇ%Ú+r²ÅlÑXSËr`µ^Úi|™h ¼vGÓ|xëWó²$Ip`§Á2.‡ÏúíÇË’èùiÖ¥¾'ý´ÚxÚÍ¢æ×:Ìž-EÀ‚OqŠöwÐT>cHJ~a“g Á§&Hºž—¦`:­WÖ™zÀÛ3iÞ`¶L¸“f •k•}ŠÏ#Í£çþ~«%Áüt´Å_ÈtçÕ¢!íX3m(‘" *Q¬ ‘3]HÛ<­ûïîl8w¯mž,Oi·#.×"„¼ qG\Ç=í*yU> XvžfPàæþhM¿qË¿ŸÙ/¼ëX2p´MMEÓáv³Kz¼Âƒ“°—™½Çxo¿ÁÞl‡PþÀòŽçxJQÆ×ç™óõ󽂕V»Æj~²­÷ﶬšÙ+4„sqwêäÌõbÊü >)ÌšÁŽ¿!¢g库bT.4ª"=‚k!M3œ–Ñ §Þ\ûcHJ~›Q(F“—$>½±3Ícü±ãVêJuÿ´e}>‹<Ƈ*\‚(…Íãèé”ôAƧã;f³î‡±ÔV¶þÙÓã;e•Û÷rŸ#|¤–6ž;ž®nôŽ– á9f{zwí¼ö }l«Iû2( – à„›£Ž„àf³Ó]jžä’*‰"ÆÇC¹ñ+°uˆ3@ç}°ßk÷ëÑ&WTç.­2´¿×(^ 4C›šš@ƒÄJU +GÉ>®Ýˆ–™ƒGôLâ]ëzáMâÎlÒ:|{îØ£‘ögÙDˆã5]‡>±ë¡«+B8s$²E©¿ŒÂHÓjø@Ëþ:Ò_À°á1ýz:ŒÏqª×=¤PçgPk"ÏÜÍ£}žç?ÐÇÛWooîN¼ šàÃFŽyöÇ Ž›´SÂÇvá(€Ù ¾¸#}dÈb8ž¨ÇŸuPØ)KM `×_ý¹±« +UÕÍÀ{òêk-±aYiú¶?Q•`UíÕ8Ì dæ×»}{‰IÁoõ`±‚z +¤Åª0†˜üÄ‚.ìç‘ð4¢²]#¢…å4Â!Äe¢Þ×k‚/ž²V??J,e»Õ¶mz«½ÁãŒ#u’ŠWÍ®W<‘.PVÕ` Rú°EŸÁóZ—D¶ÆØÊwÆXãkó«£àìñ<%&p¿,Tßp ˜!„Z>¡"1äW²ûãÇ?üžTaŠm˜ê*ŽüúÏÿúñï¯úGÖ/ñ¸Î(yløø%¸þñ§é²€Î¯Ô¹Û(ݰÂàD%gÅ´!±']U\øøÒÎf|çXZìÚ?q@¥ÑgàAL¥hD,×¢@T˜À0>&Ao=Z_Žwë1¡f_óîïœ{½vÏ<,ík?HØ,é%êô¼ïgˆY‡;û­ëõ „éŸæ +$™= !Nô3ÞÄ­êÛºj®?NÚ~ñªÑº©=7늨‹nÒ™eâÁÓNºéÒ4rVô.F@ïÁàA®ë.$ޱLœÃ ¢Ý”B•1Ÿ¶áGšS¥þ\¾Ì4T &~YY«_ðà€L—:;ããÔW‹>œ¸Ì¥EoÙ\ïXÕ=hteñ}ÍEOлKÄt2ÍÂ7û¶½©X3)ü~£k»×€Wã®þí&QÐjþØ-¬[JÀkS=bôjß.¾\ +b±§ùf15®´ð'õ–ž¯¯©²Nt8'„Y’¦×ì(›î)𲮀+uÕÒ‹šoóòH¶\K<7ƒ*”ÁŸÚâÖ os“©ßx¯ÏèÀ˜7›G²Û¿Ä*ÓqeÚdënTñ×`¢ps¼€¤Ñž67õíQZ‘g túaÚ(FüÇ¿a÷¤wYoTøjU5`3ì'æ˜æôf[¯?•ññÔšfÆ +­i3úï¨L£:g¨lcÿFe’´šNòýÿeT–A®Í´ÔVŒkUX«F¯PÒ„Îö‡ÎZ‡Àúˆ+Úw!ƒf‰ú‚°êœÎðÁš6 +ØD,Ó0nú:m<:B—fkšÎðwá´c•™]ý¼ß» ¹—óøk¨[éIÖËDÔû}„674Õú1±cûŽƒ|»~ì©—RÙtèˆ]¨v=ˆçDKÝõ"±$œ sšÅª&0>Ñ–2_D]q•Ùòm³˜ƒÍ áôß“œ0—žâÚí1/ÎJødõöŸj¨Gb.&¬ Ï1í§›Ë­Ésõ¸7”MÁwÓ¢f߃µ’hÒ–ÙŠçpzçöË<þ }i¡ùf—}¢Æš,žØOªš‘¤Pë[Ž7pÖxŽ!#8À}ÂÚ/ï‚WÙ›{Bg×›.#Q·$¯Ôio •¸Â7A¡gÚð;û;#Ä-:úJð±3Æ\‰Bê%޷שCîÃèþåçï7ãW®€Ëç +‡Ý= ¥Ç±Ü“ùº¶s¢pê³l\œoj\þs²×N¢ Oãå¹9Vü®§'-É4/ù^5°¶xlܤxJLÒi=¼'-7¥ªBú˜+žÁ¯ŸæÎÜî +,ªwÅb]õË— 36BŒÛ‘L' +(AÿÂ"±)>ͼ¸¯»Úuœ{:,ëëAðhÍptâðú×ceé -’ºªÖÌx×4±ÜÞ´µnÊVƒÄ9þma+ú¡³Ý‘jÀŒ}¨ˆ.|s|Fm£Ã‰-“ì±Á=-[*G›<…½Ùü˜ÿÌ1ºçÿŠ:ÞžA®áaÁÑî<µYÜ<°oV\ø²0`°’CEÛtZþòʧ~éÜY«÷‹«š–¨9ãf@"6Ìm%ȸqã™5£&Á“þ¡Š$©¿P!™AõaI‘£çñÖÊË‘` g&C׎}]ø¡í¬WmcWRŽfüzÛÌÕñ\7ÌdyQøÀTH¦gæbºlV`ØhTK³)*K5xÍ &0âEµ<Ò;²¡¶”ŒýšŸq=ú +Ú­ÿ@{Œ›´§=v]vlUÜC?Lb%;ôx´iªFS^8×~zÛ(B+déºI’o{TŠ©ìk}Ó,r}~éˆöÞÓ0ÀªjõÈNœë %õ1ûºI,¢45rD¦&ö’¼ðÛµ Ò +$@éSÒÉeÃÞtw1 +C)–7»x¨…p‡4]»Æò|iqlûš+“oOjØW³¾½}Ô-•ÀQ¬4‡‘Öä8P¼»®DïÚÍ +~Cg…1­¨„ëâƈº Þ›õæ€ ÿ‹/¸øcµ.ëvLq%cTz{¡éèÅÕar¢¬?MF³âóêù¬¿Ééçÿ—LŠ#;'.vËæ/nÆ–ØÀ@ø`ñÉ0°Â[ÝÏy‘cª»çh80)ѱú³Y­bÅÉ%œ ôç +!!ç·îŽfë«coÔl ”Ûk‡ÀºTÅŒØê+‹Šr³Œ¸{ºSî­Êfû@9*@Ôª¦å…D\Åíêíõ©ïl©ëeG3)‡õ@dô¡ÒRç{ÖÃ:jÈVz8q`Ó›'²Q¢dÝfWb§ò +Ë,\m@ ­0B5ÅRBËÍû³æ† +tIa˜+þ­Ùbñ‰>£¶tÕ½´NK(p™Ö†ó_®Ë$G®\‹¡s¯ÂÈ‚úf=9õßÿô󊬂aÀ¶"啕—¥ÞÃ’ç„~êGÕ7÷Ð"ò§ëQhØ/ͱ‹Lê92fèÏßÊ©¦d VÎI:ùQÎâÄ¥"_ΆËz§#'´J»Â– Bµ+ŸŽJ «sâõÎÇäwv§³^]ëµ×°IËRz5Ç2Üçu›ÖÆèïÛM fK 1 ‡¹ßµŽöécÛ/J>õÛ:¾þoÒúÚ= (]6®Mèš‘QxÞ©„¯ý„´Ï†éJrÁÂôÄfxª–ò¯Í¶Ó¹i( qã dˆW/U^Yi9kQ'õ)ß|Å^vº¶§º«Jí±p&‘•“ÒR‡µÑìO¸Zˆü¶H!Ý19Õ§ÒmDC¯eY§ÎR4qÌ<¹ÜŒ¯Ì‹+i£~"ËÇK<ÎGlfsõ¬¤Gð„ô6õ3´üÓ#«;ZB³6Ë!D;c˜³$sÑòl~ÐÎ|BK3GÅ¡£]ó¼w-¯SëvHU÷Në5Œ5|ÃʪBBA$g­Å¸J Y‚‡æ²ÕÂb4#ÒjÐËÜHisíñ͉rLòžW…·ØäyÒsý/ꓸ]‚«1â—t¿Æ=&®+9å©Q#9™ªÞL—:îÅÕqlã>ï zú¦~8꣑£’Ø~@RßáqÇúŒ¨-,¡4‚ÓtN(,Sš¶w8Át¯`Ñ WݦFb›TKå-úª’U¦ïÉ„¡¾¾>>×%±Ý½=ã+æìiŸ#Ѱ™˜¾Úsš3$Õ÷¥Ýƒ]¯MçY4†ÈÌÞHR«ž/ÖS3¢ŒÒÖÞuhJÊB[ôpØã¯ù Öo?ÒkC»©€®3ÿŸÏÔ§O!Ⴏ¼Ehņ¥Ø¾z„F-†Sg#ÒEº5¾q_lýéª>8$Ç1aÍg’ÍZØ9sòÖ÷ŠdNÈ? icB-42‹½Ž9&©›^‰IfÚ”kÒâ>¨¥Í +ï Lød9´à §ÒžÛßg°ÿ´(eÇ~“® +ýæ+…t+Hßn7ví0 šWÛ–FBØÜš­ªd¦ +…b-(#Z-{§u¡ ª•¥±Óí¡€÷6³ó2ÑÎÆ{Š›ÈÐ8¿Xp%:!„j; \KtÌ20<Ñ´IAq/H‘Õª av¨›?Ýn;ƒZúŒ׬4÷M'N÷*?¬£¼b-+´«‚ÛŽNÈŠÛÐØá•xb°Wäâž8ð¹½E9.+¬á.ÏGc€sÅÌ9Úû-ñœ²"‚i(L«§åg‹¬‡Øt‡5‰À¢òü2ÖrOÎï…«¥½ª!"ؽyÏó;ýtdfCÐxÕ Ë.øSòºFT¨¬ó2ƒÅ·]¨.˜ $:Í®9W}R{о'äî sæ3·k%ºÅÜDQȹ♤$’ò¼š9½ä®ôOÝ̯:zfì,@ÀyÛÜ;ãvê‡mQâY/‡5ͪ\ÊK]¬'>c_!‡¿ª¬t8zì[¥½ÿý$y¡?¦/nÙ\Öøý·$~›OÙ6 ¿ôlQ–ô«ÖÒPÚö»²4í?¬ +0—°@õuH-x5Ïàã:Ñj4å"M¸¢As’¾ù­;i:v_–l«$ÕízÔ)ÃGõýËzÓ5ÜX›ô£hŽ.¿¤oÁÆ©¢ùxuÇt×Fmt1Ԓŧ‘ö¦ÆU«áëíÓ,Žl,s[W^­ë!ªC!c™…^Ž,Þzá4/Ž!«ÈŒ!B§¡ÁPг¸µº|Ý(hdüüÆitÂÃb…¦qÝ9¤„ÝÓ(òq +(௦˜VËéNˆÊ¡¬žª³¡-Ü%J¨*›ÜMƒ“`v®b8K°â¥7Ï€šöZuj++~:ýýKÿB²ðþæ$]c €æXÙcÃ|8A€ÍnÛ-…¦FWQZ›‹ê›êzŒÔÀ 0mYójü ½±ú~g»z¯8Ò-ÕáCÂäëwû—Æ ÷•Òº3¢h‘ìY£É1oP¦7žqBˆk†'îNGûªÕùÁ×-¸ÍÅCïß qb¢ud?¶$«Þoâ@› ´3=~w:©:¢øTŽv¥å—/å$Iîú©ÿ¶ðîúØÑÊzX`_W…X\©¦ÊUÛhçßa:mÇ£uäŽ,Ø–” à ê 8𸯹¢U<ÔPknS}}±@­÷nÏ®-, +Åh¶ª¡&d^Ú­Khš"Þ8Ñ·ý<{™0‡Debt1+"SQ¹Šý­l·!K"è¸*‚•MUÜÍ0=ž riÇùaë¿W¢T-;ýS«¤7°å¶zÜ©C¾Ûïú;‡­0Þ/¢qÞÛtèÕTÿ ‘——;öÔYíÝcc  #À@sãjÐÊHçwP@!ƨ¢c´®ŒmúÛÝߦ(ïõØ4Çl`¬áן!Iây*yX ôƒàS‚$–š~æAfŽ/2EªÒ/bœ)’ÖõLåÆZ!4óm~hK@è¶ŒbÌÓpLd·ÿnUÜ<}íÃ*(¿H–Vwk[±²ÙáQÛÍo ŽŽ(5—!+IJJŠpŸé^9%_^½]Ç#™U[ÓÕœê—üý‹¤p3TéˆqIT±åͼÃ3MüpžjG•ˆeiP¾L?a7øTå9Rÿƒ€/Û»é`¥Íƒñºfwp ’wçBè8vP£÷0êOr92ÿ‹÷P,íKïË|Ó·ÞÌ"÷Éì€xhµ%Õíè{Ÿˆl‚ÌMZ‰„O`ÎeJå”ÿ€·ÓM±Šñ Â.¥¬b‡Ö;Ìz§3Nl¹“ +4¶äô'‹z·Ðõà‘>X#˜2±–ÕâŒX5¼i>^—VŠA¾|ÂqIŒô¶ÃÞã•ИIBÐ D!ËM)ÒŠÚØ¸{ÒI3Äü[2Óm°ãEŠöÄ¡U“Sk%‚©*DUÞà)¶QF/Ø®L½ÂbËç1u 6\ûÅ>Ù§Ío_ºëÄ¡*êjHJC n,HáÆlmg»ZÁƒGìj¾¹ó˜@öñ·ƒ Ý.Üš ÇèÆ›Û–¿¥?ÐÔåouàþ1Ì–©ö½íè‰ï°¼€QÕk+‰ÅÅ8 /hgTVidî^Î!mºƒm€õßf÷ Ê›º†mºêôùÿÓ3gܽæb3â núÆ!—éX}I.'‹ï_7̽|™²BêH}'£‘½²ßï£$ÓOG5gK­\¥{æ]Ê ‡Ä…{µ¾‚#jæºLSÇ4«S6ÍÏ=d9È0èÓ'Ñlxþ²{1¨ ¼Éáªgb-¹Ïé¡ûÿ1¿lKÞà‚ž< uÆ3ø!Ñ%hÃOe{bÉC8b}8CJ×s9”0²ÎŠÕ`:ýÂÝj‡ó8­ÐÈ@j¥3´Bç©ÙÀp£='“¸%ÕÛc Ö«WØÈ0U¹?@òâBI8œuÀR*Ä¡auÉ›Á+>6u;”óZ‰`ukÜ!ÂC³ûo@“>3ç|“Ý !¨’{OÊCõŸÀöE$ú?ãe–bYrÑÿZEn ›˜‡eh úªídÇ,žTÐ DCgÅ»S„»¹ ÓˆØ&Fc‡?‚`¡m¶Lf‘¶2l¥®|½Þ§Çš‹ó’¢z+±µUCbX…nÑ]*ukÉL¼òHl˜Õ´ ™F8 +”J‰)u÷YÉ„‰?¤‡c­¢€'äÐkÞÊ` +mŸ Wcyüᣱ×ðÏè_ÒÙYKš»Em ×¹!às»˜Ñy-ëÆ$O«"Juw&È“Ì Š'Òæ1-·»Glâã«%,*¹:Zq?ò< ¨-\Iå)ä2ŸN^Ú4·é7¹I»´Ûí=qñ8dy+‡8 ½ì.R¿zÄñÆìù|ÝŽ°÷âMˆ 0§Ò¿3gp?íDˆ¸5r¥zö婼(§ª} êŒ@ËLé Ê©C-Óî ª’ž_xRða'ò" {5Ifnü¸Öƒ•X$\l,ü²NqÀ¢ëº‹4Žû¦y¿Ù™Öž–JžGµ/Üs¡Åe˜A=bwJDœóB9‰ ‹-wÒL¬^‡>ð„³íN&7ãjxÜbJÓbâ(™¨©AMlš©m$Å3ht¨}ôÕU*‰3(†‘,†ØÑ3öªV“ꢸJð"*â¨ê?qÖ9;4HÉÙìöýîúùãï?þ¦¼ÅDÁ{üŸùúןÿøñϯúáÉ¥l<À …”WÍøe*üÅë†À…aØQUèz¼ÌDשûÌ–¸NRÁ)kž^Çñ`ˆJ—–Mت­”|Ñ©¹‹¾PÎÃè›Ði_K¯'bì¶^;g÷­šAg›D™=ý«:7µø[¶>,>ã?/à³èÓ°¢iÍ¡uD·›hjquâ_Yh]S²sÜM¥05Ú¢¤(ÆÍ£$–‹Ó—6[½µø nú#ºPŸž™¿ap†M¹K@³Ä‘Øðã »Ô !½•h̖߱k¥TéEX™ÂB +Ï šëmú·[Œb9i'‰´ø@òßwz Û4cÛY`›¡EÕ a|œøu‰XTÀyíðw½ÅMšæÖèåoĶ!PCBZnbž¥©Ò‘Å{Ì’àrOO3ËmÛ%ÍBA虫b£ó=\B~ z%À­ü2lÑžžQþ厚aر¨¼•L¶ŒRö¦Q'ÃÌ0‡Ìˆ,3ÌÚIâ£å:˜äRØ-ÄJ +t*ðu¡»¨Yk¸ ²‡ê‡¤ÒYPiRc>š›R«½€yOš‹K³ÏŠ3ŒÖ±¿Ã +‡Ê¶6" ‘q\ì³&Ä(Zh«Z¨5üÑêŒRu¾øoÛ¾’»²ìD-ÕÙwc 8j3öq-*͹ŽaZ‡÷/»Ða© é48º–ŽjÅQÍAz£\ÕTr<̵#$v)[c\Gd@ˆ†TÓªR¼ä‚:¼}+2iÉ&+ÂÑǓةYÉdLchv=ÚëøRLtÙœ.4€É¨A:B0Q³Î Ä=N¯£ÆÅ1“x'þ|QÄJŠèÎC½Wʦv^C‚0Ù W{e3"$¦aäž›œ«I-ÑGÁy0ðÏæ7hpÄ +t8 Åð˜¨mÉYT”B83Qïéa‡Ó¥eî¹pèÙ´-ìÓ ƒÁ£¸Z¤wšñ¢^Á\ÖÉb«T­›äfˆQEv[ˆcû1%òrÉd¶ ‹­èn¦Ÿ— î¨)àíÝrüÑ%­HáÈAlìp8´©î¸F»'•eBm 3&˼ªé} +£¿*—°Y,–bá®â´_ko¶r#OB½ rÌ„˜uµš‡¾bL„çZ:ŽzU£Iß$„Á¦)3úý„ªckL6?ªAÝÆÔÏ¢L«ŽP»B¦­Ú˜”ubÖO‚ÍtBs0Që¹&,?¤”NC8Ê_|ü§t6ÌÇ1#»n»z^Â[¢ýÊE«: +ÒÀ¥_ãמéùT9Ðõª¶ 5²&JVÆÉѽǦJP°â ¼Œ[¹¦‚Š2À‰ËB ¼9™™‹ÍøÔpQwꔸM»ö‘Z-‡5 g¿ SW¸:g`nc[¿I:*Çñ'ðÎË=Âr kH&YÀ¾_Õ¶™y!1`“úKY9¸iGÍU2 %°‚6 «bý¶’ºî“è-¨hÆì#o÷uŒ [i"Ŭ&ˆ>cp&/׉Ÿk¸T¶d´ß<µÏ’© íQˆPq‚ÅöøÖ1Þ„—32ò5i õ™ðçŽNº¦f­gkð Ä¥NÛí#[¦ÞÍIÒÇ9!N¸î»ÇP1«Ñ´üÝè‚ø~©4%ÜpûnL[®+Ç‹°-êžh«yL*'tH$5F»`}NjÝq­Ëy€m»ÝW«rlvçŒGîÅ>¤‹*zAÎ-AfÅ8v"t˜ ^Ìа»iÆXvìå[õ\lèk8Z|‡ö! +®IñæÎ$u'Ýp!¯4A$e <þzr+WQ­Í¼¸5`­! ޅêÛúÑ(6¡e³3£3VàÚHk˜Ï|™ëjn¨y]LÓ¢7r³ì·Ç\rÑ~¥Gd~'¦ÿ7}ŠvæŠîÉí7ïfÚ½·| Éq¨FÿüpÁ&.±=•›Ç”ÒáöV3öª¼“› ä ;Û§(u'Ýôg±ëˆ9v³%Í68ûžoº7™fÙÔ’’ $­õDŸIŒq!¿º¯¤™…cîk5ø“´…~Ÿµ,; +Ø!ÞP#ý6UÚô˜‘öºý }ŒÑŒb"çA½ÄŸójÊÑÀ"9ƒg˜(Í©M56 K©ªÉoª_UÑRÍÀ—í\\‹é4öò&xÇiÙ„ +u¦æw» +•«r]Ÿ¾†YÇ1r¶i²øÉmæt´½Îø(Ã6…‘ÖÒ0ÃÒœ,»y¬z9-tzÄ +™öBà½ZHT EŠÀYÔ„ÐýØâ¢ù„P€_ÅЫ+“9_ ›ëíù­+ƒÌadÏ t^DílϦíUgÀDÕèn†É>ÂÿQ!•£ ù¬]ikOb$K[÷»mñzL&8o2§ð¸í/aUëÅ7¥"Ë1ÈSj瘖¡˜#ãt<ÒSbô±RÝOˆ±|Æ( ±{fÆv F ~ÝäîNð¡mïg}¶S«X¨õ'$õÈJÓ¶uÇY¨¹iû&{º*jt‹Xw®Âº5Z]¢s:(ðçÿˆ¼lk¬)Ñ‹!‚ÿÒ&eìO±~z_CHLfc6Ä“ùXó«X…Ytÿ‰u§»$v‹5ÎD@ŽB*¸€ ½š=åœv–÷y`_=Æ$f¹žã´uÏH;6ÅAN(Â}÷Ò(WGÆ›‚Ó^‹(BKé´\p’JXíg¥™aч]è­#9u¡?†é~S.u,ÚN….´ì=VÓþoÛб\ûݎ˧PkÙÔ’™“Äj›«qÕ;8­N¼3+Ó2áç<¡*×É,;ê£ßXÍ…gÀ›Œw;â÷µ·ÀîZ÷ŽÅ_À0ÿS)kŒÞ÷']e,ágj¯å]ïŸ^S^ýp|y_ưZÎb n¯ïî}íµKÉõs½b¤´ºü• ÏhŸ¨cûîÆÐãmŸ^³ÂÞ$!©Ó‰íßT—=².µCó; +†àÿŸ˜z!c Š柢%¹/è”û|v·í½¥¥ohÈ.‚øíd‰kö‹sC0Ŷ·ïè0êLå¢-Ž*¢±áLÔ{Ý Vj´舞­ï_Å›•â•“Ëî6Gíoäüù! °;ÑW­ã½bp\¢˜Îíæcèž_ΚL·îà ¯¸‚. "ù%õÁãyÿ®íE>jEß>—å–Ó6KÏý™ëT½ï~ÕнÙûM(–Ö„ŽvBçÝ¥ãé_å7]OîI.L®tÌ +únN¶•k–f°*ÅóE¬¹£˜P¯a¼uèbؾ2”OCÒ!ƒT+&®ãdÊØ ¯ÝsÝ‚Ë68ŽNÍM-¿ñ2:†i‚+ »ä*Ï>5Þ% pª†¶‘åÚD `žìDAûAwtÕ/TúmáÇàÓp1Ó¦ý‹ª­øl¦‰©ö+§¹QtÑrð„ä¡&³¦Iچêä@7pq¬Å+7ûÚö‘Í}BP¡Zåc¾iØ-ÕÎìÇFx£8d©7!nUÛ@z€‡ù¢cdPôpRa]˜‡T¾Ý½&#Ù¡‹%ìÑÕ¿Ó éáŽC +†H5Ìx*®sqÔ@0&Á'‰- »¨üðø+g´,½GG!¦;ä¾=‘þˆÀ”OâšÛZåé‰5¨ŒÄïj+ù¶[?Ž›ñÒš¹Õ+o¬9¼ô<°SãË;¾fÿªS\ô˜åþßF·›òM.œ N[$5†’2cŒd©nÞº-‡Uù4r„Y¢¡ §!Uóû†-@-¹£Ð`)'q9µ¿âÛ¬¬'ó ûx¿è'×Á2þ’–Šè†ùîz ÈÕÓ)3p\ÇõxÎúf_Vy0EÙíŒ}Õö"èl^Yå(§‘2(™õSOݼ£þœÑOÖ('k¶Ù1¢f½s½ eÚ+“ÌHöÊC£‘T‹¾#¤J ÙvÞñUaLÛ~)íñÿŸ±/41WèÙkŸW?3š£ÖH©Ö‘¶Ô¢,ª›c’Y)ŽÑ Ô*~-×;á •¸Ã—¬Ÿ×8†‡ãzmÉÔò»NGXáF¾,Aæ#lêªGäT¸»°ñKÌÌe‡Ð&Ø¢uj>ãŸ4°G%i󿜔< +ÿ"׊*Ý$;Ÿ%=(¦4ïZPjJ älz³´£µÜÏÂùÏè!LÞ)M¥Î•jM¢ji†~Òr¨>¢v$+Ä5>\)$ÙïG;”•öë&èl0M1½¶A^µ@7¨¢Uõ§‡á«ö*#çþD)8mC¦ª£@ïY¥¹?4Ëz®XÕt;Í!E’4-vZÏ« Qñ¿¸lGÈåYÙ¼ÖÌmפmÄá¡ÞóB½hå³heŒDšŒê†f7태²£™6U°Èí©7Ö€p=QíyžžÝY”¡Ž~z¬k÷%ê2o¢j_ýžÝ^$Ì:u’h^Y|dR„Ö^í™ÅàÈy“2Ê}…ðªu¥PÊó’•P£'g%bç¯ÎDá1þûù-ÛSqÖU=.o™ÏcaÊb\>‰ä*ÿ4üuÈdŒøP?-ççEòŽlÐUÔX¾8¤ G‰ÅŸÙ¨Ô0²(fúÀ¥?aÉ©¾Õ篴ÍB'¬‡0Š~ªÒJÔ¹Í + 7g†f~”ÐÓ7‚øbµˆ”Öy2C\UìØÂ·óúÞÂrôÂBÌ wúÆœ¬:VãzDéhã Xbx9lJPÐrÛ  h]ãI^¡X¢éFOrÞ`.ýßã}ŒwÊ·‡׬ÿÞËìûÿ¨à?þüñûÿýöë/úóÆi,u +endstream endobj 82 0 obj <> endobj 95 0 obj [/ICCBased 49 0 R] endobj 10 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 300.0 300.0]/Type/Page>> endobj 11 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 300.0 300.0]/Type/Page>> endobj 12 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 300.0 300.0]/Type/Page>> endobj 13 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 300.0 300.0]/Type/Page>> endobj 14 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 300.0 300.0]/Type/Page>> endobj 104 0 obj <>stream +H‰ì—Mnä6…÷:/Ð4É"‹äv:AV“ ð"0ò³ð˜x‘ëçU%±Õ3= KÁp«YMñç±¾§ÒÓ/W÷ôñ܇®nù¼GÁþ/òñÏïËoîïåéúÜË› ¾TÂg-ò™29÷ö‚ŸÂϾ-Ÿ]tÑ¥Ì>qf—(ûØCw/ŸùéÓrÁ/…ñõ£§ÔÜ¥øPóÞ”+¹—eôXõZáš|nÏ]âäC‘j÷•‹»äî;W÷:Eª®‘Ö|Î »ëžz–H¯>Éð|O‰1rœ;ÅXŽ#í¡î9X¯|,4–Ô·®>yî˜8bMš(Å9€}fÝÈ*žu§-£¾Ás©zô±Õµ-w`z¯=R€Hµn#lí}’=Ô| +²hŒA2j"Ÿ*iÒy ãøö>1ö•d´bkmQ¦”›»äPŠ‘4¸ÎâáöÌMCÌ8gÙmÁ‚¢ ÊÕ÷ ª|!ž›¯:1"U'äî[‰{DdSœ{5,G:'tžšýLÁ©Å“}éMw|&¶Î•ö€ÜÄ„]ǹOíf -2M¶ÇpnÈTÍvȠׂäcíA!‘ܺ/8ÝÎ@ÄÒ¹àìÊ!œx®v›Ø¹M‡&Iþ +äÈfï‘ç/F™k ‰”,|$BÒIª%a¦= i4ËÔ'fŸ5c1JHy +ˆ˜VnÚBäK”ÖQ IŽiši${±§ç>s蟫¤’¨Žlâ”fh”öÙ˜…4ãØ0JÁ·¬k×lîM®˜­i¶3+Q”Í—…õ„×6`Kš™XnÞšÃáÖ¶ øbSÿ„×.,¿ší^Ÿá§ò瞯?Ÿ{Zìi±§Åžû?Xì_Ë3LÃçŽj–¡Vδ¦ŒÑ›I˜ÖÓv£ÅÏTÔ"f'™¦8rJ¸à<аÝzsp:flWíººLº²W]bh.'ÔØ=„ƒ‡ û¢µ‚J«_eß׈µ&qÆ13 f2¨h´6 È—9sö$šË‚äð耄ë°ê½ »¦Šñc±œ›>J:²+MO'¼à<ÿu§T¥²,›4jò”Œ¢‘<(v.*’b•ŠÎÄüT'ÄU(õ7QJ-²N#m¨¥;Ëæ÷Ñ;*Xu"K·ç +NÎZ²Dû¦j‰%ˆ\NÄ*âc¤¬«ZZ2¬ÑK§UÁ’žÙðBë¡‚å9Àên¯jGµ“SÅd *O¹uÊõn¹Žù•ÅÐÀžMTQY=&0ù@`¼EÐ6T¶w˜o,7 ¬+㨴è{í¡Yú|]ŸcE)­‘yP¨0®wÀåoÇpüUàúpM¥0ä²Ö +\5àè¸8€c.mÀñ8;°°óÅÍ[àÞeO§V´Z+,yC¹Pä3aœC…U +zàe*὆§7Y•PòTµ#CÓf/dhŠ€ª[s*£ìCU«NEÔ¶h–µ8„çªfÑpÌBƒ}‘sž.8F£3 ³öŒî¢[]Û¢È9EDSÏ<}êa²Mè&Sˆˆyp‰5i¯=ßâm™uêõ@¯£›A¬Z6+/)5M†o€ÙѨF Õº¡i¨*ê÷—M²‹9¾ÊUéPÍÐ$·ª¶Š6ŠRkŽ’Ô8ÍnX¾A†c]”̶^—A¦*œaúSqý›[ Mµ¸Éúïíìë¡Xwµ<Þaá‹(N›9•ˆt±®UÄ ˆ|à°¹QS ë ‡Ùh++‡eã0¯Æ9¤oqXsøÝžuªô½N•RôŽKê­ákwðµ_ÛŠŠ>º£/¹µ¨8â·–ìÌÇøÞàG_Â/ tÚJ_YÛ¾x€úÔ¡ØÃck z<ÐãÇ>uJõ@*Ë«?^.ÿ 0<\²Í +endstream endobj 105 0 obj <> endobj 106 0 obj [/ICCBased 49 0 R] endobj 102 0 obj <>stream +H‰ì—ËŽ\5†÷ý~ã¸lWÙÞÒ V¡Yð#.‹€²àõùÿßg:“É(„›V”N\Ç—ªÏuó›¯éÍÛkIß|{M—÷—’ZÙþüõËåçôçåÍõ¡¤Ç©d ¿Ãù[{KéÃ#>Ï¿}¸¼O– +þXªµç=ÒŒÜÝjzüãÂ/üõì}¦£çˆ´ò+†ÍJçh¦ÇËa5·2ô­åðÉQà ri–F^Á™¾r‡Fn¹—šÞ|÷Üg§À<ÏÕ’ÙÊ%š$5Û HF6ÖS]Ãæ°:ǨÉjÁ¡Ž#J6.‡=!› S[fƒsG†=nTgäÑ3ô? –k<Œã™-Îùœ^-WhoͲ7Xбq~l˜q@‰R'Æ ¬µ",YÓ„½kÒ˜\)X1 Çviu³‘ó…&ëçÌ :N˜š@k*[—µ6¡™›Dž—Sq†‡4­Ö09¶-½H5k‘k YkÁ{ë5{™p§­ çW-p˜×qnÖ¹g_yÍmn3£ÇÃwxw¾íçžQ³6r'#¢J3hÓyŸKç,Ë0}úŽk$‡¶]¤9hjnOHà>†qiû„€Æ+ã^8\0³ŸC©Ä§c[Á/]x)‡ûÙžO‰ÓïN'éÙ¹1.œX½;­‡Ÿ"ÝöXÆ=zÔgã`c‡Ð–l†Z[^C6!†qÁdÚÉ*õ–g_'£‚‰½ &úS\­NAñsµrE pGüá©£žãO­¸„'!6]ûÿ¶¨km®08ßæµãßâJ +&0…Q³‡ÂP¼ ’ÊÁŒÒ”y/¿^~Úéêú€<Ä?éáúÃ=5ÝSÓ=5ÝSÓÿšš~¿< 9}ÌDÿàåÚ‚?4ÄÊ-ÁM÷ åGA̲cnâ¾:H \˜×¬n +á$‚[[A-À™‘‡õL"¥ Šº¼]Mû¡!FñíÇž*]ÌŽÊ#ÁÏàñHm1qþ¨…)ðg¼Ã©±…a4bG.+Ȳpe;cט#Õ”pPÞSAÿ€f¸:Öx–ÈמּŽÕKÏBö€Ø£2;6”‡®ƒ¼< 9‘W$âBn>È«²Ld7¥Cp’—€a=y)ºDl&d$Û•±l¦Í‹¸È`Ó:„ËÓRüÂ…u›×!` +½Mì ²! +'´CÔžÊeaÊ'·¶Ó#ÈQ"vœfÌdd‡ÝˆN + Øþš›ÝÁ}5¸ísHtX†ŽFS/ÂgD§)“cWäqP$ì‚ {³ú¢C’6žÔ˜“ƒE“*ÏÅ Dg|ð3Ò0³Z¾»,9«-Ëyd¦Ü ÷샄†CeõAŽŒATeH”°kUu~ °ÔÉÒÃòºÈ5yñ\ÎÀ,hšqÛÃÐÙQ«Œý‹ºÀÓd¶Šì+>z >£þîàþ¸—Y¯v6Ô´Lì%1‰¡ÜÉzÐÃt\a“/lûøwfáßéõ¸¡Óö‚'ÉR»xˆßH¡¾”ˆ&qT¥åþßIî ºžD.d?âFàÔëì1¹©Õ9¹Ý°ßÕ?Õcj½{C0«IÈz:m±×kê׿ñú¬cs$[$q4!}=:b²&òtà+YÀP¼Ð0S;÷Æh­ ¥¦W4­39³KeÚg³ª@èzD:nÌB—‚šÐAÝÇ씽GSeaHàï‹u¨øœ2Þ ¤xÛ,½OØŸëm‹º¦çW=k ‡zÔ6ù,\â•À^§3¯èúøÂ U„Æ»€æj‰Ùç¿Ú³Ýi}‘Ök]ÛâKq@RŸ÷ ÆX2¨%f @ëJ´NmEMKr£º7r‡Ð5-)!É OÊ &¾ª^·ó +|ƒBïÜ‘üF=O„·’Øu½ü¦ŠÁƒ€ìvÞLOìÁkŒc_»C!¾šDJxžÄ®%ö3é nvÇö•Øž:6nÂ+ZÈ[E§Ú+¸-ô®Ëíž±7µ §;ÐàCš j¦£«Ý0ݼʾè-gh~o»ny„šß$mìø;€Ä§šû\›ãdÁÉŠ0æ}ÚŽ^F±ñºvøÎÞN–®øYO˜l“À\»q.¶àÙÃOž³oÇXz§±&ðö…”EÊ·7yµg®hŸ6nw~ÿßg9p"˜+”ˆÏkF0ߊ]°h8ƒHì:«F?ûª­ºá¾9¤ÛÉŽ ÔžÝØQìˆ.¢›;ˆŒ¬šÌºuV>®D¯ñ3n¢‡Ûܹ‚ìÚØ¥Ã#Æ¡ç× ŽÜ|ìʱة“Ú®“ˉlÇ0ž]âÕY5|Nú‹#®_Í}w\_Ƶý뻷ׄþ`È~…ñ +endstream endobj 103 0 obj <> endobj 107 0 obj [/ICCBased 49 0 R] endobj 100 0 obj <>stream +H‰ì—ÉŽä6 †ï~ +½€Õ"©õ:• §Iô!PÈrè`Ò‡¼~~RòRÕÕU“s2]¶hY"?ñ§¥§ŸNîéã)¸ßÜôe +NBÿŸõçÏ_§_ÜçééôÜùÕŸŠà·$ýå(νžñø<þýuúâÈü‘㈮$ÅQ>4wþ4é£OÓ}ʌ۹úHŒy|àêææsŽn.ž*zOs‰˜ /†—Õ|æ¬íJx#;bK1Cñ\ÈQñ•ÛÎPàKf/)¹B¾Ì\ñ ¢‰![Y›¸„ZÔ…Å€çY»'²¸àü >K-tnÙshËS + Äe}wm¯ƒ/Ì.unq˜oÃÌ XjSßtünØ¢kÕgƒøi›BöDi´6„„á,Ô,ã² +w +z`y¾JÒ[õ4±e#„#úb!-Ô¥MºÔ¶v›)õU]^ŸYñð6øbЗÆÔ[ó­è§¤£,î¼ ý¥%ÆaÚ‡-¢Fb°»aQG›á3þÈ·FÈ–¶¬˜vIÈ‚¸3è ç¶-¢Ù’¯Q—i@h†ä‘%ymkRiÅ­‡%YÙ°Öi\©³Yk›F_鉮³•Üg–-âEOo-º6’u5 ‰. Ð¥»,PØ­•í‰fBÝ–m. ²zõwƒý§ß¦Ÿ{½9=£èŸ{>ýxÔ–£¶µå¨-ÿ­¶ü1=£ºl¥„0$iŽCñEbÛJ‰º•+n…É>< +M‹ õ—[r@£Þ(!ý‚p±7eQ4ÞkÎxA©¬Nj¼âjx™Œ—N©À ÆkßAqÑÞ\©F¨†K.²ë€õ•°Þ/YÅKÁÔïH0ß• w –K Ö;¤¡@ZXG³Ë/©ü û.¿Ú¥“¯å—Wù¥.?¹–_¾–_¾–_ºY­@wÝ®Oðˆ± Ð˜¯7ÔV‡ÚÊP›t%¥®6éjcz£¶v©¶JCmÙ-õ|)ç&·:šÆŠMnÑR>¯µÜPÉjjã¡¶<Ô¦Ub롨xoP¹Õ!·êæÒê&¨žSØ’aw³ÖéŠí™{=Þ”Œà1,qÆ6“Ó!{ÁÑi\´YPuák(d_Ú˜0©¤ø’‹Ø`F#–,õcóeœPš•M‰Ë>áîƒñ6ƒY—@/Ô÷ˆdÛ`@&l[«ˆ5јê1Ä«îNH‚òrÓ™“`܇¨#ÛIóD­SˆîÑ}îѼnü58l¦qa;ÖèµíRŽ.7Zµ‡Ô®kZÕsECšQQí*r󸱾`œS©WÌ™C+2%¦ šL¥«Äð °q<•’²Ÿq~ÄÉÆ­hg£Ú߰êñRã[¥ XrØW÷Ó‘ÓψÙÎÅÁ Ìì«`Ð#:§–eÆ^J[ž0óÍâv{Lì:ËX«`ã÷•)÷”Y¯”ÿWeÖKeÆo¥Ìv£žÄþ ±7Y–Åç’þ4óiÆûÒlÒ¤o«Mº«M¹WÍf_ìgÚ÷O—¿TÊ +endstream endobj 101 0 obj <> endobj 108 0 obj [/ICCBased 49 0 R] endobj 98 0 obj <>stream +H‰ì—ÛŠd¹Eßó+ô©V„B·×)ƒÁ`Sþ€Äãbèn°ìß÷Þ¡“™G§nó຦ºBG׸ìXõé¯áÓŸRøéáôéá1…Ë·bi?[áOµ·Ë×Ó§?âó?¿þ$$ü'¡X:ZÕ8²I¸|9ñË—ÓÙb×$¦<ÂçS‹’,”K®0E0=‡R¢aõçÓÓéçÓßæñØ—ÿ…LJ¿œ$ü‚_ÿ~ƒ3¹†'?âd ÿ…õËrL‚íƒ4‰}¤Ý1¢±·Î[å9Ü`¹^ÍMƒTüRÄ^\מ/Ë1õTƒ”Môåã^X&±(^+%Eixü¯¼¥8jéAìèÄwÖuÜNž\bÖ_^ן­S“ˆ á¢*±Ö¶­Ég‰V¦³æh/1å€tljŠ=ÝsE1Y#ö<ãÜP©±eæ`C©ÕÅ ¥·cïå¹dDÁW©«rª`Á+Ëøž¬ˆ“«÷_{šs +Á2\·´ãº×CÉhAê玂*/¿.¿°®ÇÑ*“~(º7Ïçœæÿgþø÷?N_wûÕŠÔ,Ø.!G­î®®±×ŒsbF."|%)xg4ä,,åׂÓh$Å'TU—ÓˆE¦6_÷…™P 0 +pDKz5|Çi3!-(MlŒJ€<4¿é铱¯äY®Ê baæésàL©þ;®q†ƒ«•p†¶–æëáqA|q¯ä ŠË·sÁ<<¬ÔBS +Óxž¶™\ÎíÇý»Æl¾™yÆ¥èsŽÍ*¯â‰Ìø§¦ÂðãõÖ뫸”//(´ØàS<ïJÍè¦Ñ<>à~ëÃüÝ ¾¢)uoN¯Þ Õî&ä9Þ‹Ç3Ëψ ½Æ°Â9œNÕ +È¥Ìì;gäwEÕÂiXœáÔ„°k4ÍwóvÖ6 ¬ñáß³b3„"}xÚeF`äMi¹{H± rÝÌ#ÔàGå}}FÚ¤Ôƒ¢»@¦i +¶ã׋ß«q™1üê¸>àÔÁw£0†÷.^޾œ° +ÊŽ­SÒ™ý¢°Hf²À{ˆ>¯Þ±Y‡öUÞ+ ñ2³`¶6s"‰Ý¸¹Î‡D6œÝàs6=Ô) -ç^N8p`KáñôÈf#hÙ(šøEQ¥ð(Zm¼±¹Ë4{Í öDÛLF:£ëAh.œ;Šû£z—cý ¿• v¸$ÁÛy †L4v›^ºWñºP¸Õ +Ò_CCÍÃOÈ+`@AÐk§ß!ûD€Œùܔ̚ÜDMʬø¦ðr‚{17cÉ×–FË›ì‰~e†ƒª·;¦‡ Yw §Èu wwäuGÄ« ñâ4ƒœµAkÕ/“f¦hH5^¶\Ó}TóÇTÛ2Î2Ô|€¯®îcE {: µYèÃ2<Å1ÏJ™NöDBwOØÚ£0Š í&̶(ž¬ß-Ä4­Õkྮ½¥Èu`Ë!n8— Æ¨9à’€dÊP”ê²6P´hd +¡  xpaÚSáæ}K1‡™Üx³¨«Ì Ð'ͻ˔C PAð£û“å8b϶íðjF Ķºµ"^¢]'J0nÙçT->ÂÀVŸC-œq·¹&\ÓÂóeØ&þÌ—6Kr&×nd¦ßu‘ëönÏ™·gw¢†äJæêí™òó2­§b¿J¯n»ÖãÍììÓÈÙºÞQ þ]éÎG‰šMàS™åÏ.ÊXôYÁ°…PéÔì;£¸é#la-þ—Ýý.IàéGa§Šž¾+xú^ˆàéƒ >˜àƒ >˜à·e‚Ud>CvÁw<@-`¦½Êzà]ø@ö|ßâÛóAÛóA[ù ½Ê¯Ð­t°Âá à èÀÞ¡ƒþØJ²§ï”;<ȯâÁì z„}Z[à µp`y…9À"µÒíé`aƒ¬\PV.Ð;ÌÖ¬ïPÁ +m…‚¼B›Ð Ê‚¶bÞ±€/80˜ -LPV&¨G&ho1AÛ1A¾#ö¯ØâÓÞAEÞÜñZ7 Pzä=ïx5e¶ð€¡H¨máæÄrÚóê~m‚±Á8î@ ÈG #Èz;¼DŽòôí h+Øôùú0CÊnߺ²ì€`,@À%; ˜[àß;$øtÂlÚx åðO²ä=@Ó< G°öŒôèdϽ=ãyÆò.èžô ïð@Yy /@`{ hºAYy .8°Ò€^q`ªÂ (7x:ýü{mÿO? <ý(ðô}AÀÓ÷O ð ð¿%¬ó¢ó¸€P$MØ·GÔfcØ9˜Ü9f‡uG`&ƒŒ²™Qćã>æ,®,Ó•B56¬æ£ñ‚êÜÙ.žlÜþ(-gbCu[±Ó ]Ä·iõû¦­óL—âØêM#å>@³é´MmÚ+Ú*Þ¼,“:X*‰ŒSÍãÁôNìH©›…é Á[àöÎ@‡g»d¦¢?¼¸œ$³-`Sä/‡Å‚Œ09 YnÛ"*ï2'3»9àiÆÞ]¶z;©êt|ÏeÎiÛÆÌºeÀî'ù[i›òÊ!s(ù>…)X¤•EªB#vâÊm–Z™ñ^:Ûßy@ mVGà ú7f1ójXÑoyŽ$VàÂæ{CâpÈ=Ù„vvšÃ€Ö6èšRüpÖ4eí\H“µšl–“· Ð ÙÆž„¥:-Mçá498Ý@l‹+4ï9 T=kÓ65“<ì¬8ã½:1AŒ>aƼ.…1-iÈÒ.õ:…Ìø8Ë.þP<•Ò™Èĵê’{5/§ª“H¶†¶)E +×u +õÚ·#I›ä3‰œ¸QWL[OMÔ>¹JôfcÈaï:Cgãr Y]ü=ƒ¥,™pl[±£Vá6…2Õa&åÙŠM}:S¬yF58M2¯ÎÊËNŽÂJ¦31žæèkŠ P½­áFtÆ™'nSLh{Âpd°=`¤°3²ÅÙ\Ñrž63ŒÊç#T(ú ©FÎüçpÉÆûW<[|máØÚAœCzµ –Uiò$¢Òæ 4iínq€:kÿ½B ïamNjŠ)T¯yrÙIâNV¥†±‡b¢¥Fð”•I£îøûø3Ö&êIùG‹äƒðòNüû„CmÁ²‚V²_×ÁÔ„'˜ÃJ‰~Rx¯½b^hpüm¼à¼6‹c-Ü;.þ´oÁÃ’¹xÒ›V Ç"xb(¼Ícý0£¿~Ÿ&tB¢Ës¯"÷®HoýuÙRb÷ˆö?WlV|¦ûiYçf#> endobj 109 0 obj [/ICCBased 49 0 R] endobj 96 0 obj <>stream +H‰ÜU[j1 ý÷*´ëJòû7ÓP(¤!Ü.`èƒBéýÈö+ÍØžK’ $˜1>’äƒdÏé~ÓÝBpóe÷ìퟷéßO÷žÜi9¬ L%è\’ÍÀeU÷Wuÿ¾¸g`  ¶VÔŠY(ÃúèÌóè$c©¶-VŒµç‚±´ ÕÏQ`uÃ"VŠÐy^*Š&‹ÕùÍ3°ßhuÒ&žq§¥'î|ÚÆê~¹‡]îr6:à¼|w/ºü«ß7ø:ÿ¸³*}G ·ŒíJH‰˜šØž’)©˜j8°,ÍRNK(Ði> ±™¾Ò“™o“¼[üÎËï3ìaê™G€ëš}%oª’Æ$„¥p:Ôè9*nEHZqÏ©a¶V`ãÄÃ`y3Ö|e²fh”FˆŽ¨·™­¹aÈz@!¬5‚;óŒÝ¡nÏHÚŽÓ ½[—­åí})˜’”„œ[¼£úX‹ÌHmOÞc̬.hGÔõ +·0X;°”ûÊw{@.&VXz¸´a1ÅÃK“u‚õ#}Áèõ ötìE¸½Ó_Õƒû/À`ïHd +endstream endobj 97 0 obj <> endobj 110 0 obj [/ICCBased 49 0 R] endobj 6 0 obj [5 0 R] endobj 111 0 obj <> endobj xref +0 112 +0000000000 65535 f +0000000016 00000 n +0000000144 00000 n +0000040248 00000 n +0000000000 00000 f +0000047778 00000 n +0000351863 00000 n +0000040312 00000 n +0000040405 00000 n +0000040498 00000 n +0000340635 00000 n +0000340997 00000 n +0000341359 00000 n +0000341724 00000 n +0000342089 00000 n +0000272326 00000 n +0000272683 00000 n +0000273040 00000 n +0000273399 00000 n +0000273762 00000 n +0000040598 00000 n +0000040961 00000 n +0000041324 00000 n +0000041687 00000 n +0000042084 00000 n +0000042480 00000 n +0000270117 00000 n +0000272229 00000 n +0000048957 00000 n +0000044891 00000 n +0000048079 00000 n +0000267636 00000 n +0000270020 00000 n +0000266186 00000 n +0000267539 00000 n +0000263973 00000 n +0000265181 00000 n +0000265590 00000 n +0000265243 00000 n +0000260465 00000 n +0000262970 00000 n +0000263377 00000 n +0000263032 00000 n +0000042877 00000 n +0000044686 00000 n +0000047964 00000 n +0000044748 00000 n +0000260430 00000 n +0000044926 00000 n +0000045129 00000 n +0000045021 00000 n +0000047848 00000 n +0000047879 00000 n +0000048192 00000 n +0000048245 00000 n +0000048561 00000 n +0000048638 00000 n +0000048785 00000 n +0000048880 00000 n +0000049031 00000 n +0000049271 00000 n +0000050351 00000 n +0000054914 00000 n +0000120503 00000 n +0000186092 00000 n +0000251681 00000 n +0000263938 00000 n +0000263175 00000 n +0000263270 00000 n +0000263492 00000 n +0000263545 00000 n +0000263861 00000 n +0000266151 00000 n +0000265386 00000 n +0000265481 00000 n +0000265705 00000 n +0000265758 00000 n +0000266074 00000 n +0000267601 00000 n +0000270082 00000 n +0000272291 00000 n +0000304468 00000 n +0000340538 00000 n +0000280322 00000 n +0000304371 00000 n +0000278888 00000 n +0000280225 00000 n +0000276537 00000 n +0000278791 00000 n +0000274124 00000 n +0000276440 00000 n +0000276502 00000 n +0000278853 00000 n +0000280287 00000 n +0000304433 00000 n +0000340600 00000 n +0000351265 00000 n +0000351764 00000 n +0000347535 00000 n +0000351166 00000 n +0000346036 00000 n +0000347435 00000 n +0000344070 00000 n +0000345936 00000 n +0000342454 00000 n +0000343970 00000 n +0000344034 00000 n +0000346000 00000 n +0000347499 00000 n +0000351229 00000 n +0000351827 00000 n +0000351886 00000 n +trailer +<<7D5557C01281CD4D9D99656AB0619DA4>]>> +startxref +352083 +%%EOF diff --git a/files/images/firmware/Tir_off.png b/files/images/firmware/Tir_off.png new file mode 100644 index 0000000000000000000000000000000000000000..94af2e23abfb6c4ab19ef60e75fc4937d54ed9e4 Binary files /dev/null and b/files/images/firmware/Tir_off.png differ diff --git a/files/images/firmware/Tir_on.png b/files/images/firmware/Tir_on.png new file mode 100644 index 0000000000000000000000000000000000000000..884e4a59af7bcc6217e7d306d343bcc21f968767 Binary files /dev/null and b/files/images/firmware/Tir_on.png differ diff --git a/files/images/firmware/X8.png b/files/images/firmware/X8.png new file mode 100644 index 0000000000000000000000000000000000000000..5ad68cf0e4321bd72fea016866ac16c069dbae9f Binary files /dev/null and b/files/images/firmware/X8.png differ diff --git a/files/images/firmware/X8_on.png b/files/images/firmware/X8_on.png new file mode 100644 index 0000000000000000000000000000000000000000..3ef05efce8f151f0b6798302ca84fadd8268cfd3 Binary files /dev/null and b/files/images/firmware/X8_on.png differ diff --git a/files/images/firmware/Y6_off.png b/files/images/firmware/Y6_off.png new file mode 100644 index 0000000000000000000000000000000000000000..ee33903a50127bfe076c5cb1decc480ad985c478 Binary files /dev/null and b/files/images/firmware/Y6_off.png differ diff --git a/files/images/firmware/Y6_on.png b/files/images/firmware/Y6_on.png new file mode 100644 index 0000000000000000000000000000000000000000..02346bd5a3add12121d7ac56729980e68592d567 Binary files /dev/null and b/files/images/firmware/Y6_on.png differ diff --git a/files/images/firmware/apmcopter.png b/files/images/firmware/apmcopter.png new file mode 100644 index 0000000000000000000000000000000000000000..e97dab02def691706861b7507b03042e27165c93 Binary files /dev/null and b/files/images/firmware/apmcopter.png differ diff --git a/files/images/firmware/apmplane.png b/files/images/firmware/apmplane.png new file mode 100644 index 0000000000000000000000000000000000000000..16b14ddbcb3aab6e26865c92c1e194d25a549ae2 Binary files /dev/null and b/files/images/firmware/apmplane.png differ diff --git a/files/images/firmware/apmrover.png b/files/images/firmware/apmrover.png new file mode 100644 index 0000000000000000000000000000000000000000..f3000622859d5177df0770e4f1b762c311602d64 Binary files /dev/null and b/files/images/firmware/apmrover.png differ diff --git a/files/images/firmware/heli.png b/files/images/firmware/heli.png new file mode 100644 index 0000000000000000000000000000000000000000..933a4a7096655b8a716474088c7da57618b0c4f6 Binary files /dev/null and b/files/images/firmware/heli.png differ diff --git a/files/images/firmware/heli_off.png b/files/images/firmware/heli_off.png new file mode 100644 index 0000000000000000000000000000000000000000..f958a9e5e9d2ec727dfa96adede6f4ec903ca0e7 Binary files /dev/null and b/files/images/firmware/heli_off.png differ diff --git a/files/images/firmware/heli_on.png b/files/images/firmware/heli_on.png new file mode 100644 index 0000000000000000000000000000000000000000..1df05837830cb69e22411ffcde8cb2b7a6c7dfdf Binary files /dev/null and b/files/images/firmware/heli_on.png differ diff --git a/files/images/firmware/hexa_off.png b/files/images/firmware/hexa_off.png new file mode 100644 index 0000000000000000000000000000000000000000..317053c25507c0b255d743ea44577bd44798f99d Binary files /dev/null and b/files/images/firmware/hexa_off.png differ diff --git a/files/images/firmware/hexa_on.png b/files/images/firmware/hexa_on.png new file mode 100644 index 0000000000000000000000000000000000000000..0975848fe7a40dfa068531512d6af0a36c5daae6 Binary files /dev/null and b/files/images/firmware/hexa_on.png differ diff --git a/files/images/firmware/hexaplus.png b/files/images/firmware/hexaplus.png new file mode 100644 index 0000000000000000000000000000000000000000..69d3dce352972468e9e4c2afb9a0b7cff6fb2db2 Binary files /dev/null and b/files/images/firmware/hexaplus.png differ diff --git a/files/images/firmware/hexax.png b/files/images/firmware/hexax.png new file mode 100644 index 0000000000000000000000000000000000000000..86bad85c0851cb51b5ce4422e8ab56b1b4cdec07 Binary files /dev/null and b/files/images/firmware/hexax.png differ diff --git a/files/images/firmware/hexay.png b/files/images/firmware/hexay.png new file mode 100644 index 0000000000000000000000000000000000000000..74a65b89ac7aae2febaf9b64d08e26f22022e24d Binary files /dev/null and b/files/images/firmware/hexay.png differ diff --git a/files/images/firmware/octaplus.png b/files/images/firmware/octaplus.png new file mode 100644 index 0000000000000000000000000000000000000000..a371ca8e76382dfad7c0ee05b199a9830013c81e Binary files /dev/null and b/files/images/firmware/octaplus.png differ diff --git a/files/images/firmware/octax.png b/files/images/firmware/octax.png new file mode 100644 index 0000000000000000000000000000000000000000..12ec5a2a2dd6e4c1909025088dd090a5f70dae12 Binary files /dev/null and b/files/images/firmware/octax.png differ diff --git a/files/images/firmware/octo_off.png b/files/images/firmware/octo_off.png new file mode 100644 index 0000000000000000000000000000000000000000..f5bbcbc21f0dbca71fe27f161b678f12c26b01c3 Binary files /dev/null and b/files/images/firmware/octo_off.png differ diff --git a/files/images/firmware/octo_on.png b/files/images/firmware/octo_on.png new file mode 100644 index 0000000000000000000000000000000000000000..6ff00e838bbfae635831db06aecc62dc40373c15 Binary files /dev/null and b/files/images/firmware/octo_on.png differ diff --git a/files/images/firmware/octx.png b/files/images/firmware/octx.png new file mode 100644 index 0000000000000000000000000000000000000000..e2390939732f8351263af3e4a4861a5672ac52bc Binary files /dev/null and b/files/images/firmware/octx.png differ diff --git a/files/images/firmware/plane.png b/files/images/firmware/plane.png new file mode 100644 index 0000000000000000000000000000000000000000..bfe646787a8c4509696c00ac32cdf5adf067913f Binary files /dev/null and b/files/images/firmware/plane.png differ diff --git a/files/images/firmware/plane_off.png b/files/images/firmware/plane_off.png new file mode 100644 index 0000000000000000000000000000000000000000..59b54674ab1d905d76a6e2b8fa4d8c4f853e7a4b Binary files /dev/null and b/files/images/firmware/plane_off.png differ diff --git a/files/images/firmware/plane_on.png b/files/images/firmware/plane_on.png new file mode 100644 index 0000000000000000000000000000000000000000..f4421cd72a870dcc6024183b14d684a978cb46c0 Binary files /dev/null and b/files/images/firmware/plane_on.png differ diff --git a/files/images/firmware/quad_T_off.png b/files/images/firmware/quad_T_off.png new file mode 100644 index 0000000000000000000000000000000000000000..df89eb1bc280485a50c4aefac54dca74677d2b03 Binary files /dev/null and b/files/images/firmware/quad_T_off.png differ diff --git a/files/images/firmware/quad_T_on.png b/files/images/firmware/quad_T_on.png new file mode 100644 index 0000000000000000000000000000000000000000..933c7bbb75eeff1617f721ff5a3a139a59e874eb Binary files /dev/null and b/files/images/firmware/quad_T_on.png differ diff --git a/files/images/firmware/quad_off.png b/files/images/firmware/quad_off.png new file mode 100644 index 0000000000000000000000000000000000000000..43e0f047c1f6709b00bfd9b9aeba60ad8bb2f7dc Binary files /dev/null and b/files/images/firmware/quad_off.png differ diff --git a/files/images/firmware/quad_on.png b/files/images/firmware/quad_on.png new file mode 100644 index 0000000000000000000000000000000000000000..ef296bbd75eb6611888b91296ed5a8274d334cc4 Binary files /dev/null and b/files/images/firmware/quad_on.png differ diff --git a/files/images/firmware/quadplus.png b/files/images/firmware/quadplus.png new file mode 100644 index 0000000000000000000000000000000000000000..350b76f24dbc1df7ef32b239b7e34176b649e2ae Binary files /dev/null and b/files/images/firmware/quadplus.png differ diff --git a/files/images/firmware/quadx.png b/files/images/firmware/quadx.png new file mode 100644 index 0000000000000000000000000000000000000000..a935e874329bd6b663b7fb4f5146b9731694aec7 Binary files /dev/null and b/files/images/firmware/quadx.png differ diff --git a/files/images/firmware/quady.png b/files/images/firmware/quady.png new file mode 100644 index 0000000000000000000000000000000000000000..819b338272fe3935aa03115c9a2c315f426643e9 Binary files /dev/null and b/files/images/firmware/quady.png differ diff --git a/files/images/firmware/rover.png b/files/images/firmware/rover.png new file mode 100644 index 0000000000000000000000000000000000000000..2bffc8e36103f94ad952e0685debf0a2dcc8906c Binary files /dev/null and b/files/images/firmware/rover.png differ diff --git a/files/images/firmware/rover_off.png b/files/images/firmware/rover_off.png new file mode 100644 index 0000000000000000000000000000000000000000..24e91f6dae67b552a30c9e6c7aa5f90bbf57c083 Binary files /dev/null and b/files/images/firmware/rover_off.png differ diff --git a/files/images/firmware/rover_on.png b/files/images/firmware/rover_on.png new file mode 100644 index 0000000000000000000000000000000000000000..13123caeb0c05810819f996fb3ec2301fe7d5098 Binary files /dev/null and b/files/images/firmware/rover_on.png differ diff --git a/files/images/firmware/triy.png b/files/images/firmware/triy.png new file mode 100644 index 0000000000000000000000000000000000000000..16654b3c5a2560d3cb80a8982e2166e6bf66529d Binary files /dev/null and b/files/images/firmware/triy.png differ diff --git a/files/images/px4/airframes/flying_wing.png b/files/images/px4/airframes/flying_wing.png new file mode 100644 index 0000000000000000000000000000000000000000..b5baa87dd2b6fc1366feaac3ee43b3eea6947280 Binary files /dev/null and b/files/images/px4/airframes/flying_wing.png differ diff --git a/files/images/px4/airframes/hexa_+.png b/files/images/px4/airframes/hexa_+.png new file mode 100755 index 0000000000000000000000000000000000000000..486d63a04204a925d0515d9195b948d4971453c4 Binary files /dev/null and b/files/images/px4/airframes/hexa_+.png differ diff --git a/files/images/px4/airframes/hexa_x.png b/files/images/px4/airframes/hexa_x.png new file mode 100755 index 0000000000000000000000000000000000000000..cd1fe507dfd4e448c5f2c1e6113f26463d7c30d1 Binary files /dev/null and b/files/images/px4/airframes/hexa_x.png differ diff --git a/files/images/px4/airframes/octo_+.png b/files/images/px4/airframes/octo_+.png new file mode 100755 index 0000000000000000000000000000000000000000..df6eefff2e32ba8179a7d08ad1b583180b8231d6 Binary files /dev/null and b/files/images/px4/airframes/octo_+.png differ diff --git a/files/images/px4/airframes/octo_x.png b/files/images/px4/airframes/octo_x.png new file mode 100755 index 0000000000000000000000000000000000000000..41faf992abe13e44e973268bb9ca1c659e391203 Binary files /dev/null and b/files/images/px4/airframes/octo_x.png differ diff --git a/files/images/px4/airframes/plane_aert.png b/files/images/px4/airframes/plane_aert.png new file mode 100644 index 0000000000000000000000000000000000000000..583d08d01d25dea95eff062b8eef00ba35668d53 Binary files /dev/null and b/files/images/px4/airframes/plane_aert.png differ diff --git a/files/images/px4/airframes/plane_ert.png b/files/images/px4/airframes/plane_ert.png new file mode 100644 index 0000000000000000000000000000000000000000..64d82d2cbf0793a19f40c19739274b8b095726f8 Binary files /dev/null and b/files/images/px4/airframes/plane_ert.png differ diff --git a/files/images/px4/airframes/quad_+.png b/files/images/px4/airframes/quad_+.png new file mode 100755 index 0000000000000000000000000000000000000000..4832def6c73a6a387038774cf270225549400d9f Binary files /dev/null and b/files/images/px4/airframes/quad_+.png differ diff --git a/files/images/px4/airframes/quad_h.png b/files/images/px4/airframes/quad_h.png new file mode 100644 index 0000000000000000000000000000000000000000..1c5efb6e8a54c169b8c3e6b22095b997927465af Binary files /dev/null and b/files/images/px4/airframes/quad_h.png differ diff --git a/files/images/px4/airframes/quad_x.png b/files/images/px4/airframes/quad_x.png new file mode 100755 index 0000000000000000000000000000000000000000..ea6835509aa5f58fbc000d018ea72e485ebf5884 Binary files /dev/null and b/files/images/px4/airframes/quad_x.png differ diff --git a/files/images/px4/calibration/3dr_gps/gps_00.png b/files/images/px4/calibration/3dr_gps/gps_00.png new file mode 100644 index 0000000000000000000000000000000000000000..483c45ca09b5590ade075a30b3481c2d98ebb945 Binary files /dev/null and b/files/images/px4/calibration/3dr_gps/gps_00.png differ diff --git a/files/images/px4/calibration/3dr_gps/gps_01.png b/files/images/px4/calibration/3dr_gps/gps_01.png new file mode 100644 index 0000000000000000000000000000000000000000..2bb8670270bb1d9d23e826b87c6640210aee1c50 Binary files /dev/null and b/files/images/px4/calibration/3dr_gps/gps_01.png differ diff --git a/files/images/px4/calibration/3dr_gps/gps_02.png b/files/images/px4/calibration/3dr_gps/gps_02.png new file mode 100644 index 0000000000000000000000000000000000000000..3a9f51c6e6a1e05c1f056a125dafb5c247488703 Binary files /dev/null and b/files/images/px4/calibration/3dr_gps/gps_02.png differ diff --git a/files/images/px4/calibration/3dr_gps/gps_03.png b/files/images/px4/calibration/3dr_gps/gps_03.png new file mode 100644 index 0000000000000000000000000000000000000000..2e945c1d744151ba66e3d616f5f8c459a8943da5 Binary files /dev/null and b/files/images/px4/calibration/3dr_gps/gps_03.png differ diff --git a/files/images/px4/calibration/3dr_gps/gps_04.png b/files/images/px4/calibration/3dr_gps/gps_04.png new file mode 100644 index 0000000000000000000000000000000000000000..92f2e2fa47e46efb0c8303e5bdf4b187fb816c34 Binary files /dev/null and b/files/images/px4/calibration/3dr_gps/gps_04.png differ diff --git a/files/images/px4/calibration/3dr_gps/gps_06.png b/files/images/px4/calibration/3dr_gps/gps_06.png new file mode 100644 index 0000000000000000000000000000000000000000..f4c909906ed59c37f07c1767dc7694f01113dee0 Binary files /dev/null and b/files/images/px4/calibration/3dr_gps/gps_06.png differ diff --git a/files/images/px4/calibration/3dr_gps/gps_07.png b/files/images/px4/calibration/3dr_gps/gps_07.png new file mode 100644 index 0000000000000000000000000000000000000000..021fcd497b627e85dfe2eef7e1e9a6d7407819e8 Binary files /dev/null and b/files/images/px4/calibration/3dr_gps/gps_07.png differ diff --git a/files/images/px4/calibration/3dr_gps/gps_12.png b/files/images/px4/calibration/3dr_gps/gps_12.png new file mode 100644 index 0000000000000000000000000000000000000000..3ec1a7a543875db4cf2a4f95f2beb6e8c705c06e Binary files /dev/null and b/files/images/px4/calibration/3dr_gps/gps_12.png differ diff --git a/files/images/px4/calibration/3dr_gps/gps_13.png b/files/images/px4/calibration/3dr_gps/gps_13.png new file mode 100644 index 0000000000000000000000000000000000000000..6374b96bb636722589c343fae53238a2ae1818b5 Binary files /dev/null and b/files/images/px4/calibration/3dr_gps/gps_13.png differ diff --git a/files/images/px4/calibration/3dr_gps/gps_14.png b/files/images/px4/calibration/3dr_gps/gps_14.png new file mode 100644 index 0000000000000000000000000000000000000000..3cd81390c5d1962f1f68ae86f8cb14ee07367c47 Binary files /dev/null and b/files/images/px4/calibration/3dr_gps/gps_14.png differ diff --git a/files/images/px4/calibration/3dr_gps/gps_15.png b/files/images/px4/calibration/3dr_gps/gps_15.png new file mode 100644 index 0000000000000000000000000000000000000000..bf8d0f4dea428102cbaa93723355726880453516 Binary files /dev/null and b/files/images/px4/calibration/3dr_gps/gps_15.png differ diff --git a/files/images/px4/calibration/3dr_gps/gps_16.png b/files/images/px4/calibration/3dr_gps/gps_16.png new file mode 100644 index 0000000000000000000000000000000000000000..3581f855879c600ff5ff8c37628f50c3f00fa743 Binary files /dev/null and b/files/images/px4/calibration/3dr_gps/gps_16.png differ diff --git a/files/images/px4/calibration/3dr_gps/gps_17.png b/files/images/px4/calibration/3dr_gps/gps_17.png new file mode 100644 index 0000000000000000000000000000000000000000..6d9418a11aa06a413f0016d7d9e0216ffe59c1b8 Binary files /dev/null and b/files/images/px4/calibration/3dr_gps/gps_17.png differ diff --git a/files/images/px4/calibration/3dr_gps/gps_18.png b/files/images/px4/calibration/3dr_gps/gps_18.png new file mode 100644 index 0000000000000000000000000000000000000000..b04e9f1824d7df7c5d93895bb07aaafc876c79f7 Binary files /dev/null and b/files/images/px4/calibration/3dr_gps/gps_18.png differ diff --git a/files/images/px4/calibration/3dr_gps/gps_19.png b/files/images/px4/calibration/3dr_gps/gps_19.png new file mode 100644 index 0000000000000000000000000000000000000000..0e19c227af9732905c9678dc185d91888b1be828 Binary files /dev/null and b/files/images/px4/calibration/3dr_gps/gps_19.png differ diff --git a/files/images/px4/calibration/3dr_gps/gps_24.png b/files/images/px4/calibration/3dr_gps/gps_24.png new file mode 100644 index 0000000000000000000000000000000000000000..215b0b40426b5ff12accfd8025448a570aede4aa Binary files /dev/null and b/files/images/px4/calibration/3dr_gps/gps_24.png differ diff --git a/files/images/px4/calibration/accel_x+.png b/files/images/px4/calibration/accel_x+.png new file mode 100644 index 0000000000000000000000000000000000000000..86c5e44e84473111982acf5cd74e319850755e3f Binary files /dev/null and b/files/images/px4/calibration/accel_x+.png differ diff --git a/files/images/px4/calibration/accel_x-.png b/files/images/px4/calibration/accel_x-.png new file mode 100644 index 0000000000000000000000000000000000000000..d2a88349f9559bfb337efaef80d50e6ba35e3ebd Binary files /dev/null and b/files/images/px4/calibration/accel_x-.png differ diff --git a/files/images/px4/calibration/accel_y+.png b/files/images/px4/calibration/accel_y+.png new file mode 100644 index 0000000000000000000000000000000000000000..956f9645e0cacb8ff2a4a2814db338b89e2277bd Binary files /dev/null and b/files/images/px4/calibration/accel_y+.png differ diff --git a/files/images/px4/calibration/accel_y-.png b/files/images/px4/calibration/accel_y-.png new file mode 100644 index 0000000000000000000000000000000000000000..4e85afb2a45eac143710b36684a858e6244930f2 Binary files /dev/null and b/files/images/px4/calibration/accel_y-.png differ diff --git a/files/images/px4/calibration/accel_z+.png b/files/images/px4/calibration/accel_z+.png new file mode 100644 index 0000000000000000000000000000000000000000..ab2422a00ee6c9f49b4228b869f7fe8b2365bcc1 Binary files /dev/null and b/files/images/px4/calibration/accel_z+.png differ diff --git a/files/images/px4/calibration/accel_z-.png b/files/images/px4/calibration/accel_z-.png new file mode 100644 index 0000000000000000000000000000000000000000..4abe01e173f93db77a0032774e0da2f24a15f03b Binary files /dev/null and b/files/images/px4/calibration/accel_z-.png differ diff --git a/files/images/px4/calibration/arrows.png b/files/images/px4/calibration/arrows.png new file mode 100644 index 0000000000000000000000000000000000000000..bfcc76cfdf954dd2a5591f64afa76bcddb9abd8d Binary files /dev/null and b/files/images/px4/calibration/arrows.png differ diff --git a/files/images/px4/calibration/mag_calibration_figure8.png b/files/images/px4/calibration/mag_calibration_figure8.png new file mode 100644 index 0000000000000000000000000000000000000000..8201146cd1ecc85bffb470d65757d621c58e3449 Binary files /dev/null and b/files/images/px4/calibration/mag_calibration_figure8.png differ diff --git a/files/images/px4/menu/cogwheels.png b/files/images/px4/menu/cogwheels.png new file mode 100644 index 0000000000000000000000000000000000000000..8079ca4169aca274ab014c0fb82f51f1c387b33b Binary files /dev/null and b/files/images/px4/menu/cogwheels.png differ diff --git a/files/images/px4/menu/firmware_upgrade.png b/files/images/px4/menu/firmware_upgrade.png new file mode 100644 index 0000000000000000000000000000000000000000..83397753376d9e9234d6cd1698d1d1c74bf5ea65 Binary files /dev/null and b/files/images/px4/menu/firmware_upgrade.png differ diff --git a/files/images/px4/menu/plane.png b/files/images/px4/menu/plane.png new file mode 100644 index 0000000000000000000000000000000000000000..e22d605a6bbaebf2e8dffd5e48f94657b52f099f Binary files /dev/null and b/files/images/px4/menu/plane.png differ diff --git a/files/images/px4/menu/remote.png b/files/images/px4/menu/remote.png new file mode 100644 index 0000000000000000000000000000000000000000..9785678d79b080bd0efd500790336f2ef2b2dd4e Binary files /dev/null and b/files/images/px4/menu/remote.png differ diff --git a/files/images/px4/menu/sensors.png b/files/images/px4/menu/sensors.png new file mode 100644 index 0000000000000000000000000000000000000000..6c972fae53bf98facc3d8a9f2ce1ee5cc40be6d3 Binary files /dev/null and b/files/images/px4/menu/sensors.png differ diff --git a/files/images/px4/rc/cessna_back.png b/files/images/px4/rc/cessna_back.png new file mode 100644 index 0000000000000000000000000000000000000000..ae54c7eb0c03bff52b0c681bbcf940ac4910714c Binary files /dev/null and b/files/images/px4/rc/cessna_back.png differ diff --git a/files/images/px4/rc/cessna_side.png b/files/images/px4/rc/cessna_side.png new file mode 100644 index 0000000000000000000000000000000000000000..5fc19e68ba5ceb47e23f6ec36961fc0038898633 Binary files /dev/null and b/files/images/px4/rc/cessna_side.png differ diff --git a/files/images/px4/rc/rc_backgrounds.graffle b/files/images/px4/rc/rc_backgrounds.graffle new file mode 100644 index 0000000000000000000000000000000000000000..a3b5c1703ac9dfdf7ae1481ba805370c76b1354c --- /dev/null +++ b/files/images/px4/rc/rc_backgrounds.graffle @@ -0,0 +1,674 @@ + + + + + ActiveLayerIndex + 0 + ApplicationVersion + + com.omnigroup.OmniGraffle + 139.18.0.187838 + + AutoAdjust + + BackgroundGraphic + + Bounds + {{0, 0}, {559.28001499176025, 782.8900146484375}} + Class + SolidGraphic + ID + 2 + Style + + shadow + + Draws + NO + + stroke + + Draws + NO + + + + BaseZoom + 0 + CanvasOrigin + {0, 0} + ColumnAlign + 1 + ColumnSpacing + 36 + CreationDate + 2013-08-23 20:20:16 +0000 + Creator + Lorenz + DisplayScale + 1 0/72 in = 1 0/72 in + GraphDocumentVersion + 8 + GraphicsList + + + Bounds + {{188.3818359375, 271.5}, {29, 16}} + Class + ShapedGraphic + FitText + YES + Flow + Resize + FontInfo + + Color + + b + 0.379293 + g + 0.379287 + r + 0.379298 + + Font + Helvetica-Bold + Size + 13 + + ID + 38 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + RTFD + + BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0 + ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp + bmcBlIQBKwVyaWdodIaEAmlJAQWShISEDE5TRGljdGlv + bmFyeQCUhAFpA5KElpYHTlNDb2xvcoaShISEB05TQ29s + b3IAlIQBYwKEBGZmZmaD6ujoPoPq6Og+g+ro6D4BhpKE + lpYQTlNQYXJhZ3JhcGhTdHlsZYaShISEEE5TUGFyYWdy + YXBoU3R5bGUAlIQEQ0NAUwIAhISEB05TQXJyYXkAlJkM + koSEhAlOU1RleHRUYWIAlIQCQ2YAHIaShKKhADiGkoSi + oQBUhpKEoqEAcIaShKKhAIGMAIaShKKhAIGoAIaShKKh + AIHEAIaShKKhAIHgAIaShKKhAIH8AIaShKKhAIEYAYaS + hKKhAIE0AYaShKKhAIFQAYaGgQAIhARbMWZdg83MTD2G + koSWlgZOU0ZvbnSGkoSEhAZOU0ZvbnQelJkohAVbNDBj + XQYAAAAeAAAA//5IAGUAbAB2AGUAdABpAGMAYQAtAEIA + bwBsAGQAAACEAWYNmwCbAZsAmwCGhoY= + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf390 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;\red97\green97\blue97;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\b\fs26 \cf2 right} + VerticalPad + 0 + + Wrap + NO + + + Bounds + {{153, 271.5}, {20, 16}} + Class + ShapedGraphic + FitText + YES + Flow + Resize + FontInfo + + Color + + b + 0.379293 + g + 0.379287 + r + 0.379298 + + Font + Helvetica-Bold + Size + 13 + + ID + 36 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + RTFD + + BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0 + ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp + bmcBlIQBKwRsZWZ0hoQCaUkBBJKEhIQMTlNEaWN0aW9u + YXJ5AJSEAWkEkoSWlg5OU09yaWdpbmFsRm9udIaShISE + Bk5TRm9udB6UmRyEBVsyOGNdBgAAABQAAAD//kgAZQBs + AHYAZQB0AGkAYwBhAIQBZgyEAWMAnQGdAJ0AhpKElpYQ + TlNQYXJhZ3JhcGhTdHlsZYaShISEF05TTXV0YWJsZVBh + cmFncmFwaFN0eWxlAISEEE5TUGFyYWdyYXBoU3R5bGUA + lIQEQ0NAUwIAhYEACIQEWzFmXYPNzEw9hpKElpYGTlNG + b250hpKEm5kohAVbNDBjXQYAAAAeAAAA//5IAGUAbAB2 + AGUAdABpAGMAYQAtAEIAbwBsAGQAAACcDZ0AnQGdAJ0A + hpKElpYHTlNDb2xvcoaShISEB05TQ29sb3IAlJ0ChARm + ZmZmg+ro6D6D6ujoPoPq6Og+AYaGhg== + + Text + {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf390 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;\red97\green97\blue97;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\b\fs26 \cf2 left} + VerticalPad + 0 + + Wrap + NO + + + Bounds + {{124, 268}, {23, 23}} + Class + ShapedGraphic + ID + 35 + Rotation + 180 + Shape + HorizontalTriangle + Style + + fill + + Color + + b + 0.380387 + g + 0.380387 + r + 0.380387 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{224, 268}, {23, 23}} + Class + ShapedGraphic + ID + 34 + Shape + HorizontalTriangle + Style + + fill + + Color + + b + 0.380387 + g + 0.380387 + r + 0.380387 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{251.99999284744263, 106}, {23, 23}} + Class + ShapedGraphic + ID + 33 + Rotation + 270 + Shape + HorizontalTriangle + Style + + fill + + Color + + b + 0.380387 + g + 0.380387 + r + 0.380387 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{167.80909729003906, 160}, {42.381816864013672, 42}} + Class + ShapedGraphic + ID + 32 + Shape + Circle + Style + + fill + + Color + + b + 0.379293 + g + 0.379287 + r + 0.379298 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{252, 205}, {23, 23}} + Class + ShapedGraphic + ID + 13 + Rotation + 90 + Shape + HorizontalTriangle + Style + + fill + + Color + + b + 0.380387 + g + 0.380387 + r + 0.380387 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + Bounds + {{171.5, 147.5}, {128, 23}} + Class + ShapedGraphic + ID + 30 + Rotation + 90 + Shape + Rectangle + Style + + fill + + Color + + b + 0.409312 + g + 0.828576 + r + 0.468975 + + + shadow + + Draws + NO + + + + + Bounds + {{119, 237}, {128, 23}} + Class + ShapedGraphic + ID + 29 + Shape + Rectangle + Style + + fill + + Color + + b + 0.409312 + g + 0.828576 + r + 0.468975 + + + shadow + + Draws + NO + + + + + Bounds + {{78, 71}, {222, 220}} + Class + ShapedGraphic + ID + 28 + Shape + Circle + Style + + fill + + Color + + b + 0.877468 + g + 0.877468 + r + 0.877468 + + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + VerticalPad + 0 + + + + GridInfo + + GuidesLocked + NO + GuidesVisible + YES + HPages + 1 + ImageCounter + 1 + KeepToScale + + Layers + + + Lock + NO + Name + Ebene 1 + Print + YES + View + YES + + + LayoutInfo + + Animate + NO + circoMinDist + 18 + circoSeparation + 0.0 + layoutEngine + dot + neatoSeparation + 0.0 + twopiSeparation + 0.0 + + LinksVisible + NO + MagnetsVisible + NO + MasterSheets + + ModificationDate + 2013-08-26 18:20:11 +0000 + Modifier + Lorenz + NotesVisible + NO + Orientation + 2 + OriginVisible + NO + PageBreaks + YES + PrintInfo + + NSBottomMargin + + float + 41 + + NSHorizonalPagination + + coded + BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG + + NSLeftMargin + + float + 18 + + NSPaperSize + + size + {595.28001499176025, 841.8900146484375} + + NSPrintReverseOrientation + + int + 0 + + NSRightMargin + + float + 18 + + NSTopMargin + + float + 18 + + + PrintOnePage + + ReadOnly + NO + RowAlign + 1 + RowSpacing + 36 + SheetTitle + Arbeitsfläche 1 + SmartAlignmentGuidesActive + YES + SmartDistanceGuidesActive + YES + UniqueID + 1 + UseEntirePage + + VPages + 1 + WindowInfo + + CurrentSheet + 0 + ExpandedCanvases + + Frame + {{76, 4}, {918, 774}} + ListView + + OutlineWidth + 142 + RightSidebar + + ShowRuler + + Sidebar + + SidebarWidth + 120 + VisibleRegion + {{-112, 0}, {783, 635}} + Zoom + 1 + ZoomValues + + + Arbeitsfläche 1 + 1 + 1 + + + + + diff --git a/files/px4/widgets/px4_calibration.qgw b/files/px4/widgets/px4_calibration.qgw index 2a498a3ebfdd93c12a8a8e89738eb3cf75496281..bb895bc3711fc1e8be882953522613cc90dd79f3 100644 --- a/files/px4/widgets/px4_calibration.qgw +++ b/files/px4/widgets/px4_calibration.qgw @@ -58,4 +58,16 @@ QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAM4=1 QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAM5=0 QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAM6=0 QGC_TOOL_WIDGET_ITEMS\5\QGC_COMMAND_BUTTON_PARAM7=0 -QGC_TOOL_WIDGET_ITEMS\size=5 +QGC_TOOL_WIDGET_ITEMS\6\TYPE=COMMANDBUTTON +QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_DESCRIPTION=Reboot to Bootloader +QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_BUTTONTEXT=BOOTLOADER +QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_COMMANDID=246 +QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_PARAMS_VISIBLE=false +QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_PARAM1=3 +QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_PARAM2=0 +QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_PARAM3=0 +QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_PARAM4=0 +QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_PARAM5=0 +QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_PARAM6=0 +QGC_TOOL_WIDGET_ITEMS\6\QGC_COMMAND_BUTTON_PARAM7=0 +QGC_TOOL_WIDGET_ITEMS\size=7 diff --git a/files/styles/style-dark.css b/files/styles/style-dark.css index 762299c346c13ed4d3a62179c6d13d4209561a1a..75656465c5a1150f2f7015afc9cc59f36ba44193 100644 --- a/files/styles/style-dark.css +++ b/files/styles/style-dark.css @@ -208,6 +208,32 @@ QGCToolBar .QWidget { background-color: transparent; } +QGCPX4SensorCalibration QLabel#magLabel { + font-size: 15pt; + font-weight: bold; + border-radius: 4px; + min-height: 25px; +} + +QGCPX4SensorCalibration QLabel#gyroLabel { + font-size: 15pt; + font-weight: bold; + border-radius: 4px; + min-height: 25px; +} + +QGCPX4SensorCalibration QLabel#accelLabel { + font-size: 15pt; + font-weight: bold; + border-radius: 4px; + min-height: 25px; +} + +QGCPX4VehicleConfig QLabel#rcLabel { + color: #FEC654; + font-size: 18pt; +} + QGCToolWidgetItem { border: 1px solid #666; border-radius: 3px; @@ -248,6 +274,31 @@ QLabel#noUas { font-size: 30pt; } +QMessageBox QLabel { + font-size: 14pt; +} + +QMessageBox { + min-width: 400px; + min-height: 300px; +} + +QLabel#calibrationExplanationLabel { + font-size: 20pt; +} + +QLabel#tabTitleLabel { + font-size: 28pt; + font-weight: lighter; + margin-top: 16px; + margin-bottom: 8px; +} + +QLabel#instructionLabel { + color: #FEC654; + font-size: 26pt; +} + QLineEdit { border: 1px solid #777; border-radius: 2px; @@ -345,6 +396,34 @@ QPushButton, QToolButton { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #777, stop: 1 #333); } +QPushButton#advancedMenuButton, QPushButton#airframeMenuButton, QPushButton#firmwareMenuButton, +QPushButton#generalMenuButton, QPushButton#rcMenuButton, QPushButton#sensorMenuButton { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #333, stop: 1 #111); + border-radius: 5px; + min-height: 64px; + max-height: 64px; + min-width: 80px; + border: 1px solid #000000; +} + +QPushButton#planePushButton, QPushButton#flyingWingPushButton, QPushButton#quadXPushButton, +QPushButton#quadPlusPushButton, QPushButton#hexaXPushButton, QPushButton#hexaPlusPushButton, +QPushButton#octoXPushButton, QPushButton#octoPlusPushButton, QPushButton#hPushButton { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #777, stop: 1 #333); + border-radius: 5px; + min-height: 140px; + max-height: 240px; + min-width: 140px; + border: 1px solid #465158; +} + +QPushButton:checked#planePushButton, QPushButton:checked#flyingWingPushButton, QPushButton:checked#quadXPushButton, +QPushButton:checked#quadPlusPushButton, QPushButton:checked#hexaXPushButton, QPushButton:checked#hexaPlusPushButton, +QPushButton:checked#octoXPushButton, QPushButton:checked#octoPlusPushButton, QPushButton:checked#hPushButton { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #77F, stop: 1 #33A); + border: 3px solid #4651A8; +} + QPushButton#viewModeGeneric, QPushButton#viewModePX4, QPushButton#viewModeAPM, QPushButton#viewModeAR { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #73D95D, stop: 1 #18A154); border-radius: 12px; @@ -355,6 +434,24 @@ QPushButton#viewModeGeneric, QPushButton#viewModePX4, QPushButton#viewModeAPM, Q border: 3px solid #465158; } +QPushButton#magButton, QPushButton#gyroButton, QPushButton#accelButton { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #757575, stop: 1 #333); + border-radius: 5px; + border: 1px solid #000000; +} + +QWidget#containerWidget { + background-color: qlineargradient(spread:pad, x1:0.527222, y1:0.961, x2:0.536946, y2:0.198864, stop:0.103448 rgba(65, 65, 65, 255), stop:1 rgba(119, 119, 119, 255)); + border-radius: 16px; + border: 2px solid #CCCCCC; +} + +QWidget#navBarWidget { + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 #404040, stop:1 #727272); + border-radius: 0px; + border: 1px solid #222222; +} + QPushButton#connectButton, QPushButton#controlButton { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #73D95D, stop: 1 #18A154); } diff --git a/libs/eigen/Eigen/src/Core/BandMatrix.h b/libs/eigen/Eigen/src/Core/BandMatrix.h index dda8efba3671ac46f1875f3f9d4679617e5b106d..e6922b50f5f6d3c40b55e0179958dc09c5e9ae16 100644 --- a/libs/eigen/Eigen/src/Core/BandMatrix.h +++ b/libs/eigen/Eigen/src/Core/BandMatrix.h @@ -285,6 +285,7 @@ class BandMatrixWrapper : public BandMatrixBase Traits; enum { @@ -98,11 +98,12 @@ void computeProductBlockingSizes(std::ptrdiff_t& k, std::ptrdiff_t& m, std::ptrd mr_mask = (0xffffffff/mr)*mr }; + initial_n = n; manage_caching_sizes(GetAction, &l1, &l2); k = std::min(k, l1/kdiv); std::ptrdiff_t _m = k>0 ? l2/(4 * sizeof(LhsScalar) * k) : 0; if(_m diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/ardupilotmega.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/ardupilotmega.h index eec9a89c50e1bd18e9708063175983c9320c14bf..3aad8e6785ec36018850aeda6822052857eb7880 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/ardupilotmega.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/ardupilotmega.h @@ -12,15 +12,15 @@ extern "C" { // MESSAGE LENGTHS AND CRCS #ifndef MAVLINK_MESSAGE_LENGTHS -#define MAVLINK_MESSAGE_LENGTHS {9, 31, 12, 0, 14, 28, 3, 32, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 20, 2, 25, 23, 30, 101, 22, 26, 16, 14, 28, 32, 28, 28, 22, 22, 21, 6, 6, 37, 4, 4, 2, 2, 4, 2, 2, 3, 13, 12, 19, 17, 15, 15, 27, 25, 18, 18, 20, 20, 9, 34, 26, 46, 36, 0, 6, 4, 0, 11, 18, 0, 0, 0, 20, 0, 33, 3, 0, 0, 20, 22, 0, 0, 0, 0, 0, 0, 0, 28, 56, 42, 33, 0, 0, 0, 0, 0, 0, 0, 26, 32, 32, 20, 32, 62, 54, 64, 84, 9, 254, 249, 9, 36, 26, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 33, 25, 42, 8, 4, 12, 15, 13, 6, 15, 14, 0, 12, 3, 8, 28, 44, 3, 9, 22, 12, 18, 34, 66, 98, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 30, 18, 18, 51, 9, 0} +#define MAVLINK_MESSAGE_LENGTHS {9, 31, 12, 0, 14, 28, 3, 32, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 20, 2, 25, 23, 30, 101, 22, 26, 16, 14, 28, 32, 28, 28, 22, 22, 21, 6, 6, 37, 4, 4, 2, 2, 4, 2, 2, 3, 13, 12, 19, 17, 15, 15, 27, 25, 18, 18, 20, 20, 9, 34, 26, 46, 36, 0, 6, 4, 0, 11, 18, 0, 0, 0, 20, 0, 33, 3, 0, 0, 20, 22, 0, 0, 0, 0, 0, 0, 0, 28, 56, 42, 33, 0, 0, 0, 0, 0, 0, 0, 26, 32, 32, 20, 32, 62, 54, 64, 84, 9, 254, 249, 9, 36, 26, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 33, 25, 42, 8, 4, 12, 15, 13, 6, 15, 14, 0, 12, 3, 8, 28, 44, 3, 9, 22, 12, 18, 34, 66, 98, 8, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 30, 18, 18, 51, 9, 0} #endif #ifndef MAVLINK_MESSAGE_CRCS -#define MAVLINK_MESSAGE_CRCS {50, 124, 137, 0, 237, 217, 104, 119, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 214, 159, 220, 168, 24, 23, 170, 144, 67, 115, 39, 246, 185, 104, 237, 244, 222, 212, 9, 254, 230, 28, 28, 132, 221, 232, 11, 153, 41, 39, 214, 223, 141, 33, 15, 3, 100, 24, 239, 238, 30, 240, 183, 130, 130, 0, 148, 21, 0, 243, 124, 0, 0, 0, 20, 0, 152, 143, 0, 0, 127, 106, 0, 0, 0, 0, 0, 0, 0, 231, 183, 63, 54, 0, 0, 0, 0, 0, 0, 0, 175, 102, 158, 208, 56, 93, 211, 108, 32, 185, 235, 93, 124, 124, 119, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 241, 15, 134, 219, 208, 188, 84, 22, 19, 21, 134, 0, 78, 68, 189, 127, 111, 21, 21, 144, 1, 234, 73, 181, 22, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 204, 49, 170, 44, 83, 46, 0} +#define MAVLINK_MESSAGE_CRCS {50, 124, 137, 0, 237, 217, 104, 119, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 214, 159, 220, 168, 24, 23, 170, 144, 67, 115, 39, 246, 185, 104, 237, 244, 222, 212, 9, 254, 230, 28, 28, 132, 221, 232, 11, 153, 41, 39, 214, 223, 141, 33, 15, 3, 100, 24, 239, 238, 30, 240, 183, 130, 130, 0, 148, 21, 0, 243, 124, 0, 0, 0, 20, 0, 152, 143, 0, 0, 127, 106, 0, 0, 0, 0, 0, 0, 0, 231, 183, 63, 54, 0, 0, 0, 0, 0, 0, 0, 175, 102, 158, 208, 56, 93, 211, 108, 32, 185, 235, 93, 124, 124, 119, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 241, 15, 134, 219, 208, 188, 84, 22, 19, 21, 134, 0, 78, 68, 189, 127, 154, 21, 21, 144, 1, 234, 73, 181, 22, 83, 167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 204, 49, 170, 44, 83, 46, 0} #endif #ifndef MAVLINK_MESSAGE_INFO -#define MAVLINK_MESSAGE_INFO {MAVLINK_MESSAGE_INFO_HEARTBEAT, MAVLINK_MESSAGE_INFO_SYS_STATUS, MAVLINK_MESSAGE_INFO_SYSTEM_TIME, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_PING, MAVLINK_MESSAGE_INFO_CHANGE_OPERATOR_CONTROL, MAVLINK_MESSAGE_INFO_CHANGE_OPERATOR_CONTROL_ACK, MAVLINK_MESSAGE_INFO_AUTH_KEY, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_SET_MODE, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_PARAM_REQUEST_READ, MAVLINK_MESSAGE_INFO_PARAM_REQUEST_LIST, MAVLINK_MESSAGE_INFO_PARAM_VALUE, MAVLINK_MESSAGE_INFO_PARAM_SET, MAVLINK_MESSAGE_INFO_GPS_RAW_INT, MAVLINK_MESSAGE_INFO_GPS_STATUS, MAVLINK_MESSAGE_INFO_SCALED_IMU, MAVLINK_MESSAGE_INFO_RAW_IMU, MAVLINK_MESSAGE_INFO_RAW_PRESSURE, MAVLINK_MESSAGE_INFO_SCALED_PRESSURE, MAVLINK_MESSAGE_INFO_ATTITUDE, MAVLINK_MESSAGE_INFO_ATTITUDE_QUATERNION, MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED, MAVLINK_MESSAGE_INFO_GLOBAL_POSITION_INT, MAVLINK_MESSAGE_INFO_RC_CHANNELS_SCALED, MAVLINK_MESSAGE_INFO_RC_CHANNELS_RAW, MAVLINK_MESSAGE_INFO_SERVO_OUTPUT_RAW, MAVLINK_MESSAGE_INFO_MISSION_REQUEST_PARTIAL_LIST, MAVLINK_MESSAGE_INFO_MISSION_WRITE_PARTIAL_LIST, MAVLINK_MESSAGE_INFO_MISSION_ITEM, MAVLINK_MESSAGE_INFO_MISSION_REQUEST, MAVLINK_MESSAGE_INFO_MISSION_SET_CURRENT, MAVLINK_MESSAGE_INFO_MISSION_CURRENT, MAVLINK_MESSAGE_INFO_MISSION_REQUEST_LIST, MAVLINK_MESSAGE_INFO_MISSION_COUNT, MAVLINK_MESSAGE_INFO_MISSION_CLEAR_ALL, MAVLINK_MESSAGE_INFO_MISSION_ITEM_REACHED, MAVLINK_MESSAGE_INFO_MISSION_ACK, MAVLINK_MESSAGE_INFO_SET_GPS_GLOBAL_ORIGIN, MAVLINK_MESSAGE_INFO_GPS_GLOBAL_ORIGIN, MAVLINK_MESSAGE_INFO_SET_LOCAL_POSITION_SETPOINT, MAVLINK_MESSAGE_INFO_LOCAL_POSITION_SETPOINT, MAVLINK_MESSAGE_INFO_GLOBAL_POSITION_SETPOINT_INT, MAVLINK_MESSAGE_INFO_SET_GLOBAL_POSITION_SETPOINT_INT, MAVLINK_MESSAGE_INFO_SAFETY_SET_ALLOWED_AREA, MAVLINK_MESSAGE_INFO_SAFETY_ALLOWED_AREA, MAVLINK_MESSAGE_INFO_SET_ROLL_PITCH_YAW_THRUST, MAVLINK_MESSAGE_INFO_SET_ROLL_PITCH_YAW_SPEED_THRUST, MAVLINK_MESSAGE_INFO_ROLL_PITCH_YAW_THRUST_SETPOINT, MAVLINK_MESSAGE_INFO_ROLL_PITCH_YAW_SPEED_THRUST_SETPOINT, MAVLINK_MESSAGE_INFO_SET_QUAD_MOTORS_SETPOINT, MAVLINK_MESSAGE_INFO_SET_QUAD_SWARM_ROLL_PITCH_YAW_THRUST, MAVLINK_MESSAGE_INFO_NAV_CONTROLLER_OUTPUT, MAVLINK_MESSAGE_INFO_SET_QUAD_SWARM_LED_ROLL_PITCH_YAW_THRUST, MAVLINK_MESSAGE_INFO_STATE_CORRECTION, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_REQUEST_DATA_STREAM, MAVLINK_MESSAGE_INFO_DATA_STREAM, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_MANUAL_CONTROL, MAVLINK_MESSAGE_INFO_RC_CHANNELS_OVERRIDE, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_VFR_HUD, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_COMMAND_LONG, MAVLINK_MESSAGE_INFO_COMMAND_ACK, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_ROLL_PITCH_YAW_RATES_THRUST_SETPOINT, MAVLINK_MESSAGE_INFO_MANUAL_SETPOINT, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, MAVLINK_MESSAGE_INFO_HIL_STATE, MAVLINK_MESSAGE_INFO_HIL_CONTROLS, MAVLINK_MESSAGE_INFO_HIL_RC_INPUTS_RAW, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_OPTICAL_FLOW, MAVLINK_MESSAGE_INFO_GLOBAL_VISION_POSITION_ESTIMATE, MAVLINK_MESSAGE_INFO_VISION_POSITION_ESTIMATE, MAVLINK_MESSAGE_INFO_VISION_SPEED_ESTIMATE, MAVLINK_MESSAGE_INFO_VICON_POSITION_ESTIMATE, MAVLINK_MESSAGE_INFO_HIGHRES_IMU, MAVLINK_MESSAGE_INFO_OMNIDIRECTIONAL_FLOW, MAVLINK_MESSAGE_INFO_HIL_SENSOR, MAVLINK_MESSAGE_INFO_SIM_STATE, MAVLINK_MESSAGE_INFO_RADIO_STATUS, MAVLINK_MESSAGE_INFO_FILE_TRANSFER_START, MAVLINK_MESSAGE_INFO_FILE_TRANSFER_DIR_LIST, MAVLINK_MESSAGE_INFO_FILE_TRANSFER_RES, MAVLINK_MESSAGE_INFO_HIL_GPS, MAVLINK_MESSAGE_INFO_HIL_OPTICAL_FLOW, MAVLINK_MESSAGE_INFO_HIL_STATE_QUATERNION, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_BATTERY_STATUS, MAVLINK_MESSAGE_INFO_SETPOINT_8DOF, MAVLINK_MESSAGE_INFO_SETPOINT_6DOF, MAVLINK_MESSAGE_INFO_SENSOR_OFFSETS, MAVLINK_MESSAGE_INFO_SET_MAG_OFFSETS, MAVLINK_MESSAGE_INFO_MEMINFO, MAVLINK_MESSAGE_INFO_AP_ADC, MAVLINK_MESSAGE_INFO_DIGICAM_CONFIGURE, MAVLINK_MESSAGE_INFO_DIGICAM_CONTROL, MAVLINK_MESSAGE_INFO_MOUNT_CONFIGURE, MAVLINK_MESSAGE_INFO_MOUNT_CONTROL, MAVLINK_MESSAGE_INFO_MOUNT_STATUS, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_FENCE_POINT, MAVLINK_MESSAGE_INFO_FENCE_FETCH_POINT, MAVLINK_MESSAGE_INFO_FENCE_STATUS, MAVLINK_MESSAGE_INFO_AHRS, MAVLINK_MESSAGE_INFO_SIMSTATE, MAVLINK_MESSAGE_INFO_HWSTATUS, MAVLINK_MESSAGE_INFO_RADIO, MAVLINK_MESSAGE_INFO_LIMITS_STATUS, MAVLINK_MESSAGE_INFO_WIND, MAVLINK_MESSAGE_INFO_DATA16, MAVLINK_MESSAGE_INFO_DATA32, MAVLINK_MESSAGE_INFO_DATA64, MAVLINK_MESSAGE_INFO_DATA96, MAVLINK_MESSAGE_INFO_RANGEFINDER, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_MEMORY_VECT, MAVLINK_MESSAGE_INFO_DEBUG_VECT, MAVLINK_MESSAGE_INFO_NAMED_VALUE_FLOAT, MAVLINK_MESSAGE_INFO_NAMED_VALUE_INT, MAVLINK_MESSAGE_INFO_STATUSTEXT, MAVLINK_MESSAGE_INFO_DEBUG, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}} +#define MAVLINK_MESSAGE_INFO {MAVLINK_MESSAGE_INFO_HEARTBEAT, MAVLINK_MESSAGE_INFO_SYS_STATUS, MAVLINK_MESSAGE_INFO_SYSTEM_TIME, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_PING, MAVLINK_MESSAGE_INFO_CHANGE_OPERATOR_CONTROL, MAVLINK_MESSAGE_INFO_CHANGE_OPERATOR_CONTROL_ACK, MAVLINK_MESSAGE_INFO_AUTH_KEY, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_SET_MODE, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_PARAM_REQUEST_READ, MAVLINK_MESSAGE_INFO_PARAM_REQUEST_LIST, MAVLINK_MESSAGE_INFO_PARAM_VALUE, MAVLINK_MESSAGE_INFO_PARAM_SET, MAVLINK_MESSAGE_INFO_GPS_RAW_INT, MAVLINK_MESSAGE_INFO_GPS_STATUS, MAVLINK_MESSAGE_INFO_SCALED_IMU, MAVLINK_MESSAGE_INFO_RAW_IMU, MAVLINK_MESSAGE_INFO_RAW_PRESSURE, MAVLINK_MESSAGE_INFO_SCALED_PRESSURE, MAVLINK_MESSAGE_INFO_ATTITUDE, MAVLINK_MESSAGE_INFO_ATTITUDE_QUATERNION, MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED, MAVLINK_MESSAGE_INFO_GLOBAL_POSITION_INT, MAVLINK_MESSAGE_INFO_RC_CHANNELS_SCALED, MAVLINK_MESSAGE_INFO_RC_CHANNELS_RAW, MAVLINK_MESSAGE_INFO_SERVO_OUTPUT_RAW, MAVLINK_MESSAGE_INFO_MISSION_REQUEST_PARTIAL_LIST, MAVLINK_MESSAGE_INFO_MISSION_WRITE_PARTIAL_LIST, MAVLINK_MESSAGE_INFO_MISSION_ITEM, MAVLINK_MESSAGE_INFO_MISSION_REQUEST, MAVLINK_MESSAGE_INFO_MISSION_SET_CURRENT, MAVLINK_MESSAGE_INFO_MISSION_CURRENT, MAVLINK_MESSAGE_INFO_MISSION_REQUEST_LIST, MAVLINK_MESSAGE_INFO_MISSION_COUNT, MAVLINK_MESSAGE_INFO_MISSION_CLEAR_ALL, MAVLINK_MESSAGE_INFO_MISSION_ITEM_REACHED, MAVLINK_MESSAGE_INFO_MISSION_ACK, MAVLINK_MESSAGE_INFO_SET_GPS_GLOBAL_ORIGIN, MAVLINK_MESSAGE_INFO_GPS_GLOBAL_ORIGIN, MAVLINK_MESSAGE_INFO_SET_LOCAL_POSITION_SETPOINT, MAVLINK_MESSAGE_INFO_LOCAL_POSITION_SETPOINT, MAVLINK_MESSAGE_INFO_GLOBAL_POSITION_SETPOINT_INT, MAVLINK_MESSAGE_INFO_SET_GLOBAL_POSITION_SETPOINT_INT, MAVLINK_MESSAGE_INFO_SAFETY_SET_ALLOWED_AREA, MAVLINK_MESSAGE_INFO_SAFETY_ALLOWED_AREA, MAVLINK_MESSAGE_INFO_SET_ROLL_PITCH_YAW_THRUST, MAVLINK_MESSAGE_INFO_SET_ROLL_PITCH_YAW_SPEED_THRUST, MAVLINK_MESSAGE_INFO_ROLL_PITCH_YAW_THRUST_SETPOINT, MAVLINK_MESSAGE_INFO_ROLL_PITCH_YAW_SPEED_THRUST_SETPOINT, MAVLINK_MESSAGE_INFO_SET_QUAD_MOTORS_SETPOINT, MAVLINK_MESSAGE_INFO_SET_QUAD_SWARM_ROLL_PITCH_YAW_THRUST, MAVLINK_MESSAGE_INFO_NAV_CONTROLLER_OUTPUT, MAVLINK_MESSAGE_INFO_SET_QUAD_SWARM_LED_ROLL_PITCH_YAW_THRUST, MAVLINK_MESSAGE_INFO_STATE_CORRECTION, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_REQUEST_DATA_STREAM, MAVLINK_MESSAGE_INFO_DATA_STREAM, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_MANUAL_CONTROL, MAVLINK_MESSAGE_INFO_RC_CHANNELS_OVERRIDE, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_VFR_HUD, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_COMMAND_LONG, MAVLINK_MESSAGE_INFO_COMMAND_ACK, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_ROLL_PITCH_YAW_RATES_THRUST_SETPOINT, MAVLINK_MESSAGE_INFO_MANUAL_SETPOINT, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, MAVLINK_MESSAGE_INFO_HIL_STATE, MAVLINK_MESSAGE_INFO_HIL_CONTROLS, MAVLINK_MESSAGE_INFO_HIL_RC_INPUTS_RAW, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_OPTICAL_FLOW, MAVLINK_MESSAGE_INFO_GLOBAL_VISION_POSITION_ESTIMATE, MAVLINK_MESSAGE_INFO_VISION_POSITION_ESTIMATE, MAVLINK_MESSAGE_INFO_VISION_SPEED_ESTIMATE, MAVLINK_MESSAGE_INFO_VICON_POSITION_ESTIMATE, MAVLINK_MESSAGE_INFO_HIGHRES_IMU, MAVLINK_MESSAGE_INFO_OMNIDIRECTIONAL_FLOW, MAVLINK_MESSAGE_INFO_HIL_SENSOR, MAVLINK_MESSAGE_INFO_SIM_STATE, MAVLINK_MESSAGE_INFO_RADIO_STATUS, MAVLINK_MESSAGE_INFO_FILE_TRANSFER_START, MAVLINK_MESSAGE_INFO_FILE_TRANSFER_DIR_LIST, MAVLINK_MESSAGE_INFO_FILE_TRANSFER_RES, MAVLINK_MESSAGE_INFO_HIL_GPS, MAVLINK_MESSAGE_INFO_HIL_OPTICAL_FLOW, MAVLINK_MESSAGE_INFO_HIL_STATE_QUATERNION, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_BATTERY_STATUS, MAVLINK_MESSAGE_INFO_SETPOINT_8DOF, MAVLINK_MESSAGE_INFO_SETPOINT_6DOF, MAVLINK_MESSAGE_INFO_SENSOR_OFFSETS, MAVLINK_MESSAGE_INFO_SET_MAG_OFFSETS, MAVLINK_MESSAGE_INFO_MEMINFO, MAVLINK_MESSAGE_INFO_AP_ADC, MAVLINK_MESSAGE_INFO_DIGICAM_CONFIGURE, MAVLINK_MESSAGE_INFO_DIGICAM_CONTROL, MAVLINK_MESSAGE_INFO_MOUNT_CONFIGURE, MAVLINK_MESSAGE_INFO_MOUNT_CONTROL, MAVLINK_MESSAGE_INFO_MOUNT_STATUS, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_FENCE_POINT, MAVLINK_MESSAGE_INFO_FENCE_FETCH_POINT, MAVLINK_MESSAGE_INFO_FENCE_STATUS, MAVLINK_MESSAGE_INFO_AHRS, MAVLINK_MESSAGE_INFO_SIMSTATE, MAVLINK_MESSAGE_INFO_HWSTATUS, MAVLINK_MESSAGE_INFO_RADIO, MAVLINK_MESSAGE_INFO_LIMITS_STATUS, MAVLINK_MESSAGE_INFO_WIND, MAVLINK_MESSAGE_INFO_DATA16, MAVLINK_MESSAGE_INFO_DATA32, MAVLINK_MESSAGE_INFO_DATA64, MAVLINK_MESSAGE_INFO_DATA96, MAVLINK_MESSAGE_INFO_RANGEFINDER, MAVLINK_MESSAGE_INFO_AIRSPEED_AUTOCAL, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_MEMORY_VECT, MAVLINK_MESSAGE_INFO_DEBUG_VECT, MAVLINK_MESSAGE_INFO_NAMED_VALUE_FLOAT, MAVLINK_MESSAGE_INFO_NAMED_VALUE_INT, MAVLINK_MESSAGE_INFO_STATUSTEXT, MAVLINK_MESSAGE_INFO_DEBUG, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}} #endif #include "../protocol.h" @@ -74,6 +74,7 @@ enum MAV_CMD MAV_CMD_DO_SET_SERVO=183, /* Set a servo to a desired PWM value. |Servo number| PWM (microseconds, 1000 to 2000 typical)| Empty| Empty| Empty| Empty| Empty| */ MAV_CMD_DO_REPEAT_SERVO=184, /* Cycle a between its nominal setting and a desired PWM for a desired number of cycles with a desired period. |Servo number| PWM (microseconds, 1000 to 2000 typical)| Cycle count| Cycle time (seconds)| Empty| Empty| Empty| */ MAV_CMD_DO_CONTROL_VIDEO=200, /* Control onboard camera system. |Camera ID (-1 for all)| Transmission: 0: disabled, 1: enabled compressed, 2: enabled raw| Transmission mode: 0: video stream, >0: single images every n seconds (decimal)| Recording: 0: disabled, 1: enabled compressed, 2: enabled raw| Empty| Empty| Empty| */ + MAV_CMD_DO_SET_ROI=201, /* Sets the region of interest (ROI) for a sensor set or the vehicle itself. This can then be used by the vehicles control system to control the vehicle attitude and the attitude of various sensors such as cameras. |Region of intereset mode. (see MAV_ROI enum)| MISSION index/ target ID. (see MAV_ROI enum)| ROI index (allows a vehicle to manage multiple ROI's)| Empty| x the location of the fixed ROI (see MAV_FRAME)| y| z| */ MAV_CMD_DO_DIGICAM_CONFIGURE=202, /* Mission command to configure an on-board camera controller system. |Modes: P, TV, AV, M, Etc| Shutter speed: Divisor number for one second| Aperture: F stop number| ISO number e.g. 80, 100, 200, Etc| Exposure type enumerator| Command Identity| Main engine cut-off time before camera trigger in seconds/10 (0 means no cut-off)| */ MAV_CMD_DO_DIGICAM_CONTROL=203, /* Mission command to control an on-board camera controller system. |Session control e.g. show/hide lens| Zoom's absolute position| Zooming step value to offset zoom from the current position| Focus Locking, Unlocking or Re-locking| Shooting Command| Command Identity| Empty| */ MAV_CMD_DO_MOUNT_CONFIGURE=204, /* Mission command to configure a camera or antenna mount |Mount operation mode (see MAV_MOUNT_MODE enum)| stabilize roll? (1 = yes, 0 = no)| stabilize pitch? (1 = yes, 0 = no)| stabilize yaw? (1 = yes, 0 = no)| Empty| Empty| Empty| */ @@ -86,7 +87,8 @@ enum MAV_CMD MAV_CMD_OVERRIDE_GOTO=252, /* Hold / continue the current action |MAV_GOTO_DO_HOLD: hold MAV_GOTO_DO_CONTINUE: continue with next item in mission plan| MAV_GOTO_HOLD_AT_CURRENT_POSITION: Hold at current position MAV_GOTO_HOLD_AT_SPECIFIED_POSITION: hold at specified position| MAV_FRAME coordinate frame of hold point| Desired yaw angle in degrees| Latitude / X position| Longitude / Y position| Altitude / Z position| */ MAV_CMD_MISSION_START=300, /* start running a mission |first_item: the first mission item to run| last_item: the last mission item to run (after this item is run, the mission ends)| */ MAV_CMD_COMPONENT_ARM_DISARM=400, /* Arms / Disarms a component |1 to arm, 0 to disarm| */ - MAV_CMD_ENUM_END=401, /* | */ + MAV_CMD_START_RX_PAIR=500, /* Starts receiver pairing |0:Spektrum| 0:Spektrum DSM2, 1:Spektrum DSMX| */ + MAV_CMD_ENUM_END=501, /* | */ }; #endif @@ -179,6 +181,7 @@ enum LIMIT_MODULE #include "./mavlink_msg_data64.h" #include "./mavlink_msg_data96.h" #include "./mavlink_msg_rangefinder.h" +#include "./mavlink_msg_airspeed_autocal.h" #ifdef __cplusplus } diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_ahrs.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_ahrs.h index d9d2ccb04181f8896b31e1574fafd0e04002097b..c3ead1140135a2d84e61a57b351f3b106d5de22c 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_ahrs.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_ahrs.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_ahrs_pack(uint8_t system_id, uint8_t componen * @brief Pack a ahrs message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param omegaIx X gyro drift estimate rad/s * @param omegaIy Y gyro drift estimate rad/s @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_ahrs_pack_chan(uint8_t system_id, uint8_t com } /** - * @brief Encode a ahrs struct into a message + * @brief Encode a ahrs struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_ahrs_encode(uint8_t system_id, uint8_t compon return mavlink_msg_ahrs_pack(system_id, component_id, msg, ahrs->omegaIx, ahrs->omegaIy, ahrs->omegaIz, ahrs->accel_weight, ahrs->renorm_val, ahrs->error_rp, ahrs->error_yaw); } +/** + * @brief Encode a ahrs struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param ahrs C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_ahrs_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_ahrs_t* ahrs) +{ + return mavlink_msg_ahrs_pack_chan(system_id, component_id, chan, msg, ahrs->omegaIx, ahrs->omegaIy, ahrs->omegaIz, ahrs->accel_weight, ahrs->renorm_val, ahrs->error_rp, ahrs->error_yaw); +} + /** * @brief Send a ahrs message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_airspeed_autocal.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_airspeed_autocal.h new file mode 100644 index 0000000000000000000000000000000000000000..d046f2ad090dce9735806e9b5935fbed1af6f363 --- /dev/null +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_airspeed_autocal.h @@ -0,0 +1,419 @@ +// MESSAGE AIRSPEED_AUTOCAL PACKING + +#define MAVLINK_MSG_ID_AIRSPEED_AUTOCAL 174 + +typedef struct __mavlink_airspeed_autocal_t +{ + float vx; ///< GPS velocity north m/s + float vy; ///< GPS velocity east m/s + float vz; ///< GPS velocity down m/s + float diff_pressure; ///< Differential pressure pascals + float EAS2TAS; ///< Estimated to true airspeed ratio + float ratio; ///< Airspeed ratio + float state_x; ///< EKF state x + float state_y; ///< EKF state y + float state_z; ///< EKF state z + float Pax; ///< EKF Pax + float Pby; ///< EKF Pby + float Pcz; ///< EKF Pcz +} mavlink_airspeed_autocal_t; + +#define MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN 48 +#define MAVLINK_MSG_ID_174_LEN 48 + +#define MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC 167 +#define MAVLINK_MSG_ID_174_CRC 167 + + + +#define MAVLINK_MESSAGE_INFO_AIRSPEED_AUTOCAL { \ + "AIRSPEED_AUTOCAL", \ + 12, \ + { { "vx", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_airspeed_autocal_t, vx) }, \ + { "vy", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_airspeed_autocal_t, vy) }, \ + { "vz", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_airspeed_autocal_t, vz) }, \ + { "diff_pressure", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_airspeed_autocal_t, diff_pressure) }, \ + { "EAS2TAS", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_airspeed_autocal_t, EAS2TAS) }, \ + { "ratio", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_airspeed_autocal_t, ratio) }, \ + { "state_x", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_airspeed_autocal_t, state_x) }, \ + { "state_y", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_airspeed_autocal_t, state_y) }, \ + { "state_z", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_airspeed_autocal_t, state_z) }, \ + { "Pax", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_airspeed_autocal_t, Pax) }, \ + { "Pby", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_airspeed_autocal_t, Pby) }, \ + { "Pcz", NULL, MAVLINK_TYPE_FLOAT, 0, 44, offsetof(mavlink_airspeed_autocal_t, Pcz) }, \ + } \ +} + + +/** + * @brief Pack a airspeed_autocal message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param vx GPS velocity north m/s + * @param vy GPS velocity east m/s + * @param vz GPS velocity down m/s + * @param diff_pressure Differential pressure pascals + * @param EAS2TAS Estimated to true airspeed ratio + * @param ratio Airspeed ratio + * @param state_x EKF state x + * @param state_y EKF state y + * @param state_z EKF state z + * @param Pax EKF Pax + * @param Pby EKF Pby + * @param Pcz EKF Pcz + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_airspeed_autocal_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + float vx, float vy, float vz, float diff_pressure, float EAS2TAS, float ratio, float state_x, float state_y, float state_z, float Pax, float Pby, float Pcz) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN]; + _mav_put_float(buf, 0, vx); + _mav_put_float(buf, 4, vy); + _mav_put_float(buf, 8, vz); + _mav_put_float(buf, 12, diff_pressure); + _mav_put_float(buf, 16, EAS2TAS); + _mav_put_float(buf, 20, ratio); + _mav_put_float(buf, 24, state_x); + _mav_put_float(buf, 28, state_y); + _mav_put_float(buf, 32, state_z); + _mav_put_float(buf, 36, Pax); + _mav_put_float(buf, 40, Pby); + _mav_put_float(buf, 44, Pcz); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); +#else + mavlink_airspeed_autocal_t packet; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.diff_pressure = diff_pressure; + packet.EAS2TAS = EAS2TAS; + packet.ratio = ratio; + packet.state_x = state_x; + packet.state_y = state_y; + packet.state_z = state_z; + packet.Pax = Pax; + packet.Pby = Pby; + packet.Pcz = Pcz; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_AIRSPEED_AUTOCAL; +#if MAVLINK_CRC_EXTRA + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC); +#else + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); +#endif +} + +/** + * @brief Pack a airspeed_autocal message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param vx GPS velocity north m/s + * @param vy GPS velocity east m/s + * @param vz GPS velocity down m/s + * @param diff_pressure Differential pressure pascals + * @param EAS2TAS Estimated to true airspeed ratio + * @param ratio Airspeed ratio + * @param state_x EKF state x + * @param state_y EKF state y + * @param state_z EKF state z + * @param Pax EKF Pax + * @param Pby EKF Pby + * @param Pcz EKF Pcz + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_airspeed_autocal_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + float vx,float vy,float vz,float diff_pressure,float EAS2TAS,float ratio,float state_x,float state_y,float state_z,float Pax,float Pby,float Pcz) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN]; + _mav_put_float(buf, 0, vx); + _mav_put_float(buf, 4, vy); + _mav_put_float(buf, 8, vz); + _mav_put_float(buf, 12, diff_pressure); + _mav_put_float(buf, 16, EAS2TAS); + _mav_put_float(buf, 20, ratio); + _mav_put_float(buf, 24, state_x); + _mav_put_float(buf, 28, state_y); + _mav_put_float(buf, 32, state_z); + _mav_put_float(buf, 36, Pax); + _mav_put_float(buf, 40, Pby); + _mav_put_float(buf, 44, Pcz); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); +#else + mavlink_airspeed_autocal_t packet; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.diff_pressure = diff_pressure; + packet.EAS2TAS = EAS2TAS; + packet.ratio = ratio; + packet.state_x = state_x; + packet.state_y = state_y; + packet.state_z = state_z; + packet.Pax = Pax; + packet.Pby = Pby; + packet.Pcz = Pcz; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_AIRSPEED_AUTOCAL; +#if MAVLINK_CRC_EXTRA + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC); +#else + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); +#endif +} + +/** + * @brief Encode a airspeed_autocal struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param airspeed_autocal C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_airspeed_autocal_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_airspeed_autocal_t* airspeed_autocal) +{ + return mavlink_msg_airspeed_autocal_pack(system_id, component_id, msg, airspeed_autocal->vx, airspeed_autocal->vy, airspeed_autocal->vz, airspeed_autocal->diff_pressure, airspeed_autocal->EAS2TAS, airspeed_autocal->ratio, airspeed_autocal->state_x, airspeed_autocal->state_y, airspeed_autocal->state_z, airspeed_autocal->Pax, airspeed_autocal->Pby, airspeed_autocal->Pcz); +} + +/** + * @brief Encode a airspeed_autocal struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param airspeed_autocal C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_airspeed_autocal_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_airspeed_autocal_t* airspeed_autocal) +{ + return mavlink_msg_airspeed_autocal_pack_chan(system_id, component_id, chan, msg, airspeed_autocal->vx, airspeed_autocal->vy, airspeed_autocal->vz, airspeed_autocal->diff_pressure, airspeed_autocal->EAS2TAS, airspeed_autocal->ratio, airspeed_autocal->state_x, airspeed_autocal->state_y, airspeed_autocal->state_z, airspeed_autocal->Pax, airspeed_autocal->Pby, airspeed_autocal->Pcz); +} + +/** + * @brief Send a airspeed_autocal message + * @param chan MAVLink channel to send the message + * + * @param vx GPS velocity north m/s + * @param vy GPS velocity east m/s + * @param vz GPS velocity down m/s + * @param diff_pressure Differential pressure pascals + * @param EAS2TAS Estimated to true airspeed ratio + * @param ratio Airspeed ratio + * @param state_x EKF state x + * @param state_y EKF state y + * @param state_z EKF state z + * @param Pax EKF Pax + * @param Pby EKF Pby + * @param Pcz EKF Pcz + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_airspeed_autocal_send(mavlink_channel_t chan, float vx, float vy, float vz, float diff_pressure, float EAS2TAS, float ratio, float state_x, float state_y, float state_z, float Pax, float Pby, float Pcz) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN]; + _mav_put_float(buf, 0, vx); + _mav_put_float(buf, 4, vy); + _mav_put_float(buf, 8, vz); + _mav_put_float(buf, 12, diff_pressure); + _mav_put_float(buf, 16, EAS2TAS); + _mav_put_float(buf, 20, ratio); + _mav_put_float(buf, 24, state_x); + _mav_put_float(buf, 28, state_y); + _mav_put_float(buf, 32, state_z); + _mav_put_float(buf, 36, Pax); + _mav_put_float(buf, 40, Pby); + _mav_put_float(buf, 44, Pcz); + +#if MAVLINK_CRC_EXTRA + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL, buf, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL, buf, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); +#endif +#else + mavlink_airspeed_autocal_t packet; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.diff_pressure = diff_pressure; + packet.EAS2TAS = EAS2TAS; + packet.ratio = ratio; + packet.state_x = state_x; + packet.state_y = state_y; + packet.state_z = state_z; + packet.Pax = Pax; + packet.Pby = Pby; + packet.Pcz = Pcz; + +#if MAVLINK_CRC_EXTRA + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL, (const char *)&packet, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL, (const char *)&packet, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); +#endif +#endif +} + +#endif + +// MESSAGE AIRSPEED_AUTOCAL UNPACKING + + +/** + * @brief Get field vx from airspeed_autocal message + * + * @return GPS velocity north m/s + */ +static inline float mavlink_msg_airspeed_autocal_get_vx(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 0); +} + +/** + * @brief Get field vy from airspeed_autocal message + * + * @return GPS velocity east m/s + */ +static inline float mavlink_msg_airspeed_autocal_get_vy(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 4); +} + +/** + * @brief Get field vz from airspeed_autocal message + * + * @return GPS velocity down m/s + */ +static inline float mavlink_msg_airspeed_autocal_get_vz(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 8); +} + +/** + * @brief Get field diff_pressure from airspeed_autocal message + * + * @return Differential pressure pascals + */ +static inline float mavlink_msg_airspeed_autocal_get_diff_pressure(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 12); +} + +/** + * @brief Get field EAS2TAS from airspeed_autocal message + * + * @return Estimated to true airspeed ratio + */ +static inline float mavlink_msg_airspeed_autocal_get_EAS2TAS(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 16); +} + +/** + * @brief Get field ratio from airspeed_autocal message + * + * @return Airspeed ratio + */ +static inline float mavlink_msg_airspeed_autocal_get_ratio(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 20); +} + +/** + * @brief Get field state_x from airspeed_autocal message + * + * @return EKF state x + */ +static inline float mavlink_msg_airspeed_autocal_get_state_x(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 24); +} + +/** + * @brief Get field state_y from airspeed_autocal message + * + * @return EKF state y + */ +static inline float mavlink_msg_airspeed_autocal_get_state_y(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 28); +} + +/** + * @brief Get field state_z from airspeed_autocal message + * + * @return EKF state z + */ +static inline float mavlink_msg_airspeed_autocal_get_state_z(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 32); +} + +/** + * @brief Get field Pax from airspeed_autocal message + * + * @return EKF Pax + */ +static inline float mavlink_msg_airspeed_autocal_get_Pax(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 36); +} + +/** + * @brief Get field Pby from airspeed_autocal message + * + * @return EKF Pby + */ +static inline float mavlink_msg_airspeed_autocal_get_Pby(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 40); +} + +/** + * @brief Get field Pcz from airspeed_autocal message + * + * @return EKF Pcz + */ +static inline float mavlink_msg_airspeed_autocal_get_Pcz(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 44); +} + +/** + * @brief Decode a airspeed_autocal message into a struct + * + * @param msg The message to decode + * @param airspeed_autocal C-struct to decode the message contents into + */ +static inline void mavlink_msg_airspeed_autocal_decode(const mavlink_message_t* msg, mavlink_airspeed_autocal_t* airspeed_autocal) +{ +#if MAVLINK_NEED_BYTE_SWAP + airspeed_autocal->vx = mavlink_msg_airspeed_autocal_get_vx(msg); + airspeed_autocal->vy = mavlink_msg_airspeed_autocal_get_vy(msg); + airspeed_autocal->vz = mavlink_msg_airspeed_autocal_get_vz(msg); + airspeed_autocal->diff_pressure = mavlink_msg_airspeed_autocal_get_diff_pressure(msg); + airspeed_autocal->EAS2TAS = mavlink_msg_airspeed_autocal_get_EAS2TAS(msg); + airspeed_autocal->ratio = mavlink_msg_airspeed_autocal_get_ratio(msg); + airspeed_autocal->state_x = mavlink_msg_airspeed_autocal_get_state_x(msg); + airspeed_autocal->state_y = mavlink_msg_airspeed_autocal_get_state_y(msg); + airspeed_autocal->state_z = mavlink_msg_airspeed_autocal_get_state_z(msg); + airspeed_autocal->Pax = mavlink_msg_airspeed_autocal_get_Pax(msg); + airspeed_autocal->Pby = mavlink_msg_airspeed_autocal_get_Pby(msg); + airspeed_autocal->Pcz = mavlink_msg_airspeed_autocal_get_Pcz(msg); +#else + memcpy(airspeed_autocal, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); +#endif +} diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_ap_adc.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_ap_adc.h index c6c76245139f24354affb49931cb88ef3d28ee79..821ce73e4798195038ad2e15803f05478adc3b5b 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_ap_adc.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_ap_adc.h @@ -84,7 +84,7 @@ static inline uint16_t mavlink_msg_ap_adc_pack(uint8_t system_id, uint8_t compon * @brief Pack a ap_adc message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param adc1 ADC output 1 * @param adc2 ADC output 2 @@ -129,7 +129,7 @@ static inline uint16_t mavlink_msg_ap_adc_pack_chan(uint8_t system_id, uint8_t c } /** - * @brief Encode a ap_adc struct into a message + * @brief Encode a ap_adc struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -141,6 +141,20 @@ static inline uint16_t mavlink_msg_ap_adc_encode(uint8_t system_id, uint8_t comp return mavlink_msg_ap_adc_pack(system_id, component_id, msg, ap_adc->adc1, ap_adc->adc2, ap_adc->adc3, ap_adc->adc4, ap_adc->adc5, ap_adc->adc6); } +/** + * @brief Encode a ap_adc struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param ap_adc C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_ap_adc_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_ap_adc_t* ap_adc) +{ + return mavlink_msg_ap_adc_pack_chan(system_id, component_id, chan, msg, ap_adc->adc1, ap_adc->adc2, ap_adc->adc3, ap_adc->adc4, ap_adc->adc5, ap_adc->adc6); +} + /** * @brief Send a ap_adc message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_data16.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_data16.h index c75358526764784ce8f42e6bdea52cf99658008c..9200eefa0dc0ad6d1615c58f05e74ce101b8e88c 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_data16.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_data16.h @@ -67,7 +67,7 @@ static inline uint16_t mavlink_msg_data16_pack(uint8_t system_id, uint8_t compon * @brief Pack a data16 message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param type data type * @param len data length @@ -101,7 +101,7 @@ static inline uint16_t mavlink_msg_data16_pack_chan(uint8_t system_id, uint8_t c } /** - * @brief Encode a data16 struct into a message + * @brief Encode a data16 struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -113,6 +113,20 @@ static inline uint16_t mavlink_msg_data16_encode(uint8_t system_id, uint8_t comp return mavlink_msg_data16_pack(system_id, component_id, msg, data16->type, data16->len, data16->data); } +/** + * @brief Encode a data16 struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param data16 C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_data16_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_data16_t* data16) +{ + return mavlink_msg_data16_pack_chan(system_id, component_id, chan, msg, data16->type, data16->len, data16->data); +} + /** * @brief Send a data16 message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_data32.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_data32.h index 46c804a3c2eaab3ee9767e0a8640d6eb8a232023..3afedb7874300737e20d56128e0aa06192f97a61 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_data32.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_data32.h @@ -67,7 +67,7 @@ static inline uint16_t mavlink_msg_data32_pack(uint8_t system_id, uint8_t compon * @brief Pack a data32 message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param type data type * @param len data length @@ -101,7 +101,7 @@ static inline uint16_t mavlink_msg_data32_pack_chan(uint8_t system_id, uint8_t c } /** - * @brief Encode a data32 struct into a message + * @brief Encode a data32 struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -113,6 +113,20 @@ static inline uint16_t mavlink_msg_data32_encode(uint8_t system_id, uint8_t comp return mavlink_msg_data32_pack(system_id, component_id, msg, data32->type, data32->len, data32->data); } +/** + * @brief Encode a data32 struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param data32 C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_data32_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_data32_t* data32) +{ + return mavlink_msg_data32_pack_chan(system_id, component_id, chan, msg, data32->type, data32->len, data32->data); +} + /** * @brief Send a data32 message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_data64.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_data64.h index 843084dffa9540bd2b9ce48c97c82b2e92661469..6931ada167d274a48e911fc038dc020c11fe4b82 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_data64.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_data64.h @@ -67,7 +67,7 @@ static inline uint16_t mavlink_msg_data64_pack(uint8_t system_id, uint8_t compon * @brief Pack a data64 message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param type data type * @param len data length @@ -101,7 +101,7 @@ static inline uint16_t mavlink_msg_data64_pack_chan(uint8_t system_id, uint8_t c } /** - * @brief Encode a data64 struct into a message + * @brief Encode a data64 struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -113,6 +113,20 @@ static inline uint16_t mavlink_msg_data64_encode(uint8_t system_id, uint8_t comp return mavlink_msg_data64_pack(system_id, component_id, msg, data64->type, data64->len, data64->data); } +/** + * @brief Encode a data64 struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param data64 C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_data64_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_data64_t* data64) +{ + return mavlink_msg_data64_pack_chan(system_id, component_id, chan, msg, data64->type, data64->len, data64->data); +} + /** * @brief Send a data64 message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_data96.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_data96.h index 095628865cf551c80ce1383645a9344707563470..cffc7d7e7fc782425f65d84be9fe7bb9ae78f7df 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_data96.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_data96.h @@ -67,7 +67,7 @@ static inline uint16_t mavlink_msg_data96_pack(uint8_t system_id, uint8_t compon * @brief Pack a data96 message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param type data type * @param len data length @@ -101,7 +101,7 @@ static inline uint16_t mavlink_msg_data96_pack_chan(uint8_t system_id, uint8_t c } /** - * @brief Encode a data96 struct into a message + * @brief Encode a data96 struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -113,6 +113,20 @@ static inline uint16_t mavlink_msg_data96_encode(uint8_t system_id, uint8_t comp return mavlink_msg_data96_pack(system_id, component_id, msg, data96->type, data96->len, data96->data); } +/** + * @brief Encode a data96 struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param data96 C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_data96_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_data96_t* data96) +{ + return mavlink_msg_data96_pack_chan(system_id, component_id, chan, msg, data96->type, data96->len, data96->data); +} + /** * @brief Send a data96 message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_digicam_configure.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_digicam_configure.h index bcc706a887d8266c7f1187ea0b20581a421c8922..c6518c41995f765fd873cf5e66c43dca209d5182 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_digicam_configure.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_digicam_configure.h @@ -109,7 +109,7 @@ static inline uint16_t mavlink_msg_digicam_configure_pack(uint8_t system_id, uin * @brief Pack a digicam_configure message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -169,7 +169,7 @@ static inline uint16_t mavlink_msg_digicam_configure_pack_chan(uint8_t system_id } /** - * @brief Encode a digicam_configure struct into a message + * @brief Encode a digicam_configure struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -181,6 +181,20 @@ static inline uint16_t mavlink_msg_digicam_configure_encode(uint8_t system_id, u return mavlink_msg_digicam_configure_pack(system_id, component_id, msg, digicam_configure->target_system, digicam_configure->target_component, digicam_configure->mode, digicam_configure->shutter_speed, digicam_configure->aperture, digicam_configure->iso, digicam_configure->exposure_type, digicam_configure->command_id, digicam_configure->engine_cut_off, digicam_configure->extra_param, digicam_configure->extra_value); } +/** + * @brief Encode a digicam_configure struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param digicam_configure C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_digicam_configure_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_digicam_configure_t* digicam_configure) +{ + return mavlink_msg_digicam_configure_pack_chan(system_id, component_id, chan, msg, digicam_configure->target_system, digicam_configure->target_component, digicam_configure->mode, digicam_configure->shutter_speed, digicam_configure->aperture, digicam_configure->iso, digicam_configure->exposure_type, digicam_configure->command_id, digicam_configure->engine_cut_off, digicam_configure->extra_param, digicam_configure->extra_value); +} + /** * @brief Send a digicam_configure message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_digicam_control.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_digicam_control.h index 7fa8cdfef8696261eeb41dbbf30915c9b791fcf1..bfa5414a39414f696355e6d39d74f1c5922bdf30 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_digicam_control.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_digicam_control.h @@ -104,7 +104,7 @@ static inline uint16_t mavlink_msg_digicam_control_pack(uint8_t system_id, uint8 * @brief Pack a digicam_control message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -161,7 +161,7 @@ static inline uint16_t mavlink_msg_digicam_control_pack_chan(uint8_t system_id, } /** - * @brief Encode a digicam_control struct into a message + * @brief Encode a digicam_control struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -173,6 +173,20 @@ static inline uint16_t mavlink_msg_digicam_control_encode(uint8_t system_id, uin return mavlink_msg_digicam_control_pack(system_id, component_id, msg, digicam_control->target_system, digicam_control->target_component, digicam_control->session, digicam_control->zoom_pos, digicam_control->zoom_step, digicam_control->focus_lock, digicam_control->shot, digicam_control->command_id, digicam_control->extra_param, digicam_control->extra_value); } +/** + * @brief Encode a digicam_control struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param digicam_control C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_digicam_control_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_digicam_control_t* digicam_control) +{ + return mavlink_msg_digicam_control_pack_chan(system_id, component_id, chan, msg, digicam_control->target_system, digicam_control->target_component, digicam_control->session, digicam_control->zoom_pos, digicam_control->zoom_step, digicam_control->focus_lock, digicam_control->shot, digicam_control->command_id, digicam_control->extra_param, digicam_control->extra_value); +} + /** * @brief Send a digicam_control message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_fence_fetch_point.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_fence_fetch_point.h index 2cd4fc798ca9ca9fa3066bddfd451b1b649251f2..fe3677d53d73138da19d0e7427f65eb792293782 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_fence_fetch_point.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_fence_fetch_point.h @@ -69,7 +69,7 @@ static inline uint16_t mavlink_msg_fence_fetch_point_pack(uint8_t system_id, uin * @brief Pack a fence_fetch_point message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -105,7 +105,7 @@ static inline uint16_t mavlink_msg_fence_fetch_point_pack_chan(uint8_t system_id } /** - * @brief Encode a fence_fetch_point struct into a message + * @brief Encode a fence_fetch_point struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -117,6 +117,20 @@ static inline uint16_t mavlink_msg_fence_fetch_point_encode(uint8_t system_id, u return mavlink_msg_fence_fetch_point_pack(system_id, component_id, msg, fence_fetch_point->target_system, fence_fetch_point->target_component, fence_fetch_point->idx); } +/** + * @brief Encode a fence_fetch_point struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param fence_fetch_point C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_fence_fetch_point_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_fence_fetch_point_t* fence_fetch_point) +{ + return mavlink_msg_fence_fetch_point_pack_chan(system_id, component_id, chan, msg, fence_fetch_point->target_system, fence_fetch_point->target_component, fence_fetch_point->idx); +} + /** * @brief Send a fence_fetch_point message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_fence_point.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_fence_point.h index b3c4706ee092b386d3aab5e20c0f484fada03a97..febda6cdc5c177f1337ce24e61c2eaaf3e845851 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_fence_point.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_fence_point.h @@ -84,7 +84,7 @@ static inline uint16_t mavlink_msg_fence_point_pack(uint8_t system_id, uint8_t c * @brief Pack a fence_point message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -129,7 +129,7 @@ static inline uint16_t mavlink_msg_fence_point_pack_chan(uint8_t system_id, uint } /** - * @brief Encode a fence_point struct into a message + * @brief Encode a fence_point struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -141,6 +141,20 @@ static inline uint16_t mavlink_msg_fence_point_encode(uint8_t system_id, uint8_t return mavlink_msg_fence_point_pack(system_id, component_id, msg, fence_point->target_system, fence_point->target_component, fence_point->idx, fence_point->count, fence_point->lat, fence_point->lng); } +/** + * @brief Encode a fence_point struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param fence_point C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_fence_point_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_fence_point_t* fence_point) +{ + return mavlink_msg_fence_point_pack_chan(system_id, component_id, chan, msg, fence_point->target_system, fence_point->target_component, fence_point->idx, fence_point->count, fence_point->lat, fence_point->lng); +} + /** * @brief Send a fence_point message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_fence_status.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_fence_status.h index 32f2bc03a8b709c7afca90e0e2fba3cb0cc2fea1..61209040616a05e9a1a1bcbaacf2a7e95edd79ad 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_fence_status.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_fence_status.h @@ -74,7 +74,7 @@ static inline uint16_t mavlink_msg_fence_status_pack(uint8_t system_id, uint8_t * @brief Pack a fence_status message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param breach_status 0 if currently inside fence, 1 if outside * @param breach_count number of fence breaches @@ -113,7 +113,7 @@ static inline uint16_t mavlink_msg_fence_status_pack_chan(uint8_t system_id, uin } /** - * @brief Encode a fence_status struct into a message + * @brief Encode a fence_status struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -125,6 +125,20 @@ static inline uint16_t mavlink_msg_fence_status_encode(uint8_t system_id, uint8_ return mavlink_msg_fence_status_pack(system_id, component_id, msg, fence_status->breach_status, fence_status->breach_count, fence_status->breach_type, fence_status->breach_time); } +/** + * @brief Encode a fence_status struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param fence_status C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_fence_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_fence_status_t* fence_status) +{ + return mavlink_msg_fence_status_pack_chan(system_id, component_id, chan, msg, fence_status->breach_status, fence_status->breach_count, fence_status->breach_type, fence_status->breach_time); +} + /** * @brief Send a fence_status message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_hwstatus.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_hwstatus.h index 73870ec0fb7c1a38d06acfbefedb780fd4c3b44d..2f5dea513afe161c8bca2abdbdd776a408d86527 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_hwstatus.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_hwstatus.h @@ -64,7 +64,7 @@ static inline uint16_t mavlink_msg_hwstatus_pack(uint8_t system_id, uint8_t comp * @brief Pack a hwstatus message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param Vcc board voltage (mV) * @param I2Cerr I2C error count @@ -97,7 +97,7 @@ static inline uint16_t mavlink_msg_hwstatus_pack_chan(uint8_t system_id, uint8_t } /** - * @brief Encode a hwstatus struct into a message + * @brief Encode a hwstatus struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -109,6 +109,20 @@ static inline uint16_t mavlink_msg_hwstatus_encode(uint8_t system_id, uint8_t co return mavlink_msg_hwstatus_pack(system_id, component_id, msg, hwstatus->Vcc, hwstatus->I2Cerr); } +/** + * @brief Encode a hwstatus struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param hwstatus C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_hwstatus_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_hwstatus_t* hwstatus) +{ + return mavlink_msg_hwstatus_pack_chan(system_id, component_id, chan, msg, hwstatus->Vcc, hwstatus->I2Cerr); +} + /** * @brief Send a hwstatus message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_limits_status.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_limits_status.h index f7b04fba71a8799ae8be1cd5c32570b0358f3905..34743fd0216106fb022e3574e42a6c35534d1a57 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_limits_status.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_limits_status.h @@ -99,7 +99,7 @@ static inline uint16_t mavlink_msg_limits_status_pack(uint8_t system_id, uint8_t * @brief Pack a limits_status message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param limits_state state of AP_Limits, (see enum LimitState, LIMITS_STATE) * @param last_trigger time of last breach in milliseconds since boot @@ -153,7 +153,7 @@ static inline uint16_t mavlink_msg_limits_status_pack_chan(uint8_t system_id, ui } /** - * @brief Encode a limits_status struct into a message + * @brief Encode a limits_status struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -165,6 +165,20 @@ static inline uint16_t mavlink_msg_limits_status_encode(uint8_t system_id, uint8 return mavlink_msg_limits_status_pack(system_id, component_id, msg, limits_status->limits_state, limits_status->last_trigger, limits_status->last_action, limits_status->last_recovery, limits_status->last_clear, limits_status->breach_count, limits_status->mods_enabled, limits_status->mods_required, limits_status->mods_triggered); } +/** + * @brief Encode a limits_status struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param limits_status C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_limits_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_limits_status_t* limits_status) +{ + return mavlink_msg_limits_status_pack_chan(system_id, component_id, chan, msg, limits_status->limits_state, limits_status->last_trigger, limits_status->last_action, limits_status->last_recovery, limits_status->last_clear, limits_status->breach_count, limits_status->mods_enabled, limits_status->mods_required, limits_status->mods_triggered); +} + /** * @brief Send a limits_status message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_meminfo.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_meminfo.h index 437029eed7732f3ad5e7b62436cbfa408e6d0684..55f772bbc5c06836799040a11f511ea86fe641ec 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_meminfo.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_meminfo.h @@ -64,7 +64,7 @@ static inline uint16_t mavlink_msg_meminfo_pack(uint8_t system_id, uint8_t compo * @brief Pack a meminfo message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param brkval heap top * @param freemem free memory @@ -97,7 +97,7 @@ static inline uint16_t mavlink_msg_meminfo_pack_chan(uint8_t system_id, uint8_t } /** - * @brief Encode a meminfo struct into a message + * @brief Encode a meminfo struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -109,6 +109,20 @@ static inline uint16_t mavlink_msg_meminfo_encode(uint8_t system_id, uint8_t com return mavlink_msg_meminfo_pack(system_id, component_id, msg, meminfo->brkval, meminfo->freemem); } +/** + * @brief Encode a meminfo struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param meminfo C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_meminfo_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_meminfo_t* meminfo) +{ + return mavlink_msg_meminfo_pack_chan(system_id, component_id, chan, msg, meminfo->brkval, meminfo->freemem); +} + /** * @brief Send a meminfo message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_mount_configure.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_mount_configure.h index 450153c6fe5bd2ab74f3f7be69b55a9a71671737..de717dfa4dc0a79e3de5a16286268fbdc01cb6c6 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_mount_configure.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_mount_configure.h @@ -84,7 +84,7 @@ static inline uint16_t mavlink_msg_mount_configure_pack(uint8_t system_id, uint8 * @brief Pack a mount_configure message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -129,7 +129,7 @@ static inline uint16_t mavlink_msg_mount_configure_pack_chan(uint8_t system_id, } /** - * @brief Encode a mount_configure struct into a message + * @brief Encode a mount_configure struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -141,6 +141,20 @@ static inline uint16_t mavlink_msg_mount_configure_encode(uint8_t system_id, uin return mavlink_msg_mount_configure_pack(system_id, component_id, msg, mount_configure->target_system, mount_configure->target_component, mount_configure->mount_mode, mount_configure->stab_roll, mount_configure->stab_pitch, mount_configure->stab_yaw); } +/** + * @brief Encode a mount_configure struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param mount_configure C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mount_configure_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mount_configure_t* mount_configure) +{ + return mavlink_msg_mount_configure_pack_chan(system_id, component_id, chan, msg, mount_configure->target_system, mount_configure->target_component, mount_configure->mount_mode, mount_configure->stab_roll, mount_configure->stab_pitch, mount_configure->stab_yaw); +} + /** * @brief Send a mount_configure message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_mount_control.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_mount_control.h index 5b83d7e970da56f5c12f3951be0d7ef9bf15638b..44416353ed4e99cedff6bf6416dcda49b7e91d5a 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_mount_control.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_mount_control.h @@ -84,7 +84,7 @@ static inline uint16_t mavlink_msg_mount_control_pack(uint8_t system_id, uint8_t * @brief Pack a mount_control message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -129,7 +129,7 @@ static inline uint16_t mavlink_msg_mount_control_pack_chan(uint8_t system_id, ui } /** - * @brief Encode a mount_control struct into a message + * @brief Encode a mount_control struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -141,6 +141,20 @@ static inline uint16_t mavlink_msg_mount_control_encode(uint8_t system_id, uint8 return mavlink_msg_mount_control_pack(system_id, component_id, msg, mount_control->target_system, mount_control->target_component, mount_control->input_a, mount_control->input_b, mount_control->input_c, mount_control->save_position); } +/** + * @brief Encode a mount_control struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param mount_control C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mount_control_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mount_control_t* mount_control) +{ + return mavlink_msg_mount_control_pack_chan(system_id, component_id, chan, msg, mount_control->target_system, mount_control->target_component, mount_control->input_a, mount_control->input_b, mount_control->input_c, mount_control->save_position); +} + /** * @brief Send a mount_control message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_mount_status.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_mount_status.h index c031db42b43fa630d0a2eef8835c2e2233a8291e..4905905dc5429e5c719f273290c0a31577944076 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_mount_status.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_mount_status.h @@ -79,7 +79,7 @@ static inline uint16_t mavlink_msg_mount_status_pack(uint8_t system_id, uint8_t * @brief Pack a mount_status message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -121,7 +121,7 @@ static inline uint16_t mavlink_msg_mount_status_pack_chan(uint8_t system_id, uin } /** - * @brief Encode a mount_status struct into a message + * @brief Encode a mount_status struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -133,6 +133,20 @@ static inline uint16_t mavlink_msg_mount_status_encode(uint8_t system_id, uint8_ return mavlink_msg_mount_status_pack(system_id, component_id, msg, mount_status->target_system, mount_status->target_component, mount_status->pointing_a, mount_status->pointing_b, mount_status->pointing_c); } +/** + * @brief Encode a mount_status struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param mount_status C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mount_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mount_status_t* mount_status) +{ + return mavlink_msg_mount_status_pack_chan(system_id, component_id, chan, msg, mount_status->target_system, mount_status->target_component, mount_status->pointing_a, mount_status->pointing_b, mount_status->pointing_c); +} + /** * @brief Send a mount_status message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_radio.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_radio.h index e13776993e4a51472549ded94b0355261a47b46d..8e9740e82841f2c828f57e42614d728a61dd58e8 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_radio.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_radio.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_radio_pack(uint8_t system_id, uint8_t compone * @brief Pack a radio message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param rssi local signal strength * @param remrssi remote signal strength @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_radio_pack_chan(uint8_t system_id, uint8_t co } /** - * @brief Encode a radio struct into a message + * @brief Encode a radio struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_radio_encode(uint8_t system_id, uint8_t compo return mavlink_msg_radio_pack(system_id, component_id, msg, radio->rssi, radio->remrssi, radio->txbuf, radio->noise, radio->remnoise, radio->rxerrors, radio->fixed); } +/** + * @brief Encode a radio struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param radio C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_radio_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_radio_t* radio) +{ + return mavlink_msg_radio_pack_chan(system_id, component_id, chan, msg, radio->rssi, radio->remrssi, radio->txbuf, radio->noise, radio->remnoise, radio->rxerrors, radio->fixed); +} + /** * @brief Send a radio message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_rangefinder.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_rangefinder.h index d88abe36a424d180be2e692e18d516422f93057b..c476447a87874cab1d9b81100a7de62fe7b1207d 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_rangefinder.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_rangefinder.h @@ -64,7 +64,7 @@ static inline uint16_t mavlink_msg_rangefinder_pack(uint8_t system_id, uint8_t c * @brief Pack a rangefinder message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param distance distance in meters * @param voltage raw voltage if available, zero otherwise @@ -97,7 +97,7 @@ static inline uint16_t mavlink_msg_rangefinder_pack_chan(uint8_t system_id, uint } /** - * @brief Encode a rangefinder struct into a message + * @brief Encode a rangefinder struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -109,6 +109,20 @@ static inline uint16_t mavlink_msg_rangefinder_encode(uint8_t system_id, uint8_t return mavlink_msg_rangefinder_pack(system_id, component_id, msg, rangefinder->distance, rangefinder->voltage); } +/** + * @brief Encode a rangefinder struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param rangefinder C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_rangefinder_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_rangefinder_t* rangefinder) +{ + return mavlink_msg_rangefinder_pack_chan(system_id, component_id, chan, msg, rangefinder->distance, rangefinder->voltage); +} + /** * @brief Send a rangefinder message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_sensor_offsets.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_sensor_offsets.h index d121e48e6670b1340cc52fc1fae1352e77e2aadb..31b7d989de2849e0aad271e360ba62272e910bd4 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_sensor_offsets.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_sensor_offsets.h @@ -114,7 +114,7 @@ static inline uint16_t mavlink_msg_sensor_offsets_pack(uint8_t system_id, uint8_ * @brief Pack a sensor_offsets message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param mag_ofs_x magnetometer X offset * @param mag_ofs_y magnetometer Y offset @@ -177,7 +177,7 @@ static inline uint16_t mavlink_msg_sensor_offsets_pack_chan(uint8_t system_id, u } /** - * @brief Encode a sensor_offsets struct into a message + * @brief Encode a sensor_offsets struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -189,6 +189,20 @@ static inline uint16_t mavlink_msg_sensor_offsets_encode(uint8_t system_id, uint return mavlink_msg_sensor_offsets_pack(system_id, component_id, msg, sensor_offsets->mag_ofs_x, sensor_offsets->mag_ofs_y, sensor_offsets->mag_ofs_z, sensor_offsets->mag_declination, sensor_offsets->raw_press, sensor_offsets->raw_temp, sensor_offsets->gyro_cal_x, sensor_offsets->gyro_cal_y, sensor_offsets->gyro_cal_z, sensor_offsets->accel_cal_x, sensor_offsets->accel_cal_y, sensor_offsets->accel_cal_z); } +/** + * @brief Encode a sensor_offsets struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param sensor_offsets C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_sensor_offsets_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_sensor_offsets_t* sensor_offsets) +{ + return mavlink_msg_sensor_offsets_pack_chan(system_id, component_id, chan, msg, sensor_offsets->mag_ofs_x, sensor_offsets->mag_ofs_y, sensor_offsets->mag_ofs_z, sensor_offsets->mag_declination, sensor_offsets->raw_press, sensor_offsets->raw_temp, sensor_offsets->gyro_cal_x, sensor_offsets->gyro_cal_y, sensor_offsets->gyro_cal_z, sensor_offsets->accel_cal_x, sensor_offsets->accel_cal_y, sensor_offsets->accel_cal_z); +} + /** * @brief Send a sensor_offsets message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_set_mag_offsets.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_set_mag_offsets.h index a59e9064947c211656afb510455a2329166fbaf7..b2c629c39a0a1aaa493d8be517485179a3679c40 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_set_mag_offsets.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_set_mag_offsets.h @@ -79,7 +79,7 @@ static inline uint16_t mavlink_msg_set_mag_offsets_pack(uint8_t system_id, uint8 * @brief Pack a set_mag_offsets message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -121,7 +121,7 @@ static inline uint16_t mavlink_msg_set_mag_offsets_pack_chan(uint8_t system_id, } /** - * @brief Encode a set_mag_offsets struct into a message + * @brief Encode a set_mag_offsets struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -133,6 +133,20 @@ static inline uint16_t mavlink_msg_set_mag_offsets_encode(uint8_t system_id, uin return mavlink_msg_set_mag_offsets_pack(system_id, component_id, msg, set_mag_offsets->target_system, set_mag_offsets->target_component, set_mag_offsets->mag_ofs_x, set_mag_offsets->mag_ofs_y, set_mag_offsets->mag_ofs_z); } +/** + * @brief Encode a set_mag_offsets struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param set_mag_offsets C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_set_mag_offsets_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_mag_offsets_t* set_mag_offsets) +{ + return mavlink_msg_set_mag_offsets_pack_chan(system_id, component_id, chan, msg, set_mag_offsets->target_system, set_mag_offsets->target_component, set_mag_offsets->mag_ofs_x, set_mag_offsets->mag_ofs_y, set_mag_offsets->mag_ofs_z); +} + /** * @brief Send a set_mag_offsets message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_simstate.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_simstate.h index 7373c8bffedb0a16cdf1d4f84224c97d00134d93..8ef44f76d55d40c6e9ef1add3769763c2d1caa70 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_simstate.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_simstate.h @@ -13,15 +13,15 @@ typedef struct __mavlink_simstate_t float xgyro; ///< Angular speed around X axis rad/s float ygyro; ///< Angular speed around Y axis rad/s float zgyro; ///< Angular speed around Z axis rad/s - float lat; ///< Latitude in degrees - float lng; ///< Longitude in degrees + int32_t lat; ///< Latitude in degrees * 1E7 + int32_t lng; ///< Longitude in degrees * 1E7 } mavlink_simstate_t; #define MAVLINK_MSG_ID_SIMSTATE_LEN 44 #define MAVLINK_MSG_ID_164_LEN 44 -#define MAVLINK_MSG_ID_SIMSTATE_CRC 111 -#define MAVLINK_MSG_ID_164_CRC 111 +#define MAVLINK_MSG_ID_SIMSTATE_CRC 154 +#define MAVLINK_MSG_ID_164_CRC 154 @@ -37,8 +37,8 @@ typedef struct __mavlink_simstate_t { "xgyro", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_simstate_t, xgyro) }, \ { "ygyro", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_simstate_t, ygyro) }, \ { "zgyro", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_simstate_t, zgyro) }, \ - { "lat", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_simstate_t, lat) }, \ - { "lng", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_simstate_t, lng) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 36, offsetof(mavlink_simstate_t, lat) }, \ + { "lng", NULL, MAVLINK_TYPE_INT32_T, 0, 40, offsetof(mavlink_simstate_t, lng) }, \ } \ } @@ -58,12 +58,12 @@ typedef struct __mavlink_simstate_t * @param xgyro Angular speed around X axis rad/s * @param ygyro Angular speed around Y axis rad/s * @param zgyro Angular speed around Z axis rad/s - * @param lat Latitude in degrees - * @param lng Longitude in degrees + * @param lat Latitude in degrees * 1E7 + * @param lng Longitude in degrees * 1E7 * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_simstate_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - float roll, float pitch, float yaw, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, float lat, float lng) + float roll, float pitch, float yaw, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, int32_t lat, int32_t lng) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS char buf[MAVLINK_MSG_ID_SIMSTATE_LEN]; @@ -76,8 +76,8 @@ static inline uint16_t mavlink_msg_simstate_pack(uint8_t system_id, uint8_t comp _mav_put_float(buf, 24, xgyro); _mav_put_float(buf, 28, ygyro); _mav_put_float(buf, 32, zgyro); - _mav_put_float(buf, 36, lat); - _mav_put_float(buf, 40, lng); + _mav_put_int32_t(buf, 36, lat); + _mav_put_int32_t(buf, 40, lng); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SIMSTATE_LEN); #else @@ -109,7 +109,7 @@ static inline uint16_t mavlink_msg_simstate_pack(uint8_t system_id, uint8_t comp * @brief Pack a simstate message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param roll Roll angle (rad) * @param pitch Pitch angle (rad) @@ -120,13 +120,13 @@ static inline uint16_t mavlink_msg_simstate_pack(uint8_t system_id, uint8_t comp * @param xgyro Angular speed around X axis rad/s * @param ygyro Angular speed around Y axis rad/s * @param zgyro Angular speed around Z axis rad/s - * @param lat Latitude in degrees - * @param lng Longitude in degrees + * @param lat Latitude in degrees * 1E7 + * @param lng Longitude in degrees * 1E7 * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_simstate_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, - float roll,float pitch,float yaw,float xacc,float yacc,float zacc,float xgyro,float ygyro,float zgyro,float lat,float lng) + float roll,float pitch,float yaw,float xacc,float yacc,float zacc,float xgyro,float ygyro,float zgyro,int32_t lat,int32_t lng) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS char buf[MAVLINK_MSG_ID_SIMSTATE_LEN]; @@ -139,8 +139,8 @@ static inline uint16_t mavlink_msg_simstate_pack_chan(uint8_t system_id, uint8_t _mav_put_float(buf, 24, xgyro); _mav_put_float(buf, 28, ygyro); _mav_put_float(buf, 32, zgyro); - _mav_put_float(buf, 36, lat); - _mav_put_float(buf, 40, lng); + _mav_put_int32_t(buf, 36, lat); + _mav_put_int32_t(buf, 40, lng); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SIMSTATE_LEN); #else @@ -169,7 +169,7 @@ static inline uint16_t mavlink_msg_simstate_pack_chan(uint8_t system_id, uint8_t } /** - * @brief Encode a simstate struct into a message + * @brief Encode a simstate struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -181,6 +181,20 @@ static inline uint16_t mavlink_msg_simstate_encode(uint8_t system_id, uint8_t co return mavlink_msg_simstate_pack(system_id, component_id, msg, simstate->roll, simstate->pitch, simstate->yaw, simstate->xacc, simstate->yacc, simstate->zacc, simstate->xgyro, simstate->ygyro, simstate->zgyro, simstate->lat, simstate->lng); } +/** + * @brief Encode a simstate struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param simstate C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_simstate_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_simstate_t* simstate) +{ + return mavlink_msg_simstate_pack_chan(system_id, component_id, chan, msg, simstate->roll, simstate->pitch, simstate->yaw, simstate->xacc, simstate->yacc, simstate->zacc, simstate->xgyro, simstate->ygyro, simstate->zgyro, simstate->lat, simstate->lng); +} + /** * @brief Send a simstate message * @param chan MAVLink channel to send the message @@ -194,12 +208,12 @@ static inline uint16_t mavlink_msg_simstate_encode(uint8_t system_id, uint8_t co * @param xgyro Angular speed around X axis rad/s * @param ygyro Angular speed around Y axis rad/s * @param zgyro Angular speed around Z axis rad/s - * @param lat Latitude in degrees - * @param lng Longitude in degrees + * @param lat Latitude in degrees * 1E7 + * @param lng Longitude in degrees * 1E7 */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS -static inline void mavlink_msg_simstate_send(mavlink_channel_t chan, float roll, float pitch, float yaw, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, float lat, float lng) +static inline void mavlink_msg_simstate_send(mavlink_channel_t chan, float roll, float pitch, float yaw, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, int32_t lat, int32_t lng) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS char buf[MAVLINK_MSG_ID_SIMSTATE_LEN]; @@ -212,8 +226,8 @@ static inline void mavlink_msg_simstate_send(mavlink_channel_t chan, float roll, _mav_put_float(buf, 24, xgyro); _mav_put_float(buf, 28, ygyro); _mav_put_float(buf, 32, zgyro); - _mav_put_float(buf, 36, lat); - _mav_put_float(buf, 40, lng); + _mav_put_int32_t(buf, 36, lat); + _mav_put_int32_t(buf, 40, lng); #if MAVLINK_CRC_EXTRA _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIMSTATE, buf, MAVLINK_MSG_ID_SIMSTATE_LEN, MAVLINK_MSG_ID_SIMSTATE_CRC); @@ -340,21 +354,21 @@ static inline float mavlink_msg_simstate_get_zgyro(const mavlink_message_t* msg) /** * @brief Get field lat from simstate message * - * @return Latitude in degrees + * @return Latitude in degrees * 1E7 */ -static inline float mavlink_msg_simstate_get_lat(const mavlink_message_t* msg) +static inline int32_t mavlink_msg_simstate_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 36); + return _MAV_RETURN_int32_t(msg, 36); } /** * @brief Get field lng from simstate message * - * @return Longitude in degrees + * @return Longitude in degrees * 1E7 */ -static inline float mavlink_msg_simstate_get_lng(const mavlink_message_t* msg) +static inline int32_t mavlink_msg_simstate_get_lng(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 40); + return _MAV_RETURN_int32_t(msg, 40); } /** diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_wind.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_wind.h index ebdd2949d9e33a5713f2216d23c2005c3e93b53b..7608a7bd1070ec2fe33b1e1d735214abf92ec1dc 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_wind.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/mavlink_msg_wind.h @@ -69,7 +69,7 @@ static inline uint16_t mavlink_msg_wind_pack(uint8_t system_id, uint8_t componen * @brief Pack a wind message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param direction wind direction that wind is coming from (degrees) * @param speed wind speed in ground plane (m/s) @@ -105,7 +105,7 @@ static inline uint16_t mavlink_msg_wind_pack_chan(uint8_t system_id, uint8_t com } /** - * @brief Encode a wind struct into a message + * @brief Encode a wind struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -117,6 +117,20 @@ static inline uint16_t mavlink_msg_wind_encode(uint8_t system_id, uint8_t compon return mavlink_msg_wind_pack(system_id, component_id, msg, wind->direction, wind->speed, wind->speed_z); } +/** + * @brief Encode a wind struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param wind C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_wind_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_wind_t* wind) +{ + return mavlink_msg_wind_pack_chan(system_id, component_id, chan, msg, wind->direction, wind->speed, wind->speed_z); +} + /** * @brief Send a wind message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/testsuite.h b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/testsuite.h index 07bf19ee07ed26db798a03512dae6a7e03066b2d..2c9cfef3dc33b87e93024c9c70f0bb3fba9893d3 100644 --- a/libs/mavlink/include/mavlink/v1.0/ardupilotmega/testsuite.h +++ b/libs/mavlink/include/mavlink/v1.0/ardupilotmega/testsuite.h @@ -738,8 +738,8 @@ static void mavlink_test_simstate(uint8_t system_id, uint8_t component_id, mavli 185.0, 213.0, 241.0, - 269.0, - 297.0, + 963499336, + 963499544, }; mavlink_simstate_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); @@ -1225,6 +1225,71 @@ static void mavlink_test_rangefinder(uint8_t system_id, uint8_t component_id, ma MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); } +static void mavlink_test_airspeed_autocal(uint8_t system_id, uint8_t component_id, mavlink_message_t *last_msg) +{ + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_airspeed_autocal_t packet_in = { + 17.0, + 45.0, + 73.0, + 101.0, + 129.0, + 157.0, + 185.0, + 213.0, + 241.0, + 269.0, + 297.0, + 325.0, + }; + mavlink_airspeed_autocal_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.vx = packet_in.vx; + packet1.vy = packet_in.vy; + packet1.vz = packet_in.vz; + packet1.diff_pressure = packet_in.diff_pressure; + packet1.EAS2TAS = packet_in.EAS2TAS; + packet1.ratio = packet_in.ratio; + packet1.state_x = packet_in.state_x; + packet1.state_y = packet_in.state_y; + packet1.state_z = packet_in.state_z; + packet1.Pax = packet_in.Pax; + packet1.Pby = packet_in.Pby; + packet1.Pcz = packet_in.Pcz; + + + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_airspeed_autocal_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_airspeed_autocal_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_airspeed_autocal_pack(system_id, component_id, &msg , packet1.vx , packet1.vy , packet1.vz , packet1.diff_pressure , packet1.EAS2TAS , packet1.ratio , packet1.state_x , packet1.state_y , packet1.state_z , packet1.Pax , packet1.Pby , packet1.Pcz ); + mavlink_msg_airspeed_autocal_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_airspeed_autocal_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.vx , packet1.vy , packet1.vz , packet1.diff_pressure , packet1.EAS2TAS , packet1.ratio , packet1.state_x , packet1.state_y , packet1.state_z , packet1.Pax , packet1.Pby , packet1.Pcz ); + mavlink_msg_airspeed_autocal_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; i0: single images every n seconds (decimal)| Recording: 0: disabled, 1: enabled compressed, 2: enabled raw| Empty| Empty| Empty| */ + MAV_CMD_DO_SET_ROI=201, /* Sets the region of interest (ROI) for a sensor set or the vehicle itself. This can then be used by the vehicles control system to control the vehicle attitude and the attitude of various sensors such as cameras. |Region of intereset mode. (see MAV_ROI enum)| MISSION index/ target ID. (see MAV_ROI enum)| ROI index (allows a vehicle to manage multiple ROI's)| Empty| x the location of the fixed ROI (see MAV_FRAME)| y| z| */ MAV_CMD_DO_LAST=240, /* NOP - This command is only used to mark the upper limit of the DO commands in the enumeration |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ MAV_CMD_PREFLIGHT_CALIBRATION=241, /* Trigger calibration. This command will be only accepted if in pre-flight mode. |Gyro calibration: 0: no, 1: yes| Magnetometer calibration: 0: no, 1: yes| Ground pressure: 0: no, 1: yes| Radio calibration: 0: no, 1: yes| Accelerometer calibration: 0: no, 1: yes| Empty| Empty| */ MAV_CMD_PREFLIGHT_SET_SENSOR_OFFSETS=242, /* Set sensor offsets. This command will be only accepted if in pre-flight mode. |Sensor to adjust the offsets for: 0: gyros, 1: accelerometer, 2: magnetometer, 3: barometer, 4: optical flow| X axis offset (or generic dimension 1), in the sensor's raw units| Y axis offset (or generic dimension 2), in the sensor's raw units| Z axis offset (or generic dimension 3), in the sensor's raw units| Generic dimension 4, in the sensor's raw units| Generic dimension 5, in the sensor's raw units| Generic dimension 6, in the sensor's raw units| */ @@ -71,7 +96,8 @@ enum MAV_CMD MAV_CMD_OVERRIDE_GOTO=252, /* Hold / continue the current action |MAV_GOTO_DO_HOLD: hold MAV_GOTO_DO_CONTINUE: continue with next item in mission plan| MAV_GOTO_HOLD_AT_CURRENT_POSITION: Hold at current position MAV_GOTO_HOLD_AT_SPECIFIED_POSITION: hold at specified position| MAV_FRAME coordinate frame of hold point| Desired yaw angle in degrees| Latitude / X position| Longitude / Y position| Altitude / Z position| */ MAV_CMD_MISSION_START=300, /* start running a mission |first_item: the first mission item to run| last_item: the last mission item to run (after this item is run, the mission ends)| */ MAV_CMD_COMPONENT_ARM_DISARM=400, /* Arms / Disarms a component |1 to arm, 0 to disarm| */ - MAV_CMD_ENUM_END=401, /* | */ + MAV_CMD_START_RX_PAIR=500, /* Starts receiver pairing |0:Spektrum| 0:Spektrum DSM2, 1:Spektrum DSMX| */ + MAV_CMD_ENUM_END=501, /* | */ }; #endif diff --git a/libs/mavlink/include/mavlink/v1.0/autoquad/mavlink_msg_aq_telemetry_f.h b/libs/mavlink/include/mavlink/v1.0/autoquad/mavlink_msg_aq_telemetry_f.h index dabccdf733ac89e383291dba5157d4ed47dcb982..ed7c86bcb8324f19a80917649ad23397cc813c07 100644 --- a/libs/mavlink/include/mavlink/v1.0/autoquad/mavlink_msg_aq_telemetry_f.h +++ b/libs/mavlink/include/mavlink/v1.0/autoquad/mavlink_msg_aq_telemetry_f.h @@ -159,7 +159,7 @@ static inline uint16_t mavlink_msg_aq_telemetry_f_pack(uint8_t system_id, uint8_ * @brief Pack a aq_telemetry_f message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param Index Index of message * @param value1 value1 @@ -249,7 +249,7 @@ static inline uint16_t mavlink_msg_aq_telemetry_f_pack_chan(uint8_t system_id, u } /** - * @brief Encode a aq_telemetry_f struct into a message + * @brief Encode a aq_telemetry_f struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -261,6 +261,20 @@ static inline uint16_t mavlink_msg_aq_telemetry_f_encode(uint8_t system_id, uint return mavlink_msg_aq_telemetry_f_pack(system_id, component_id, msg, aq_telemetry_f->Index, aq_telemetry_f->value1, aq_telemetry_f->value2, aq_telemetry_f->value3, aq_telemetry_f->value4, aq_telemetry_f->value5, aq_telemetry_f->value6, aq_telemetry_f->value7, aq_telemetry_f->value8, aq_telemetry_f->value9, aq_telemetry_f->value10, aq_telemetry_f->value11, aq_telemetry_f->value12, aq_telemetry_f->value13, aq_telemetry_f->value14, aq_telemetry_f->value15, aq_telemetry_f->value16, aq_telemetry_f->value17, aq_telemetry_f->value18, aq_telemetry_f->value19, aq_telemetry_f->value20); } +/** + * @brief Encode a aq_telemetry_f struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param aq_telemetry_f C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_aq_telemetry_f_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_aq_telemetry_f_t* aq_telemetry_f) +{ + return mavlink_msg_aq_telemetry_f_pack_chan(system_id, component_id, chan, msg, aq_telemetry_f->Index, aq_telemetry_f->value1, aq_telemetry_f->value2, aq_telemetry_f->value3, aq_telemetry_f->value4, aq_telemetry_f->value5, aq_telemetry_f->value6, aq_telemetry_f->value7, aq_telemetry_f->value8, aq_telemetry_f->value9, aq_telemetry_f->value10, aq_telemetry_f->value11, aq_telemetry_f->value12, aq_telemetry_f->value13, aq_telemetry_f->value14, aq_telemetry_f->value15, aq_telemetry_f->value16, aq_telemetry_f->value17, aq_telemetry_f->value18, aq_telemetry_f->value19, aq_telemetry_f->value20); +} + /** * @brief Send a aq_telemetry_f message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/autoquad/version.h b/libs/mavlink/include/mavlink/v1.0/autoquad/version.h index a26ce2e909b6e79c1a697cf4d92d9d0c2f35118a..d8ba74f03c1787993518d4eb2fa7f2ffb7a15a67 100644 --- a/libs/mavlink/include/mavlink/v1.0/autoquad/version.h +++ b/libs/mavlink/include/mavlink/v1.0/autoquad/version.h @@ -5,7 +5,7 @@ #ifndef MAVLINK_VERSION_H #define MAVLINK_VERSION_H -#define MAVLINK_BUILD_DATE "Thu Jul 4 13:11:37 2013" +#define MAVLINK_BUILD_DATE "Tue Sep 10 23:49:36 2013" #define MAVLINK_WIRE_PROTOCOL_VERSION "1.0" #define MAVLINK_MAX_DIALECT_PAYLOAD_SIZE 254 diff --git a/libs/mavlink/include/mavlink/v1.0/common/common.h b/libs/mavlink/include/mavlink/v1.0/common/common.h index e2ab66ed1c04ebcad9b44434cfdf0d6a436e7843..9d3db33265f267980261220a9769d8686b1a1f46 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/common.h +++ b/libs/mavlink/include/mavlink/v1.0/common/common.h @@ -260,6 +260,7 @@ enum MAV_CMD MAV_CMD_DO_SET_SERVO=183, /* Set a servo to a desired PWM value. |Servo number| PWM (microseconds, 1000 to 2000 typical)| Empty| Empty| Empty| Empty| Empty| */ MAV_CMD_DO_REPEAT_SERVO=184, /* Cycle a between its nominal setting and a desired PWM for a desired number of cycles with a desired period. |Servo number| PWM (microseconds, 1000 to 2000 typical)| Cycle count| Cycle time (seconds)| Empty| Empty| Empty| */ MAV_CMD_DO_CONTROL_VIDEO=200, /* Control onboard camera system. |Camera ID (-1 for all)| Transmission: 0: disabled, 1: enabled compressed, 2: enabled raw| Transmission mode: 0: video stream, >0: single images every n seconds (decimal)| Recording: 0: disabled, 1: enabled compressed, 2: enabled raw| Empty| Empty| Empty| */ + MAV_CMD_DO_SET_ROI=201, /* Sets the region of interest (ROI) for a sensor set or the vehicle itself. This can then be used by the vehicles control system to control the vehicle attitude and the attitude of various sensors such as cameras. |Region of intereset mode. (see MAV_ROI enum)| MISSION index/ target ID. (see MAV_ROI enum)| ROI index (allows a vehicle to manage multiple ROI's)| Empty| x the location of the fixed ROI (see MAV_FRAME)| y| z| */ MAV_CMD_DO_LAST=240, /* NOP - This command is only used to mark the upper limit of the DO commands in the enumeration |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ MAV_CMD_PREFLIGHT_CALIBRATION=241, /* Trigger calibration. This command will be only accepted if in pre-flight mode. |Gyro calibration: 0: no, 1: yes| Magnetometer calibration: 0: no, 1: yes| Ground pressure: 0: no, 1: yes| Radio calibration: 0: no, 1: yes| Accelerometer calibration: 0: no, 1: yes| Empty| Empty| */ MAV_CMD_PREFLIGHT_SET_SENSOR_OFFSETS=242, /* Set sensor offsets. This command will be only accepted if in pre-flight mode. |Sensor to adjust the offsets for: 0: gyros, 1: accelerometer, 2: magnetometer, 3: barometer, 4: optical flow| X axis offset (or generic dimension 1), in the sensor's raw units| Y axis offset (or generic dimension 2), in the sensor's raw units| Z axis offset (or generic dimension 3), in the sensor's raw units| Generic dimension 4, in the sensor's raw units| Generic dimension 5, in the sensor's raw units| Generic dimension 6, in the sensor's raw units| */ @@ -268,7 +269,8 @@ enum MAV_CMD MAV_CMD_OVERRIDE_GOTO=252, /* Hold / continue the current action |MAV_GOTO_DO_HOLD: hold MAV_GOTO_DO_CONTINUE: continue with next item in mission plan| MAV_GOTO_HOLD_AT_CURRENT_POSITION: Hold at current position MAV_GOTO_HOLD_AT_SPECIFIED_POSITION: hold at specified position| MAV_FRAME coordinate frame of hold point| Desired yaw angle in degrees| Latitude / X position| Longitude / Y position| Altitude / Z position| */ MAV_CMD_MISSION_START=300, /* start running a mission |first_item: the first mission item to run| last_item: the last mission item to run (after this item is run, the mission ends)| */ MAV_CMD_COMPONENT_ARM_DISARM=400, /* Arms / Disarms a component |1 to arm, 0 to disarm| */ - MAV_CMD_ENUM_END=401, /* | */ + MAV_CMD_START_RX_PAIR=500, /* Starts receiver pairing |0:Spektrum| 0:Spektrum DSM2, 1:Spektrum DSMX| */ + MAV_CMD_ENUM_END=501, /* | */ }; #endif diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_6dof_setpoint.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_6dof_setpoint.h deleted file mode 100644 index 0c4ab8c7dff3ddd08c19415007e1288f1c72b1e9..0000000000000000000000000000000000000000 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_6dof_setpoint.h +++ /dev/null @@ -1,276 +0,0 @@ -// MESSAGE 6DOF_SETPOINT PACKING - -#define MAVLINK_MSG_ID_6DOF_SETPOINT 149 - -typedef struct __mavlink_6dof_setpoint_t -{ - float trans_x; ///< Translational Component in x - float trans_y; ///< Translational Component in y - float trans_z; ///< Translational Component in z - float rot_x; ///< Rotational Component in x - float rot_y; ///< Rotational Component in y - float rot_z; ///< Rotational Component in z - uint8_t target_system; ///< System ID -} mavlink_6dof_setpoint_t; - -#define MAVLINK_MSG_ID_6DOF_SETPOINT_LEN 25 -#define MAVLINK_MSG_ID_149_LEN 25 - - - -#define MAVLINK_MESSAGE_INFO_6DOF_SETPOINT { \ - "6DOF_SETPOINT", \ - 7, \ - { { "trans_x", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_6dof_setpoint_t, trans_x) }, \ - { "trans_y", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_6dof_setpoint_t, trans_y) }, \ - { "trans_z", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_6dof_setpoint_t, trans_z) }, \ - { "rot_x", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_6dof_setpoint_t, rot_x) }, \ - { "rot_y", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_6dof_setpoint_t, rot_y) }, \ - { "rot_z", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_6dof_setpoint_t, rot_z) }, \ - { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 24, offsetof(mavlink_6dof_setpoint_t, target_system) }, \ - } \ -} - - -/** - * @brief Pack a 6dof_setpoint message - * @param system_id ID of this system - * @param component_id ID of this component (e.g. 200 for IMU) - * @param msg The MAVLink message to compress the data into - * - * @param target_system System ID - * @param trans_x Translational Component in x - * @param trans_y Translational Component in y - * @param trans_z Translational Component in z - * @param rot_x Rotational Component in x - * @param rot_y Rotational Component in y - * @param rot_z Rotational Component in z - * @return length of the message in bytes (excluding serial stream start sign) - */ -static inline uint16_t mavlink_msg_6dof_setpoint_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, float trans_x, float trans_y, float trans_z, float rot_x, float rot_y, float rot_z) -{ -#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[25]; - _mav_put_float(buf, 0, trans_x); - _mav_put_float(buf, 4, trans_y); - _mav_put_float(buf, 8, trans_z); - _mav_put_float(buf, 12, rot_x); - _mav_put_float(buf, 16, rot_y); - _mav_put_float(buf, 20, rot_z); - _mav_put_uint8_t(buf, 24, target_system); - - memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, 25); -#else - mavlink_6dof_setpoint_t packet; - packet.trans_x = trans_x; - packet.trans_y = trans_y; - packet.trans_z = trans_z; - packet.rot_x = rot_x; - packet.rot_y = rot_y; - packet.rot_z = rot_z; - packet.target_system = target_system; - - memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, 25); -#endif - - msg->msgid = MAVLINK_MSG_ID_6DOF_SETPOINT; - return mavlink_finalize_message(msg, system_id, component_id, 25, 144); -} - -/** - * @brief Pack a 6dof_setpoint message on a channel - * @param system_id ID of this system - * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over - * @param msg The MAVLink message to compress the data into - * @param target_system System ID - * @param trans_x Translational Component in x - * @param trans_y Translational Component in y - * @param trans_z Translational Component in z - * @param rot_x Rotational Component in x - * @param rot_y Rotational Component in y - * @param rot_z Rotational Component in z - * @return length of the message in bytes (excluding serial stream start sign) - */ -static inline uint16_t mavlink_msg_6dof_setpoint_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,float trans_x,float trans_y,float trans_z,float rot_x,float rot_y,float rot_z) -{ -#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[25]; - _mav_put_float(buf, 0, trans_x); - _mav_put_float(buf, 4, trans_y); - _mav_put_float(buf, 8, trans_z); - _mav_put_float(buf, 12, rot_x); - _mav_put_float(buf, 16, rot_y); - _mav_put_float(buf, 20, rot_z); - _mav_put_uint8_t(buf, 24, target_system); - - memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, 25); -#else - mavlink_6dof_setpoint_t packet; - packet.trans_x = trans_x; - packet.trans_y = trans_y; - packet.trans_z = trans_z; - packet.rot_x = rot_x; - packet.rot_y = rot_y; - packet.rot_z = rot_z; - packet.target_system = target_system; - - memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, 25); -#endif - - msg->msgid = MAVLINK_MSG_ID_6DOF_SETPOINT; - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, 25, 144); -} - -/** - * @brief Encode a 6dof_setpoint struct into a message - * - * @param system_id ID of this system - * @param component_id ID of this component (e.g. 200 for IMU) - * @param msg The MAVLink message to compress the data into - * @param 6dof_setpoint C-struct to read the message contents from - */ -static inline uint16_t mavlink_msg_6dof_setpoint_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_6dof_setpoint_t* 6dof_setpoint) -{ - return mavlink_msg_6dof_setpoint_pack(system_id, component_id, msg, 6dof_setpoint->target_system, 6dof_setpoint->trans_x, 6dof_setpoint->trans_y, 6dof_setpoint->trans_z, 6dof_setpoint->rot_x, 6dof_setpoint->rot_y, 6dof_setpoint->rot_z); -} - -/** - * @brief Send a 6dof_setpoint message - * @param chan MAVLink channel to send the message - * - * @param target_system System ID - * @param trans_x Translational Component in x - * @param trans_y Translational Component in y - * @param trans_z Translational Component in z - * @param rot_x Rotational Component in x - * @param rot_y Rotational Component in y - * @param rot_z Rotational Component in z - */ -#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS - -static inline void mavlink_msg_6dof_setpoint_send(mavlink_channel_t chan, uint8_t target_system, float trans_x, float trans_y, float trans_z, float rot_x, float rot_y, float rot_z) -{ -#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[25]; - _mav_put_float(buf, 0, trans_x); - _mav_put_float(buf, 4, trans_y); - _mav_put_float(buf, 8, trans_z); - _mav_put_float(buf, 12, rot_x); - _mav_put_float(buf, 16, rot_y); - _mav_put_float(buf, 20, rot_z); - _mav_put_uint8_t(buf, 24, target_system); - - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_6DOF_SETPOINT, buf, 25, 144); -#else - mavlink_6dof_setpoint_t packet; - packet.trans_x = trans_x; - packet.trans_y = trans_y; - packet.trans_z = trans_z; - packet.rot_x = rot_x; - packet.rot_y = rot_y; - packet.rot_z = rot_z; - packet.target_system = target_system; - - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_6DOF_SETPOINT, (const char *)&packet, 25, 144); -#endif -} - -#endif - -// MESSAGE 6DOF_SETPOINT UNPACKING - - -/** - * @brief Get field target_system from 6dof_setpoint message - * - * @return System ID - */ -static inline uint8_t mavlink_msg_6dof_setpoint_get_target_system(const mavlink_message_t* msg) -{ - return _MAV_RETURN_uint8_t(msg, 24); -} - -/** - * @brief Get field trans_x from 6dof_setpoint message - * - * @return Translational Component in x - */ -static inline float mavlink_msg_6dof_setpoint_get_trans_x(const mavlink_message_t* msg) -{ - return _MAV_RETURN_float(msg, 0); -} - -/** - * @brief Get field trans_y from 6dof_setpoint message - * - * @return Translational Component in y - */ -static inline float mavlink_msg_6dof_setpoint_get_trans_y(const mavlink_message_t* msg) -{ - return _MAV_RETURN_float(msg, 4); -} - -/** - * @brief Get field trans_z from 6dof_setpoint message - * - * @return Translational Component in z - */ -static inline float mavlink_msg_6dof_setpoint_get_trans_z(const mavlink_message_t* msg) -{ - return _MAV_RETURN_float(msg, 8); -} - -/** - * @brief Get field rot_x from 6dof_setpoint message - * - * @return Rotational Component in x - */ -static inline float mavlink_msg_6dof_setpoint_get_rot_x(const mavlink_message_t* msg) -{ - return _MAV_RETURN_float(msg, 12); -} - -/** - * @brief Get field rot_y from 6dof_setpoint message - * - * @return Rotational Component in y - */ -static inline float mavlink_msg_6dof_setpoint_get_rot_y(const mavlink_message_t* msg) -{ - return _MAV_RETURN_float(msg, 16); -} - -/** - * @brief Get field rot_z from 6dof_setpoint message - * - * @return Rotational Component in z - */ -static inline float mavlink_msg_6dof_setpoint_get_rot_z(const mavlink_message_t* msg) -{ - return _MAV_RETURN_float(msg, 20); -} - -/** - * @brief Decode a 6dof_setpoint message into a struct - * - * @param msg The message to decode - * @param 6dof_setpoint C-struct to decode the message contents into - */ -static inline void mavlink_msg_6dof_setpoint_decode(const mavlink_message_t* msg, mavlink_6dof_setpoint_t* 6dof_setpoint) -{ -#if MAVLINK_NEED_BYTE_SWAP - 6dof_setpoint->trans_x = mavlink_msg_6dof_setpoint_get_trans_x(msg); - 6dof_setpoint->trans_y = mavlink_msg_6dof_setpoint_get_trans_y(msg); - 6dof_setpoint->trans_z = mavlink_msg_6dof_setpoint_get_trans_z(msg); - 6dof_setpoint->rot_x = mavlink_msg_6dof_setpoint_get_rot_x(msg); - 6dof_setpoint->rot_y = mavlink_msg_6dof_setpoint_get_rot_y(msg); - 6dof_setpoint->rot_z = mavlink_msg_6dof_setpoint_get_rot_z(msg); - 6dof_setpoint->target_system = mavlink_msg_6dof_setpoint_get_target_system(msg); -#else - memcpy(6dof_setpoint, _MAV_PAYLOAD(msg), 25); -#endif -} diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_8dof_setpoint.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_8dof_setpoint.h deleted file mode 100644 index 521d2fb668139ad220289d2aa16fa919833647aa..0000000000000000000000000000000000000000 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_8dof_setpoint.h +++ /dev/null @@ -1,320 +0,0 @@ -// MESSAGE 8DOF_SETPOINT PACKING - -#define MAVLINK_MSG_ID_8DOF_SETPOINT 148 - -typedef struct __mavlink_8dof_setpoint_t -{ - float val1; ///< Value 1 - float val2; ///< Value 2 - float val3; ///< Value 3 - float val4; ///< Value 4 - float val5; ///< Value 5 - float val6; ///< Value 6 - float val7; ///< Value 7 - float val8; ///< Value 8 - uint8_t target_system; ///< System ID -} mavlink_8dof_setpoint_t; - -#define MAVLINK_MSG_ID_8DOF_SETPOINT_LEN 33 -#define MAVLINK_MSG_ID_148_LEN 33 - - - -#define MAVLINK_MESSAGE_INFO_8DOF_SETPOINT { \ - "8DOF_SETPOINT", \ - 9, \ - { { "val1", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_8dof_setpoint_t, val1) }, \ - { "val2", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_8dof_setpoint_t, val2) }, \ - { "val3", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_8dof_setpoint_t, val3) }, \ - { "val4", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_8dof_setpoint_t, val4) }, \ - { "val5", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_8dof_setpoint_t, val5) }, \ - { "val6", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_8dof_setpoint_t, val6) }, \ - { "val7", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_8dof_setpoint_t, val7) }, \ - { "val8", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_8dof_setpoint_t, val8) }, \ - { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 32, offsetof(mavlink_8dof_setpoint_t, target_system) }, \ - } \ -} - - -/** - * @brief Pack a 8dof_setpoint message - * @param system_id ID of this system - * @param component_id ID of this component (e.g. 200 for IMU) - * @param msg The MAVLink message to compress the data into - * - * @param target_system System ID - * @param val1 Value 1 - * @param val2 Value 2 - * @param val3 Value 3 - * @param val4 Value 4 - * @param val5 Value 5 - * @param val6 Value 6 - * @param val7 Value 7 - * @param val8 Value 8 - * @return length of the message in bytes (excluding serial stream start sign) - */ -static inline uint16_t mavlink_msg_8dof_setpoint_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, float val1, float val2, float val3, float val4, float val5, float val6, float val7, float val8) -{ -#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[33]; - _mav_put_float(buf, 0, val1); - _mav_put_float(buf, 4, val2); - _mav_put_float(buf, 8, val3); - _mav_put_float(buf, 12, val4); - _mav_put_float(buf, 16, val5); - _mav_put_float(buf, 20, val6); - _mav_put_float(buf, 24, val7); - _mav_put_float(buf, 28, val8); - _mav_put_uint8_t(buf, 32, target_system); - - memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, 33); -#else - mavlink_8dof_setpoint_t packet; - packet.val1 = val1; - packet.val2 = val2; - packet.val3 = val3; - packet.val4 = val4; - packet.val5 = val5; - packet.val6 = val6; - packet.val7 = val7; - packet.val8 = val8; - packet.target_system = target_system; - - memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, 33); -#endif - - msg->msgid = MAVLINK_MSG_ID_8DOF_SETPOINT; - return mavlink_finalize_message(msg, system_id, component_id, 33, 42); -} - -/** - * @brief Pack a 8dof_setpoint message on a channel - * @param system_id ID of this system - * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over - * @param msg The MAVLink message to compress the data into - * @param target_system System ID - * @param val1 Value 1 - * @param val2 Value 2 - * @param val3 Value 3 - * @param val4 Value 4 - * @param val5 Value 5 - * @param val6 Value 6 - * @param val7 Value 7 - * @param val8 Value 8 - * @return length of the message in bytes (excluding serial stream start sign) - */ -static inline uint16_t mavlink_msg_8dof_setpoint_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,float val1,float val2,float val3,float val4,float val5,float val6,float val7,float val8) -{ -#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[33]; - _mav_put_float(buf, 0, val1); - _mav_put_float(buf, 4, val2); - _mav_put_float(buf, 8, val3); - _mav_put_float(buf, 12, val4); - _mav_put_float(buf, 16, val5); - _mav_put_float(buf, 20, val6); - _mav_put_float(buf, 24, val7); - _mav_put_float(buf, 28, val8); - _mav_put_uint8_t(buf, 32, target_system); - - memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, 33); -#else - mavlink_8dof_setpoint_t packet; - packet.val1 = val1; - packet.val2 = val2; - packet.val3 = val3; - packet.val4 = val4; - packet.val5 = val5; - packet.val6 = val6; - packet.val7 = val7; - packet.val8 = val8; - packet.target_system = target_system; - - memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, 33); -#endif - - msg->msgid = MAVLINK_MSG_ID_8DOF_SETPOINT; - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, 33, 42); -} - -/** - * @brief Encode a 8dof_setpoint struct into a message - * - * @param system_id ID of this system - * @param component_id ID of this component (e.g. 200 for IMU) - * @param msg The MAVLink message to compress the data into - * @param 8dof_setpoint C-struct to read the message contents from - */ -static inline uint16_t mavlink_msg_8dof_setpoint_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_8dof_setpoint_t* 8dof_setpoint) -{ - return mavlink_msg_8dof_setpoint_pack(system_id, component_id, msg, 8dof_setpoint->target_system, 8dof_setpoint->val1, 8dof_setpoint->val2, 8dof_setpoint->val3, 8dof_setpoint->val4, 8dof_setpoint->val5, 8dof_setpoint->val6, 8dof_setpoint->val7, 8dof_setpoint->val8); -} - -/** - * @brief Send a 8dof_setpoint message - * @param chan MAVLink channel to send the message - * - * @param target_system System ID - * @param val1 Value 1 - * @param val2 Value 2 - * @param val3 Value 3 - * @param val4 Value 4 - * @param val5 Value 5 - * @param val6 Value 6 - * @param val7 Value 7 - * @param val8 Value 8 - */ -#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS - -static inline void mavlink_msg_8dof_setpoint_send(mavlink_channel_t chan, uint8_t target_system, float val1, float val2, float val3, float val4, float val5, float val6, float val7, float val8) -{ -#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[33]; - _mav_put_float(buf, 0, val1); - _mav_put_float(buf, 4, val2); - _mav_put_float(buf, 8, val3); - _mav_put_float(buf, 12, val4); - _mav_put_float(buf, 16, val5); - _mav_put_float(buf, 20, val6); - _mav_put_float(buf, 24, val7); - _mav_put_float(buf, 28, val8); - _mav_put_uint8_t(buf, 32, target_system); - - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_8DOF_SETPOINT, buf, 33, 42); -#else - mavlink_8dof_setpoint_t packet; - packet.val1 = val1; - packet.val2 = val2; - packet.val3 = val3; - packet.val4 = val4; - packet.val5 = val5; - packet.val6 = val6; - packet.val7 = val7; - packet.val8 = val8; - packet.target_system = target_system; - - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_8DOF_SETPOINT, (const char *)&packet, 33, 42); -#endif -} - -#endif - -// MESSAGE 8DOF_SETPOINT UNPACKING - - -/** - * @brief Get field target_system from 8dof_setpoint message - * - * @return System ID - */ -static inline uint8_t mavlink_msg_8dof_setpoint_get_target_system(const mavlink_message_t* msg) -{ - return _MAV_RETURN_uint8_t(msg, 32); -} - -/** - * @brief Get field val1 from 8dof_setpoint message - * - * @return Value 1 - */ -static inline float mavlink_msg_8dof_setpoint_get_val1(const mavlink_message_t* msg) -{ - return _MAV_RETURN_float(msg, 0); -} - -/** - * @brief Get field val2 from 8dof_setpoint message - * - * @return Value 2 - */ -static inline float mavlink_msg_8dof_setpoint_get_val2(const mavlink_message_t* msg) -{ - return _MAV_RETURN_float(msg, 4); -} - -/** - * @brief Get field val3 from 8dof_setpoint message - * - * @return Value 3 - */ -static inline float mavlink_msg_8dof_setpoint_get_val3(const mavlink_message_t* msg) -{ - return _MAV_RETURN_float(msg, 8); -} - -/** - * @brief Get field val4 from 8dof_setpoint message - * - * @return Value 4 - */ -static inline float mavlink_msg_8dof_setpoint_get_val4(const mavlink_message_t* msg) -{ - return _MAV_RETURN_float(msg, 12); -} - -/** - * @brief Get field val5 from 8dof_setpoint message - * - * @return Value 5 - */ -static inline float mavlink_msg_8dof_setpoint_get_val5(const mavlink_message_t* msg) -{ - return _MAV_RETURN_float(msg, 16); -} - -/** - * @brief Get field val6 from 8dof_setpoint message - * - * @return Value 6 - */ -static inline float mavlink_msg_8dof_setpoint_get_val6(const mavlink_message_t* msg) -{ - return _MAV_RETURN_float(msg, 20); -} - -/** - * @brief Get field val7 from 8dof_setpoint message - * - * @return Value 7 - */ -static inline float mavlink_msg_8dof_setpoint_get_val7(const mavlink_message_t* msg) -{ - return _MAV_RETURN_float(msg, 24); -} - -/** - * @brief Get field val8 from 8dof_setpoint message - * - * @return Value 8 - */ -static inline float mavlink_msg_8dof_setpoint_get_val8(const mavlink_message_t* msg) -{ - return _MAV_RETURN_float(msg, 28); -} - -/** - * @brief Decode a 8dof_setpoint message into a struct - * - * @param msg The message to decode - * @param 8dof_setpoint C-struct to decode the message contents into - */ -static inline void mavlink_msg_8dof_setpoint_decode(const mavlink_message_t* msg, mavlink_8dof_setpoint_t* 8dof_setpoint) -{ -#if MAVLINK_NEED_BYTE_SWAP - 8dof_setpoint->val1 = mavlink_msg_8dof_setpoint_get_val1(msg); - 8dof_setpoint->val2 = mavlink_msg_8dof_setpoint_get_val2(msg); - 8dof_setpoint->val3 = mavlink_msg_8dof_setpoint_get_val3(msg); - 8dof_setpoint->val4 = mavlink_msg_8dof_setpoint_get_val4(msg); - 8dof_setpoint->val5 = mavlink_msg_8dof_setpoint_get_val5(msg); - 8dof_setpoint->val6 = mavlink_msg_8dof_setpoint_get_val6(msg); - 8dof_setpoint->val7 = mavlink_msg_8dof_setpoint_get_val7(msg); - 8dof_setpoint->val8 = mavlink_msg_8dof_setpoint_get_val8(msg); - 8dof_setpoint->target_system = mavlink_msg_8dof_setpoint_get_target_system(msg); -#else - memcpy(8dof_setpoint, _MAV_PAYLOAD(msg), 33); -#endif -} diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_attitude.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_attitude.h index 0ba416ee1481ad88814fe6d3a138699643fc4c85..8ddf5bf099f25396cf05a641ca0b4ece2b5c950f 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_attitude.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_attitude.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_attitude_pack(uint8_t system_id, uint8_t comp * @brief Pack a attitude message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp (milliseconds since system boot) * @param roll Roll angle (rad, -pi..+pi) @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_attitude_pack_chan(uint8_t system_id, uint8_t } /** - * @brief Encode a attitude struct into a message + * @brief Encode a attitude struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_attitude_encode(uint8_t system_id, uint8_t co return mavlink_msg_attitude_pack(system_id, component_id, msg, attitude->time_boot_ms, attitude->roll, attitude->pitch, attitude->yaw, attitude->rollspeed, attitude->pitchspeed, attitude->yawspeed); } +/** + * @brief Encode a attitude struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param attitude C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_attitude_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_attitude_t* attitude) +{ + return mavlink_msg_attitude_pack_chan(system_id, component_id, chan, msg, attitude->time_boot_ms, attitude->roll, attitude->pitch, attitude->yaw, attitude->rollspeed, attitude->pitchspeed, attitude->yawspeed); +} + /** * @brief Send a attitude message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_attitude_quaternion.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_attitude_quaternion.h index 611803f2b74e01e2dfcee637d4cf1da803dbc05f..9f8d5875987fb2c115d8444b6d95be10b4f8f6a7 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_attitude_quaternion.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_attitude_quaternion.h @@ -94,7 +94,7 @@ static inline uint16_t mavlink_msg_attitude_quaternion_pack(uint8_t system_id, u * @brief Pack a attitude_quaternion message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp (milliseconds since system boot) * @param q1 Quaternion component 1 @@ -145,7 +145,7 @@ static inline uint16_t mavlink_msg_attitude_quaternion_pack_chan(uint8_t system_ } /** - * @brief Encode a attitude_quaternion struct into a message + * @brief Encode a attitude_quaternion struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -157,6 +157,20 @@ static inline uint16_t mavlink_msg_attitude_quaternion_encode(uint8_t system_id, return mavlink_msg_attitude_quaternion_pack(system_id, component_id, msg, attitude_quaternion->time_boot_ms, attitude_quaternion->q1, attitude_quaternion->q2, attitude_quaternion->q3, attitude_quaternion->q4, attitude_quaternion->rollspeed, attitude_quaternion->pitchspeed, attitude_quaternion->yawspeed); } +/** + * @brief Encode a attitude_quaternion struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param attitude_quaternion C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_attitude_quaternion_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_attitude_quaternion_t* attitude_quaternion) +{ + return mavlink_msg_attitude_quaternion_pack_chan(system_id, component_id, chan, msg, attitude_quaternion->time_boot_ms, attitude_quaternion->q1, attitude_quaternion->q2, attitude_quaternion->q3, attitude_quaternion->q4, attitude_quaternion->rollspeed, attitude_quaternion->pitchspeed, attitude_quaternion->yawspeed); +} + /** * @brief Send a attitude_quaternion message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_auth_key.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_auth_key.h index 030b564c97e258c24a1056374552a1720d1291e0..5703a59871957c814373bc3041b19164b6ce0f4f 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_auth_key.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_auth_key.h @@ -59,7 +59,7 @@ static inline uint16_t mavlink_msg_auth_key_pack(uint8_t system_id, uint8_t comp * @brief Pack a auth_key message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param key key * @return length of the message in bytes (excluding serial stream start sign) @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_auth_key_pack_chan(uint8_t system_id, uint8_t } /** - * @brief Encode a auth_key struct into a message + * @brief Encode a auth_key struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -101,6 +101,20 @@ static inline uint16_t mavlink_msg_auth_key_encode(uint8_t system_id, uint8_t co return mavlink_msg_auth_key_pack(system_id, component_id, msg, auth_key->key); } +/** + * @brief Encode a auth_key struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param auth_key C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_auth_key_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_auth_key_t* auth_key) +{ + return mavlink_msg_auth_key_pack_chan(system_id, component_id, chan, msg, auth_key->key); +} + /** * @brief Send a auth_key message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_battery_status.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_battery_status.h index 83c81598416e960692da02cd94a0fc0b558d9248..c945aebaea8a6a8d20393532cef6dda46cc8c479 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_battery_status.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_battery_status.h @@ -99,7 +99,7 @@ static inline uint16_t mavlink_msg_battery_status_pack(uint8_t system_id, uint8_ * @brief Pack a battery_status message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param accu_id Accupack ID * @param voltage_cell_1 Battery voltage of cell 1, in millivolts (1 = 1 millivolt) @@ -153,7 +153,7 @@ static inline uint16_t mavlink_msg_battery_status_pack_chan(uint8_t system_id, u } /** - * @brief Encode a battery_status struct into a message + * @brief Encode a battery_status struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -165,6 +165,20 @@ static inline uint16_t mavlink_msg_battery_status_encode(uint8_t system_id, uint return mavlink_msg_battery_status_pack(system_id, component_id, msg, battery_status->accu_id, battery_status->voltage_cell_1, battery_status->voltage_cell_2, battery_status->voltage_cell_3, battery_status->voltage_cell_4, battery_status->voltage_cell_5, battery_status->voltage_cell_6, battery_status->current_battery, battery_status->battery_remaining); } +/** + * @brief Encode a battery_status struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param battery_status C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_battery_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_battery_status_t* battery_status) +{ + return mavlink_msg_battery_status_pack_chan(system_id, component_id, chan, msg, battery_status->accu_id, battery_status->voltage_cell_1, battery_status->voltage_cell_2, battery_status->voltage_cell_3, battery_status->voltage_cell_4, battery_status->voltage_cell_5, battery_status->voltage_cell_6, battery_status->current_battery, battery_status->battery_remaining); +} + /** * @brief Send a battery_status message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_change_operator_control.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_change_operator_control.h index c7195dfcaa0bf948fa771896f8acc0ef92488154..0b6de930d2744a06f7ee97a0bef17bf242204463 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_change_operator_control.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_change_operator_control.h @@ -72,7 +72,7 @@ static inline uint16_t mavlink_msg_change_operator_control_pack(uint8_t system_i * @brief Pack a change_operator_control message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System the GCS requests control for * @param control_request 0: request control of this MAV, 1: Release control of this MAV @@ -109,7 +109,7 @@ static inline uint16_t mavlink_msg_change_operator_control_pack_chan(uint8_t sys } /** - * @brief Encode a change_operator_control struct into a message + * @brief Encode a change_operator_control struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -121,6 +121,20 @@ static inline uint16_t mavlink_msg_change_operator_control_encode(uint8_t system return mavlink_msg_change_operator_control_pack(system_id, component_id, msg, change_operator_control->target_system, change_operator_control->control_request, change_operator_control->version, change_operator_control->passkey); } +/** + * @brief Encode a change_operator_control struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param change_operator_control C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_change_operator_control_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_change_operator_control_t* change_operator_control) +{ + return mavlink_msg_change_operator_control_pack_chan(system_id, component_id, chan, msg, change_operator_control->target_system, change_operator_control->control_request, change_operator_control->version, change_operator_control->passkey); +} + /** * @brief Send a change_operator_control message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_change_operator_control_ack.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_change_operator_control_ack.h index 5cf98e77fe5b5a8e38ffae28e47b0e71a150e956..c6f6a28e4be46e05c9f30dedf0e85f66be76ba49 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_change_operator_control_ack.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_change_operator_control_ack.h @@ -69,7 +69,7 @@ static inline uint16_t mavlink_msg_change_operator_control_ack_pack(uint8_t syst * @brief Pack a change_operator_control_ack message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param gcs_system_id ID of the GCS this message * @param control_request 0: request control of this MAV, 1: Release control of this MAV @@ -105,7 +105,7 @@ static inline uint16_t mavlink_msg_change_operator_control_ack_pack_chan(uint8_t } /** - * @brief Encode a change_operator_control_ack struct into a message + * @brief Encode a change_operator_control_ack struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -117,6 +117,20 @@ static inline uint16_t mavlink_msg_change_operator_control_ack_encode(uint8_t sy return mavlink_msg_change_operator_control_ack_pack(system_id, component_id, msg, change_operator_control_ack->gcs_system_id, change_operator_control_ack->control_request, change_operator_control_ack->ack); } +/** + * @brief Encode a change_operator_control_ack struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param change_operator_control_ack C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_change_operator_control_ack_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_change_operator_control_ack_t* change_operator_control_ack) +{ + return mavlink_msg_change_operator_control_ack_pack_chan(system_id, component_id, chan, msg, change_operator_control_ack->gcs_system_id, change_operator_control_ack->control_request, change_operator_control_ack->ack); +} + /** * @brief Send a change_operator_control_ack message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_command_ack.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_command_ack.h index 82c2835de0cb15f536b8a6662f1c7995ebecfd7e..dca2fe6819f7de7eb7934c016657e430c1014f52 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_command_ack.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_command_ack.h @@ -64,7 +64,7 @@ static inline uint16_t mavlink_msg_command_ack_pack(uint8_t system_id, uint8_t c * @brief Pack a command_ack message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param command Command ID, as defined by MAV_CMD enum. * @param result See MAV_RESULT enum @@ -97,7 +97,7 @@ static inline uint16_t mavlink_msg_command_ack_pack_chan(uint8_t system_id, uint } /** - * @brief Encode a command_ack struct into a message + * @brief Encode a command_ack struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -109,6 +109,20 @@ static inline uint16_t mavlink_msg_command_ack_encode(uint8_t system_id, uint8_t return mavlink_msg_command_ack_pack(system_id, component_id, msg, command_ack->command, command_ack->result); } +/** + * @brief Encode a command_ack struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param command_ack C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_command_ack_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_command_ack_t* command_ack) +{ + return mavlink_msg_command_ack_pack_chan(system_id, component_id, chan, msg, command_ack->command, command_ack->result); +} + /** * @brief Send a command_ack message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_command_long.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_command_long.h index 5c44c62844a52d5634b9645cb46e55ed3dc75e69..8f705c0dd2e96dd367bd27be5504bf1c41e82ff9 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_command_long.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_command_long.h @@ -109,7 +109,7 @@ static inline uint16_t mavlink_msg_command_long_pack(uint8_t system_id, uint8_t * @brief Pack a command_long message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System which should execute the command * @param target_component Component which should execute the command, 0 for all components @@ -169,7 +169,7 @@ static inline uint16_t mavlink_msg_command_long_pack_chan(uint8_t system_id, uin } /** - * @brief Encode a command_long struct into a message + * @brief Encode a command_long struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -181,6 +181,20 @@ static inline uint16_t mavlink_msg_command_long_encode(uint8_t system_id, uint8_ return mavlink_msg_command_long_pack(system_id, component_id, msg, command_long->target_system, command_long->target_component, command_long->command, command_long->confirmation, command_long->param1, command_long->param2, command_long->param3, command_long->param4, command_long->param5, command_long->param6, command_long->param7); } +/** + * @brief Encode a command_long struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param command_long C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_command_long_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_command_long_t* command_long) +{ + return mavlink_msg_command_long_pack_chan(system_id, component_id, chan, msg, command_long->target_system, command_long->target_component, command_long->command, command_long->confirmation, command_long->param1, command_long->param2, command_long->param3, command_long->param4, command_long->param5, command_long->param6, command_long->param7); +} + /** * @brief Send a command_long message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_data_stream.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_data_stream.h index 782ea9f26b4f6ee119cf5715d78ae15de059b8d5..dc0768e1282c23b8aeba9cc077be9342300412c0 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_data_stream.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_data_stream.h @@ -69,7 +69,7 @@ static inline uint16_t mavlink_msg_data_stream_pack(uint8_t system_id, uint8_t c * @brief Pack a data_stream message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param stream_id The ID of the requested data stream * @param message_rate The requested interval between two messages of this type @@ -105,7 +105,7 @@ static inline uint16_t mavlink_msg_data_stream_pack_chan(uint8_t system_id, uint } /** - * @brief Encode a data_stream struct into a message + * @brief Encode a data_stream struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -117,6 +117,20 @@ static inline uint16_t mavlink_msg_data_stream_encode(uint8_t system_id, uint8_t return mavlink_msg_data_stream_pack(system_id, component_id, msg, data_stream->stream_id, data_stream->message_rate, data_stream->on_off); } +/** + * @brief Encode a data_stream struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param data_stream C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_data_stream_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_data_stream_t* data_stream) +{ + return mavlink_msg_data_stream_pack_chan(system_id, component_id, chan, msg, data_stream->stream_id, data_stream->message_rate, data_stream->on_off); +} + /** * @brief Send a data_stream message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_debug.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_debug.h index a111619185acbae77df78cb2f291feb19729a2bb..9a6ed87eeb3e631b2ae9c117794a2c3f0a355900 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_debug.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_debug.h @@ -69,7 +69,7 @@ static inline uint16_t mavlink_msg_debug_pack(uint8_t system_id, uint8_t compone * @brief Pack a debug message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp (milliseconds since system boot) * @param ind index of debug variable @@ -105,7 +105,7 @@ static inline uint16_t mavlink_msg_debug_pack_chan(uint8_t system_id, uint8_t co } /** - * @brief Encode a debug struct into a message + * @brief Encode a debug struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -117,6 +117,20 @@ static inline uint16_t mavlink_msg_debug_encode(uint8_t system_id, uint8_t compo return mavlink_msg_debug_pack(system_id, component_id, msg, debug->time_boot_ms, debug->ind, debug->value); } +/** + * @brief Encode a debug struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param debug C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_debug_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_debug_t* debug) +{ + return mavlink_msg_debug_pack_chan(system_id, component_id, chan, msg, debug->time_boot_ms, debug->ind, debug->value); +} + /** * @brief Send a debug message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_debug_vect.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_debug_vect.h index 5ee4e323ac03dfad3449071dbe491bb5aef5d4ee..6cfc75212ed7c2e0eab8df6c0647635358840bd1 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_debug_vect.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_debug_vect.h @@ -77,7 +77,7 @@ static inline uint16_t mavlink_msg_debug_vect_pack(uint8_t system_id, uint8_t co * @brief Pack a debug_vect message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param name Name * @param time_usec Timestamp @@ -117,7 +117,7 @@ static inline uint16_t mavlink_msg_debug_vect_pack_chan(uint8_t system_id, uint8 } /** - * @brief Encode a debug_vect struct into a message + * @brief Encode a debug_vect struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -129,6 +129,20 @@ static inline uint16_t mavlink_msg_debug_vect_encode(uint8_t system_id, uint8_t return mavlink_msg_debug_vect_pack(system_id, component_id, msg, debug_vect->name, debug_vect->time_usec, debug_vect->x, debug_vect->y, debug_vect->z); } +/** + * @brief Encode a debug_vect struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param debug_vect C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_debug_vect_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_debug_vect_t* debug_vect) +{ + return mavlink_msg_debug_vect_pack_chan(system_id, component_id, chan, msg, debug_vect->name, debug_vect->time_usec, debug_vect->x, debug_vect->y, debug_vect->z); +} + /** * @brief Send a debug_vect message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_file_transfer_dir_list.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_file_transfer_dir_list.h index c026419a20d4ad11af4a3126c9d1be7fc767f2bf..4f31698d50138f74c63a9a02a14b1a3357313c5f 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_file_transfer_dir_list.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_file_transfer_dir_list.h @@ -67,7 +67,7 @@ static inline uint16_t mavlink_msg_file_transfer_dir_list_pack(uint8_t system_id * @brief Pack a file_transfer_dir_list message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param transfer_uid Unique transfer ID * @param dir_path Directory path to list @@ -101,7 +101,7 @@ static inline uint16_t mavlink_msg_file_transfer_dir_list_pack_chan(uint8_t syst } /** - * @brief Encode a file_transfer_dir_list struct into a message + * @brief Encode a file_transfer_dir_list struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -113,6 +113,20 @@ static inline uint16_t mavlink_msg_file_transfer_dir_list_encode(uint8_t system_ return mavlink_msg_file_transfer_dir_list_pack(system_id, component_id, msg, file_transfer_dir_list->transfer_uid, file_transfer_dir_list->dir_path, file_transfer_dir_list->flags); } +/** + * @brief Encode a file_transfer_dir_list struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param file_transfer_dir_list C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_file_transfer_dir_list_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_file_transfer_dir_list_t* file_transfer_dir_list) +{ + return mavlink_msg_file_transfer_dir_list_pack_chan(system_id, component_id, chan, msg, file_transfer_dir_list->transfer_uid, file_transfer_dir_list->dir_path, file_transfer_dir_list->flags); +} + /** * @brief Send a file_transfer_dir_list message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_file_transfer_res.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_file_transfer_res.h index 86d407d66b8e88fb5af47feefe270062eb914060..fc6247faca63f1224c704990f7d7386eec49a57d 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_file_transfer_res.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_file_transfer_res.h @@ -64,7 +64,7 @@ static inline uint16_t mavlink_msg_file_transfer_res_pack(uint8_t system_id, uin * @brief Pack a file_transfer_res message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param transfer_uid Unique transfer ID * @param result 0: OK, 1: not permitted, 2: bad path / file name, 3: no space left on device @@ -97,7 +97,7 @@ static inline uint16_t mavlink_msg_file_transfer_res_pack_chan(uint8_t system_id } /** - * @brief Encode a file_transfer_res struct into a message + * @brief Encode a file_transfer_res struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -109,6 +109,20 @@ static inline uint16_t mavlink_msg_file_transfer_res_encode(uint8_t system_id, u return mavlink_msg_file_transfer_res_pack(system_id, component_id, msg, file_transfer_res->transfer_uid, file_transfer_res->result); } +/** + * @brief Encode a file_transfer_res struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param file_transfer_res C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_file_transfer_res_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_file_transfer_res_t* file_transfer_res) +{ + return mavlink_msg_file_transfer_res_pack_chan(system_id, component_id, chan, msg, file_transfer_res->transfer_uid, file_transfer_res->result); +} + /** * @brief Send a file_transfer_res message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_file_transfer_start.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_file_transfer_start.h index 24bf25413f9f343c681818b29970fe2bea1766c7..05be77339b86d1b12b368c57fcfeee5725900595 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_file_transfer_start.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_file_transfer_start.h @@ -77,7 +77,7 @@ static inline uint16_t mavlink_msg_file_transfer_start_pack(uint8_t system_id, u * @brief Pack a file_transfer_start message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param transfer_uid Unique transfer ID * @param dest_path Destination path @@ -117,7 +117,7 @@ static inline uint16_t mavlink_msg_file_transfer_start_pack_chan(uint8_t system_ } /** - * @brief Encode a file_transfer_start struct into a message + * @brief Encode a file_transfer_start struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -129,6 +129,20 @@ static inline uint16_t mavlink_msg_file_transfer_start_encode(uint8_t system_id, return mavlink_msg_file_transfer_start_pack(system_id, component_id, msg, file_transfer_start->transfer_uid, file_transfer_start->dest_path, file_transfer_start->direction, file_transfer_start->file_size, file_transfer_start->flags); } +/** + * @brief Encode a file_transfer_start struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param file_transfer_start C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_file_transfer_start_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_file_transfer_start_t* file_transfer_start) +{ + return mavlink_msg_file_transfer_start_pack_chan(system_id, component_id, chan, msg, file_transfer_start->transfer_uid, file_transfer_start->dest_path, file_transfer_start->direction, file_transfer_start->file_size, file_transfer_start->flags); +} + /** * @brief Send a file_transfer_start message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_global_position_int.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_global_position_int.h index 11ab97ee47f58bf14a13e38cbefde005827e7285..7ed3d2a636f9d7a825126282d23e255e070122c8 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_global_position_int.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_global_position_int.h @@ -12,7 +12,7 @@ typedef struct __mavlink_global_position_int_t int16_t vx; ///< Ground X Speed (Latitude), expressed as m/s * 100 int16_t vy; ///< Ground Y Speed (Longitude), expressed as m/s * 100 int16_t vz; ///< Ground Z Speed (Altitude), expressed as m/s * 100 - uint16_t hdg; ///< Compass heading in degrees * 100, 0.0..359.99 degrees. If unknown, set to: 65535 + uint16_t hdg; ///< Compass heading in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX } mavlink_global_position_int_t; #define MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN 28 @@ -53,7 +53,7 @@ typedef struct __mavlink_global_position_int_t * @param vx Ground X Speed (Latitude), expressed as m/s * 100 * @param vy Ground Y Speed (Longitude), expressed as m/s * 100 * @param vz Ground Z Speed (Altitude), expressed as m/s * 100 - * @param hdg Compass heading in degrees * 100, 0.0..359.99 degrees. If unknown, set to: 65535 + * @param hdg Compass heading in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_global_position_int_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, @@ -99,7 +99,7 @@ static inline uint16_t mavlink_msg_global_position_int_pack(uint8_t system_id, u * @brief Pack a global_position_int message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp (milliseconds since system boot) * @param lat Latitude, expressed as * 1E7 @@ -109,7 +109,7 @@ static inline uint16_t mavlink_msg_global_position_int_pack(uint8_t system_id, u * @param vx Ground X Speed (Latitude), expressed as m/s * 100 * @param vy Ground Y Speed (Longitude), expressed as m/s * 100 * @param vz Ground Z Speed (Altitude), expressed as m/s * 100 - * @param hdg Compass heading in degrees * 100, 0.0..359.99 degrees. If unknown, set to: 65535 + * @param hdg Compass heading in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_global_position_int_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, @@ -153,7 +153,7 @@ static inline uint16_t mavlink_msg_global_position_int_pack_chan(uint8_t system_ } /** - * @brief Encode a global_position_int struct into a message + * @brief Encode a global_position_int struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -165,6 +165,20 @@ static inline uint16_t mavlink_msg_global_position_int_encode(uint8_t system_id, return mavlink_msg_global_position_int_pack(system_id, component_id, msg, global_position_int->time_boot_ms, global_position_int->lat, global_position_int->lon, global_position_int->alt, global_position_int->relative_alt, global_position_int->vx, global_position_int->vy, global_position_int->vz, global_position_int->hdg); } +/** + * @brief Encode a global_position_int struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param global_position_int C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_global_position_int_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_global_position_int_t* global_position_int) +{ + return mavlink_msg_global_position_int_pack_chan(system_id, component_id, chan, msg, global_position_int->time_boot_ms, global_position_int->lat, global_position_int->lon, global_position_int->alt, global_position_int->relative_alt, global_position_int->vx, global_position_int->vy, global_position_int->vz, global_position_int->hdg); +} + /** * @brief Send a global_position_int message * @param chan MAVLink channel to send the message @@ -177,7 +191,7 @@ static inline uint16_t mavlink_msg_global_position_int_encode(uint8_t system_id, * @param vx Ground X Speed (Latitude), expressed as m/s * 100 * @param vy Ground Y Speed (Longitude), expressed as m/s * 100 * @param vz Ground Z Speed (Altitude), expressed as m/s * 100 - * @param hdg Compass heading in degrees * 100, 0.0..359.99 degrees. If unknown, set to: 65535 + * @param hdg Compass heading in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS @@ -308,7 +322,7 @@ static inline int16_t mavlink_msg_global_position_int_get_vz(const mavlink_messa /** * @brief Get field hdg from global_position_int message * - * @return Compass heading in degrees * 100, 0.0..359.99 degrees. If unknown, set to: 65535 + * @return Compass heading in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX */ static inline uint16_t mavlink_msg_global_position_int_get_hdg(const mavlink_message_t* msg) { diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_global_position_setpoint_int.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_global_position_setpoint_int.h index 8153628aa80be38248c9d155d9ec87d05626c706..1a1c97199e408ea71f55a91eabec29483d925193 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_global_position_setpoint_int.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_global_position_setpoint_int.h @@ -79,7 +79,7 @@ static inline uint16_t mavlink_msg_global_position_setpoint_int_pack(uint8_t sys * @brief Pack a global_position_setpoint_int message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param coordinate_frame Coordinate frame - valid values are only MAV_FRAME_GLOBAL or MAV_FRAME_GLOBAL_RELATIVE_ALT * @param latitude Latitude (WGS84), in degrees * 1E7 @@ -121,7 +121,7 @@ static inline uint16_t mavlink_msg_global_position_setpoint_int_pack_chan(uint8_ } /** - * @brief Encode a global_position_setpoint_int struct into a message + * @brief Encode a global_position_setpoint_int struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -133,6 +133,20 @@ static inline uint16_t mavlink_msg_global_position_setpoint_int_encode(uint8_t s return mavlink_msg_global_position_setpoint_int_pack(system_id, component_id, msg, global_position_setpoint_int->coordinate_frame, global_position_setpoint_int->latitude, global_position_setpoint_int->longitude, global_position_setpoint_int->altitude, global_position_setpoint_int->yaw); } +/** + * @brief Encode a global_position_setpoint_int struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param global_position_setpoint_int C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_global_position_setpoint_int_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_global_position_setpoint_int_t* global_position_setpoint_int) +{ + return mavlink_msg_global_position_setpoint_int_pack_chan(system_id, component_id, chan, msg, global_position_setpoint_int->coordinate_frame, global_position_setpoint_int->latitude, global_position_setpoint_int->longitude, global_position_setpoint_int->altitude, global_position_setpoint_int->yaw); +} + /** * @brief Send a global_position_setpoint_int message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_global_vision_position_estimate.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_global_vision_position_estimate.h index b388fa24add458a3558bb87cf9a597b37d7b67c1..f7be74c9176a5c8b51843a10397bfa9b40ec08ca 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_global_vision_position_estimate.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_global_vision_position_estimate.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_global_vision_position_estimate_pack(uint8_t * @brief Pack a global_vision_position_estimate message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param usec Timestamp (microseconds, synced to UNIX time or since system boot) * @param x Global X position @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_global_vision_position_estimate_pack_chan(uin } /** - * @brief Encode a global_vision_position_estimate struct into a message + * @brief Encode a global_vision_position_estimate struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_global_vision_position_estimate_encode(uint8_ return mavlink_msg_global_vision_position_estimate_pack(system_id, component_id, msg, global_vision_position_estimate->usec, global_vision_position_estimate->x, global_vision_position_estimate->y, global_vision_position_estimate->z, global_vision_position_estimate->roll, global_vision_position_estimate->pitch, global_vision_position_estimate->yaw); } +/** + * @brief Encode a global_vision_position_estimate struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param global_vision_position_estimate C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_global_vision_position_estimate_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_global_vision_position_estimate_t* global_vision_position_estimate) +{ + return mavlink_msg_global_vision_position_estimate_pack_chan(system_id, component_id, chan, msg, global_vision_position_estimate->usec, global_vision_position_estimate->x, global_vision_position_estimate->y, global_vision_position_estimate->z, global_vision_position_estimate->roll, global_vision_position_estimate->pitch, global_vision_position_estimate->yaw); +} + /** * @brief Send a global_vision_position_estimate message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_gps_global_origin.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_gps_global_origin.h index bd09cb753447c4aebf4070dac1f22c81e90de5ee..016e9cb0e6db1bfc9b1d0ec95ede62b46229f168 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_gps_global_origin.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_gps_global_origin.h @@ -69,7 +69,7 @@ static inline uint16_t mavlink_msg_gps_global_origin_pack(uint8_t system_id, uin * @brief Pack a gps_global_origin message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param latitude Latitude (WGS84), in degrees * 1E7 * @param longitude Longitude (WGS84), in degrees * 1E7 @@ -105,7 +105,7 @@ static inline uint16_t mavlink_msg_gps_global_origin_pack_chan(uint8_t system_id } /** - * @brief Encode a gps_global_origin struct into a message + * @brief Encode a gps_global_origin struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -117,6 +117,20 @@ static inline uint16_t mavlink_msg_gps_global_origin_encode(uint8_t system_id, u return mavlink_msg_gps_global_origin_pack(system_id, component_id, msg, gps_global_origin->latitude, gps_global_origin->longitude, gps_global_origin->altitude); } +/** + * @brief Encode a gps_global_origin struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param gps_global_origin C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gps_global_origin_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gps_global_origin_t* gps_global_origin) +{ + return mavlink_msg_gps_global_origin_pack_chan(system_id, component_id, chan, msg, gps_global_origin->latitude, gps_global_origin->longitude, gps_global_origin->altitude); +} + /** * @brief Send a gps_global_origin message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_gps_raw_int.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_gps_raw_int.h index 2136b65eef4c6011e570431f1a7d6ae8c0f5c99f..3054d4fdabc6beef4281adb5ac7a02162cc71618 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_gps_raw_int.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_gps_raw_int.h @@ -8,10 +8,10 @@ typedef struct __mavlink_gps_raw_int_t int32_t lat; ///< Latitude (WGS84), in degrees * 1E7 int32_t lon; ///< Longitude (WGS84), in degrees * 1E7 int32_t alt; ///< Altitude (WGS84), in meters * 1000 (positive for up) - uint16_t eph; ///< GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535 - uint16_t epv; ///< GPS VDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535 - uint16_t vel; ///< GPS ground speed (m/s * 100). If unknown, set to: 65535 - uint16_t cog; ///< Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: 65535 + uint16_t eph; ///< GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX + uint16_t epv; ///< GPS VDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX + uint16_t vel; ///< GPS ground speed (m/s * 100). If unknown, set to: UINT16_MAX + uint16_t cog; ///< Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX uint8_t fix_type; ///< 0-1: no fix, 2: 2D fix, 3: 3D fix. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix. uint8_t satellites_visible; ///< Number of satellites visible. If unknown, set to 255 } mavlink_gps_raw_int_t; @@ -52,10 +52,10 @@ typedef struct __mavlink_gps_raw_int_t * @param lat Latitude (WGS84), in degrees * 1E7 * @param lon Longitude (WGS84), in degrees * 1E7 * @param alt Altitude (WGS84), in meters * 1000 (positive for up) - * @param eph GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535 - * @param epv GPS VDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535 - * @param vel GPS ground speed (m/s * 100). If unknown, set to: 65535 - * @param cog Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: 65535 + * @param eph GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX + * @param epv GPS VDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX + * @param vel GPS ground speed (m/s * 100). If unknown, set to: UINT16_MAX + * @param cog Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX * @param satellites_visible Number of satellites visible. If unknown, set to 255 * @return length of the message in bytes (excluding serial stream start sign) */ @@ -104,17 +104,17 @@ static inline uint16_t mavlink_msg_gps_raw_int_pack(uint8_t system_id, uint8_t c * @brief Pack a gps_raw_int message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) * @param fix_type 0-1: no fix, 2: 2D fix, 3: 3D fix. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix. * @param lat Latitude (WGS84), in degrees * 1E7 * @param lon Longitude (WGS84), in degrees * 1E7 * @param alt Altitude (WGS84), in meters * 1000 (positive for up) - * @param eph GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535 - * @param epv GPS VDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535 - * @param vel GPS ground speed (m/s * 100). If unknown, set to: 65535 - * @param cog Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: 65535 + * @param eph GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX + * @param epv GPS VDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX + * @param vel GPS ground speed (m/s * 100). If unknown, set to: UINT16_MAX + * @param cog Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX * @param satellites_visible Number of satellites visible. If unknown, set to 255 * @return length of the message in bytes (excluding serial stream start sign) */ @@ -161,7 +161,7 @@ static inline uint16_t mavlink_msg_gps_raw_int_pack_chan(uint8_t system_id, uint } /** - * @brief Encode a gps_raw_int struct into a message + * @brief Encode a gps_raw_int struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -173,6 +173,20 @@ static inline uint16_t mavlink_msg_gps_raw_int_encode(uint8_t system_id, uint8_t return mavlink_msg_gps_raw_int_pack(system_id, component_id, msg, gps_raw_int->time_usec, gps_raw_int->fix_type, gps_raw_int->lat, gps_raw_int->lon, gps_raw_int->alt, gps_raw_int->eph, gps_raw_int->epv, gps_raw_int->vel, gps_raw_int->cog, gps_raw_int->satellites_visible); } +/** + * @brief Encode a gps_raw_int struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param gps_raw_int C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gps_raw_int_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gps_raw_int_t* gps_raw_int) +{ + return mavlink_msg_gps_raw_int_pack_chan(system_id, component_id, chan, msg, gps_raw_int->time_usec, gps_raw_int->fix_type, gps_raw_int->lat, gps_raw_int->lon, gps_raw_int->alt, gps_raw_int->eph, gps_raw_int->epv, gps_raw_int->vel, gps_raw_int->cog, gps_raw_int->satellites_visible); +} + /** * @brief Send a gps_raw_int message * @param chan MAVLink channel to send the message @@ -182,10 +196,10 @@ static inline uint16_t mavlink_msg_gps_raw_int_encode(uint8_t system_id, uint8_t * @param lat Latitude (WGS84), in degrees * 1E7 * @param lon Longitude (WGS84), in degrees * 1E7 * @param alt Altitude (WGS84), in meters * 1000 (positive for up) - * @param eph GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535 - * @param epv GPS VDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535 - * @param vel GPS ground speed (m/s * 100). If unknown, set to: 65535 - * @param cog Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: 65535 + * @param eph GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX + * @param epv GPS VDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX + * @param vel GPS ground speed (m/s * 100). If unknown, set to: UINT16_MAX + * @param cog Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX * @param satellites_visible Number of satellites visible. If unknown, set to 255 */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS @@ -289,7 +303,7 @@ static inline int32_t mavlink_msg_gps_raw_int_get_alt(const mavlink_message_t* m /** * @brief Get field eph from gps_raw_int message * - * @return GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535 + * @return GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX */ static inline uint16_t mavlink_msg_gps_raw_int_get_eph(const mavlink_message_t* msg) { @@ -299,7 +313,7 @@ static inline uint16_t mavlink_msg_gps_raw_int_get_eph(const mavlink_message_t* /** * @brief Get field epv from gps_raw_int message * - * @return GPS VDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535 + * @return GPS VDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX */ static inline uint16_t mavlink_msg_gps_raw_int_get_epv(const mavlink_message_t* msg) { @@ -309,7 +323,7 @@ static inline uint16_t mavlink_msg_gps_raw_int_get_epv(const mavlink_message_t* /** * @brief Get field vel from gps_raw_int message * - * @return GPS ground speed (m/s * 100). If unknown, set to: 65535 + * @return GPS ground speed (m/s * 100). If unknown, set to: UINT16_MAX */ static inline uint16_t mavlink_msg_gps_raw_int_get_vel(const mavlink_message_t* msg) { @@ -319,7 +333,7 @@ static inline uint16_t mavlink_msg_gps_raw_int_get_vel(const mavlink_message_t* /** * @brief Get field cog from gps_raw_int message * - * @return Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: 65535 + * @return Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX */ static inline uint16_t mavlink_msg_gps_raw_int_get_cog(const mavlink_message_t* msg) { diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_gps_status.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_gps_status.h index cd6dde700f575f12ad69c60043879b6baa40d3dc..28d6b57d19b43f69db5214c313759364d1d7b99c 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_gps_status.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_gps_status.h @@ -86,7 +86,7 @@ static inline uint16_t mavlink_msg_gps_status_pack(uint8_t system_id, uint8_t co * @brief Pack a gps_status message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param satellites_visible Number of satellites visible * @param satellite_prn Global satellite ID @@ -129,7 +129,7 @@ static inline uint16_t mavlink_msg_gps_status_pack_chan(uint8_t system_id, uint8 } /** - * @brief Encode a gps_status struct into a message + * @brief Encode a gps_status struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -141,6 +141,20 @@ static inline uint16_t mavlink_msg_gps_status_encode(uint8_t system_id, uint8_t return mavlink_msg_gps_status_pack(system_id, component_id, msg, gps_status->satellites_visible, gps_status->satellite_prn, gps_status->satellite_used, gps_status->satellite_elevation, gps_status->satellite_azimuth, gps_status->satellite_snr); } +/** + * @brief Encode a gps_status struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param gps_status C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gps_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gps_status_t* gps_status) +{ + return mavlink_msg_gps_status_pack_chan(system_id, component_id, chan, msg, gps_status->satellites_visible, gps_status->satellite_prn, gps_status->satellite_used, gps_status->satellite_elevation, gps_status->satellite_azimuth, gps_status->satellite_snr); +} + /** * @brief Send a gps_status message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_heartbeat.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_heartbeat.h index b2f0b65d064bb7f183186f63c8026d599de74d40..826138fad14e3d5ca89758e123610878fe4ca7bc 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_heartbeat.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_heartbeat.h @@ -83,7 +83,7 @@ static inline uint16_t mavlink_msg_heartbeat_pack(uint8_t system_id, uint8_t com * @brief Pack a heartbeat message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param type Type of the MAV (quadrotor, helicopter, etc., up to 15 types, defined in MAV_TYPE ENUM) * @param autopilot Autopilot type / class. defined in MAV_AUTOPILOT ENUM @@ -127,7 +127,7 @@ static inline uint16_t mavlink_msg_heartbeat_pack_chan(uint8_t system_id, uint8_ } /** - * @brief Encode a heartbeat struct into a message + * @brief Encode a heartbeat struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -139,6 +139,20 @@ static inline uint16_t mavlink_msg_heartbeat_encode(uint8_t system_id, uint8_t c return mavlink_msg_heartbeat_pack(system_id, component_id, msg, heartbeat->type, heartbeat->autopilot, heartbeat->base_mode, heartbeat->custom_mode, heartbeat->system_status); } +/** + * @brief Encode a heartbeat struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param heartbeat C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_heartbeat_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_heartbeat_t* heartbeat) +{ + return mavlink_msg_heartbeat_pack_chan(system_id, component_id, chan, msg, heartbeat->type, heartbeat->autopilot, heartbeat->base_mode, heartbeat->custom_mode, heartbeat->system_status); +} + /** * @brief Send a heartbeat message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_highres_imu.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_highres_imu.h index 6e7492ea65e236303b9501f8b9df869388e0a1b8..0dcd95ed32ae573917342036bdc95ede98b01ad8 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_highres_imu.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_highres_imu.h @@ -129,7 +129,7 @@ static inline uint16_t mavlink_msg_highres_imu_pack(uint8_t system_id, uint8_t c * @brief Pack a highres_imu message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_usec Timestamp (microseconds, synced to UNIX time or since system boot) * @param xacc X acceleration (m/s^2) @@ -201,7 +201,7 @@ static inline uint16_t mavlink_msg_highres_imu_pack_chan(uint8_t system_id, uint } /** - * @brief Encode a highres_imu struct into a message + * @brief Encode a highres_imu struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -213,6 +213,20 @@ static inline uint16_t mavlink_msg_highres_imu_encode(uint8_t system_id, uint8_t return mavlink_msg_highres_imu_pack(system_id, component_id, msg, highres_imu->time_usec, highres_imu->xacc, highres_imu->yacc, highres_imu->zacc, highres_imu->xgyro, highres_imu->ygyro, highres_imu->zgyro, highres_imu->xmag, highres_imu->ymag, highres_imu->zmag, highres_imu->abs_pressure, highres_imu->diff_pressure, highres_imu->pressure_alt, highres_imu->temperature, highres_imu->fields_updated); } +/** + * @brief Encode a highres_imu struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param highres_imu C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_highres_imu_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_highres_imu_t* highres_imu) +{ + return mavlink_msg_highres_imu_pack_chan(system_id, component_id, chan, msg, highres_imu->time_usec, highres_imu->xacc, highres_imu->yacc, highres_imu->zacc, highres_imu->xgyro, highres_imu->ygyro, highres_imu->zgyro, highres_imu->xmag, highres_imu->ymag, highres_imu->zmag, highres_imu->abs_pressure, highres_imu->diff_pressure, highres_imu->pressure_alt, highres_imu->temperature, highres_imu->fields_updated); +} + /** * @brief Send a highres_imu message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_controls.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_controls.h index 3319d3fd2d0d06fb6dc05a4812c0d447b25f5619..aed5108d055d0b3b898baac5c3bf80b78bef0d24 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_controls.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_controls.h @@ -109,7 +109,7 @@ static inline uint16_t mavlink_msg_hil_controls_pack(uint8_t system_id, uint8_t * @brief Pack a hil_controls message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) * @param roll_ailerons Control output -1 .. 1 @@ -169,7 +169,7 @@ static inline uint16_t mavlink_msg_hil_controls_pack_chan(uint8_t system_id, uin } /** - * @brief Encode a hil_controls struct into a message + * @brief Encode a hil_controls struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -181,6 +181,20 @@ static inline uint16_t mavlink_msg_hil_controls_encode(uint8_t system_id, uint8_ return mavlink_msg_hil_controls_pack(system_id, component_id, msg, hil_controls->time_usec, hil_controls->roll_ailerons, hil_controls->pitch_elevator, hil_controls->yaw_rudder, hil_controls->throttle, hil_controls->aux1, hil_controls->aux2, hil_controls->aux3, hil_controls->aux4, hil_controls->mode, hil_controls->nav_mode); } +/** + * @brief Encode a hil_controls struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param hil_controls C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_hil_controls_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_hil_controls_t* hil_controls) +{ + return mavlink_msg_hil_controls_pack_chan(system_id, component_id, chan, msg, hil_controls->time_usec, hil_controls->roll_ailerons, hil_controls->pitch_elevator, hil_controls->yaw_rudder, hil_controls->throttle, hil_controls->aux1, hil_controls->aux2, hil_controls->aux3, hil_controls->aux4, hil_controls->mode, hil_controls->nav_mode); +} + /** * @brief Send a hil_controls message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_gps.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_gps.h index 75ab6835ddc98ea1c0d3dcc27e8c51495220eca1..36a551872bcc664d9fd6c650e3807cdc33efa3b7 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_gps.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_gps.h @@ -119,7 +119,7 @@ static inline uint16_t mavlink_msg_hil_gps_pack(uint8_t system_id, uint8_t compo * @brief Pack a hil_gps message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) * @param fix_type 0-1: no fix, 2: 2D fix, 3: 3D fix. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix. @@ -185,7 +185,7 @@ static inline uint16_t mavlink_msg_hil_gps_pack_chan(uint8_t system_id, uint8_t } /** - * @brief Encode a hil_gps struct into a message + * @brief Encode a hil_gps struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -197,6 +197,20 @@ static inline uint16_t mavlink_msg_hil_gps_encode(uint8_t system_id, uint8_t com return mavlink_msg_hil_gps_pack(system_id, component_id, msg, hil_gps->time_usec, hil_gps->fix_type, hil_gps->lat, hil_gps->lon, hil_gps->alt, hil_gps->eph, hil_gps->epv, hil_gps->vel, hil_gps->vn, hil_gps->ve, hil_gps->vd, hil_gps->cog, hil_gps->satellites_visible); } +/** + * @brief Encode a hil_gps struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param hil_gps C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_hil_gps_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_hil_gps_t* hil_gps) +{ + return mavlink_msg_hil_gps_pack_chan(system_id, component_id, chan, msg, hil_gps->time_usec, hil_gps->fix_type, hil_gps->lat, hil_gps->lon, hil_gps->alt, hil_gps->eph, hil_gps->epv, hil_gps->vel, hil_gps->vn, hil_gps->ve, hil_gps->vd, hil_gps->cog, hil_gps->satellites_visible); +} + /** * @brief Send a hil_gps message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_optical_flow.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_optical_flow.h index 13e13d47cb7f0d472624b787a833390a6ebf680b..acb1392e14c1e911808ac91757d780d8ea9e5a50 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_optical_flow.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_optical_flow.h @@ -94,7 +94,7 @@ static inline uint16_t mavlink_msg_hil_optical_flow_pack(uint8_t system_id, uint * @brief Pack a hil_optical_flow message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_usec Timestamp (UNIX) * @param sensor_id Sensor ID @@ -145,7 +145,7 @@ static inline uint16_t mavlink_msg_hil_optical_flow_pack_chan(uint8_t system_id, } /** - * @brief Encode a hil_optical_flow struct into a message + * @brief Encode a hil_optical_flow struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -157,6 +157,20 @@ static inline uint16_t mavlink_msg_hil_optical_flow_encode(uint8_t system_id, ui return mavlink_msg_hil_optical_flow_pack(system_id, component_id, msg, hil_optical_flow->time_usec, hil_optical_flow->sensor_id, hil_optical_flow->flow_x, hil_optical_flow->flow_y, hil_optical_flow->flow_comp_m_x, hil_optical_flow->flow_comp_m_y, hil_optical_flow->quality, hil_optical_flow->ground_distance); } +/** + * @brief Encode a hil_optical_flow struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param hil_optical_flow C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_hil_optical_flow_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_hil_optical_flow_t* hil_optical_flow) +{ + return mavlink_msg_hil_optical_flow_pack_chan(system_id, component_id, chan, msg, hil_optical_flow->time_usec, hil_optical_flow->sensor_id, hil_optical_flow->flow_x, hil_optical_flow->flow_y, hil_optical_flow->flow_comp_m_x, hil_optical_flow->flow_comp_m_y, hil_optical_flow->quality, hil_optical_flow->ground_distance); +} + /** * @brief Send a hil_optical_flow message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_rc_inputs_raw.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_rc_inputs_raw.h index f2435dde8716d81732f94bdf28e31e48bd18f317..a42bde50b24faa0774eda0c39aba072b6ae414db 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_rc_inputs_raw.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_rc_inputs_raw.h @@ -124,7 +124,7 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_pack(uint8_t system_id, uin * @brief Pack a hil_rc_inputs_raw message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) * @param chan1_raw RC channel 1 value, in microseconds @@ -193,7 +193,7 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_pack_chan(uint8_t system_id } /** - * @brief Encode a hil_rc_inputs_raw struct into a message + * @brief Encode a hil_rc_inputs_raw struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -205,6 +205,20 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_encode(uint8_t system_id, u return mavlink_msg_hil_rc_inputs_raw_pack(system_id, component_id, msg, hil_rc_inputs_raw->time_usec, hil_rc_inputs_raw->chan1_raw, hil_rc_inputs_raw->chan2_raw, hil_rc_inputs_raw->chan3_raw, hil_rc_inputs_raw->chan4_raw, hil_rc_inputs_raw->chan5_raw, hil_rc_inputs_raw->chan6_raw, hil_rc_inputs_raw->chan7_raw, hil_rc_inputs_raw->chan8_raw, hil_rc_inputs_raw->chan9_raw, hil_rc_inputs_raw->chan10_raw, hil_rc_inputs_raw->chan11_raw, hil_rc_inputs_raw->chan12_raw, hil_rc_inputs_raw->rssi); } +/** + * @brief Encode a hil_rc_inputs_raw struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param hil_rc_inputs_raw C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_hil_rc_inputs_raw_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_hil_rc_inputs_raw_t* hil_rc_inputs_raw) +{ + return mavlink_msg_hil_rc_inputs_raw_pack_chan(system_id, component_id, chan, msg, hil_rc_inputs_raw->time_usec, hil_rc_inputs_raw->chan1_raw, hil_rc_inputs_raw->chan2_raw, hil_rc_inputs_raw->chan3_raw, hil_rc_inputs_raw->chan4_raw, hil_rc_inputs_raw->chan5_raw, hil_rc_inputs_raw->chan6_raw, hil_rc_inputs_raw->chan7_raw, hil_rc_inputs_raw->chan8_raw, hil_rc_inputs_raw->chan9_raw, hil_rc_inputs_raw->chan10_raw, hil_rc_inputs_raw->chan11_raw, hil_rc_inputs_raw->chan12_raw, hil_rc_inputs_raw->rssi); +} + /** * @brief Send a hil_rc_inputs_raw message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_sensor.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_sensor.h index 422e55adc8eddc71e45b766f8eb00c7fadb0cf34..6c2667473d7b42a2ef4451849c0aa0f73c0f3144 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_sensor.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_sensor.h @@ -129,7 +129,7 @@ static inline uint16_t mavlink_msg_hil_sensor_pack(uint8_t system_id, uint8_t co * @brief Pack a hil_sensor message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_usec Timestamp (microseconds, synced to UNIX time or since system boot) * @param xacc X acceleration (m/s^2) @@ -201,7 +201,7 @@ static inline uint16_t mavlink_msg_hil_sensor_pack_chan(uint8_t system_id, uint8 } /** - * @brief Encode a hil_sensor struct into a message + * @brief Encode a hil_sensor struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -213,6 +213,20 @@ static inline uint16_t mavlink_msg_hil_sensor_encode(uint8_t system_id, uint8_t return mavlink_msg_hil_sensor_pack(system_id, component_id, msg, hil_sensor->time_usec, hil_sensor->xacc, hil_sensor->yacc, hil_sensor->zacc, hil_sensor->xgyro, hil_sensor->ygyro, hil_sensor->zgyro, hil_sensor->xmag, hil_sensor->ymag, hil_sensor->zmag, hil_sensor->abs_pressure, hil_sensor->diff_pressure, hil_sensor->pressure_alt, hil_sensor->temperature, hil_sensor->fields_updated); } +/** + * @brief Encode a hil_sensor struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param hil_sensor C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_hil_sensor_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_hil_sensor_t* hil_sensor) +{ + return mavlink_msg_hil_sensor_pack_chan(system_id, component_id, chan, msg, hil_sensor->time_usec, hil_sensor->xacc, hil_sensor->yacc, hil_sensor->zacc, hil_sensor->xgyro, hil_sensor->ygyro, hil_sensor->zgyro, hil_sensor->xmag, hil_sensor->ymag, hil_sensor->zmag, hil_sensor->abs_pressure, hil_sensor->diff_pressure, hil_sensor->pressure_alt, hil_sensor->temperature, hil_sensor->fields_updated); +} + /** * @brief Send a hil_sensor message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_state.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_state.h index 1d3f286649f648515c46cea6b1428b501be8ebfd..bcc85776704a07fe0b8fddeeca41a376a08e0801 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_state.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_state.h @@ -134,7 +134,7 @@ static inline uint16_t mavlink_msg_hil_state_pack(uint8_t system_id, uint8_t com * @brief Pack a hil_state message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) * @param roll Roll angle (rad) @@ -209,7 +209,7 @@ static inline uint16_t mavlink_msg_hil_state_pack_chan(uint8_t system_id, uint8_ } /** - * @brief Encode a hil_state struct into a message + * @brief Encode a hil_state struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -221,6 +221,20 @@ static inline uint16_t mavlink_msg_hil_state_encode(uint8_t system_id, uint8_t c return mavlink_msg_hil_state_pack(system_id, component_id, msg, hil_state->time_usec, hil_state->roll, hil_state->pitch, hil_state->yaw, hil_state->rollspeed, hil_state->pitchspeed, hil_state->yawspeed, hil_state->lat, hil_state->lon, hil_state->alt, hil_state->vx, hil_state->vy, hil_state->vz, hil_state->xacc, hil_state->yacc, hil_state->zacc); } +/** + * @brief Encode a hil_state struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param hil_state C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_hil_state_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_hil_state_t* hil_state) +{ + return mavlink_msg_hil_state_pack_chan(system_id, component_id, chan, msg, hil_state->time_usec, hil_state->roll, hil_state->pitch, hil_state->yaw, hil_state->rollspeed, hil_state->pitchspeed, hil_state->yawspeed, hil_state->lat, hil_state->lon, hil_state->alt, hil_state->vx, hil_state->vy, hil_state->vz, hil_state->xacc, hil_state->yacc, hil_state->zacc); +} + /** * @brief Send a hil_state message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_state_quaternion.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_state_quaternion.h index 0474e64a2b693bbb4ee6cea24a72f4902d88a85f..732176193eef7ac97b63fd553be9797208b8afd2 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_state_quaternion.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_hil_state_quaternion.h @@ -132,7 +132,7 @@ static inline uint16_t mavlink_msg_hil_state_quaternion_pack(uint8_t system_id, * @brief Pack a hil_state_quaternion message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) * @param attitude_quaternion Vehicle attitude expressed as normalized quaternion @@ -205,7 +205,7 @@ static inline uint16_t mavlink_msg_hil_state_quaternion_pack_chan(uint8_t system } /** - * @brief Encode a hil_state_quaternion struct into a message + * @brief Encode a hil_state_quaternion struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -217,6 +217,20 @@ static inline uint16_t mavlink_msg_hil_state_quaternion_encode(uint8_t system_id return mavlink_msg_hil_state_quaternion_pack(system_id, component_id, msg, hil_state_quaternion->time_usec, hil_state_quaternion->attitude_quaternion, hil_state_quaternion->rollspeed, hil_state_quaternion->pitchspeed, hil_state_quaternion->yawspeed, hil_state_quaternion->lat, hil_state_quaternion->lon, hil_state_quaternion->alt, hil_state_quaternion->vx, hil_state_quaternion->vy, hil_state_quaternion->vz, hil_state_quaternion->ind_airspeed, hil_state_quaternion->true_airspeed, hil_state_quaternion->xacc, hil_state_quaternion->yacc, hil_state_quaternion->zacc); } +/** + * @brief Encode a hil_state_quaternion struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param hil_state_quaternion C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_hil_state_quaternion_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_hil_state_quaternion_t* hil_state_quaternion) +{ + return mavlink_msg_hil_state_quaternion_pack_chan(system_id, component_id, chan, msg, hil_state_quaternion->time_usec, hil_state_quaternion->attitude_quaternion, hil_state_quaternion->rollspeed, hil_state_quaternion->pitchspeed, hil_state_quaternion->yawspeed, hil_state_quaternion->lat, hil_state_quaternion->lon, hil_state_quaternion->alt, hil_state_quaternion->vx, hil_state_quaternion->vy, hil_state_quaternion->vz, hil_state_quaternion->ind_airspeed, hil_state_quaternion->true_airspeed, hil_state_quaternion->xacc, hil_state_quaternion->yacc, hil_state_quaternion->zacc); +} + /** * @brief Send a hil_state_quaternion message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_local_position_ned.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_local_position_ned.h index 56723f3d7d3b7ec0d80087513723dfb5665bcade..a0b72c0e1e54fd3f7b7eef1d3e26327b456b4d18 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_local_position_ned.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_local_position_ned.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_local_position_ned_pack(uint8_t system_id, ui * @brief Pack a local_position_ned message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp (milliseconds since system boot) * @param x X Position @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_local_position_ned_pack_chan(uint8_t system_i } /** - * @brief Encode a local_position_ned struct into a message + * @brief Encode a local_position_ned struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_local_position_ned_encode(uint8_t system_id, return mavlink_msg_local_position_ned_pack(system_id, component_id, msg, local_position_ned->time_boot_ms, local_position_ned->x, local_position_ned->y, local_position_ned->z, local_position_ned->vx, local_position_ned->vy, local_position_ned->vz); } +/** + * @brief Encode a local_position_ned struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param local_position_ned C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_local_position_ned_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_local_position_ned_t* local_position_ned) +{ + return mavlink_msg_local_position_ned_pack_chan(system_id, component_id, chan, msg, local_position_ned->time_boot_ms, local_position_ned->x, local_position_ned->y, local_position_ned->z, local_position_ned->vx, local_position_ned->vy, local_position_ned->vz); +} + /** * @brief Send a local_position_ned message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_local_position_ned_system_global_offset.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_local_position_ned_system_global_offset.h index c206a2906b4c0bc206604b04248ed00235c3ad84..8c46862027fbcc85d6c0bf6c4b28f9d3a13468c5 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_local_position_ned_system_global_offset.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_local_position_ned_system_global_offset.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_local_position_ned_system_global_offset_pack( * @brief Pack a local_position_ned_system_global_offset message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp (milliseconds since system boot) * @param x X Position @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_local_position_ned_system_global_offset_pack_ } /** - * @brief Encode a local_position_ned_system_global_offset struct into a message + * @brief Encode a local_position_ned_system_global_offset struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_local_position_ned_system_global_offset_encod return mavlink_msg_local_position_ned_system_global_offset_pack(system_id, component_id, msg, local_position_ned_system_global_offset->time_boot_ms, local_position_ned_system_global_offset->x, local_position_ned_system_global_offset->y, local_position_ned_system_global_offset->z, local_position_ned_system_global_offset->roll, local_position_ned_system_global_offset->pitch, local_position_ned_system_global_offset->yaw); } +/** + * @brief Encode a local_position_ned_system_global_offset struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param local_position_ned_system_global_offset C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_local_position_ned_system_global_offset_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_local_position_ned_system_global_offset_t* local_position_ned_system_global_offset) +{ + return mavlink_msg_local_position_ned_system_global_offset_pack_chan(system_id, component_id, chan, msg, local_position_ned_system_global_offset->time_boot_ms, local_position_ned_system_global_offset->x, local_position_ned_system_global_offset->y, local_position_ned_system_global_offset->z, local_position_ned_system_global_offset->roll, local_position_ned_system_global_offset->pitch, local_position_ned_system_global_offset->yaw); +} + /** * @brief Send a local_position_ned_system_global_offset message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_local_position_setpoint.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_local_position_setpoint.h index 96f35fe625c4761ab61b7c2fbee00ec8e98abfa8..1794815f8ec561dc50adcf9b7285548fb99782be 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_local_position_setpoint.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_local_position_setpoint.h @@ -79,7 +79,7 @@ static inline uint16_t mavlink_msg_local_position_setpoint_pack(uint8_t system_i * @brief Pack a local_position_setpoint message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param coordinate_frame Coordinate frame - valid values are only MAV_FRAME_LOCAL_NED or MAV_FRAME_LOCAL_ENU * @param x x position @@ -121,7 +121,7 @@ static inline uint16_t mavlink_msg_local_position_setpoint_pack_chan(uint8_t sys } /** - * @brief Encode a local_position_setpoint struct into a message + * @brief Encode a local_position_setpoint struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -133,6 +133,20 @@ static inline uint16_t mavlink_msg_local_position_setpoint_encode(uint8_t system return mavlink_msg_local_position_setpoint_pack(system_id, component_id, msg, local_position_setpoint->coordinate_frame, local_position_setpoint->x, local_position_setpoint->y, local_position_setpoint->z, local_position_setpoint->yaw); } +/** + * @brief Encode a local_position_setpoint struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param local_position_setpoint C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_local_position_setpoint_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_local_position_setpoint_t* local_position_setpoint) +{ + return mavlink_msg_local_position_setpoint_pack_chan(system_id, component_id, chan, msg, local_position_setpoint->coordinate_frame, local_position_setpoint->x, local_position_setpoint->y, local_position_setpoint->z, local_position_setpoint->yaw); +} + /** * @brief Send a local_position_setpoint message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_manual_control.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_manual_control.h index c9e4a4f8a59748563cf92bf287bbd4c9860c9e3a..6b6e9e148a0260a902e64be81475b6b33143a93b 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_manual_control.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_manual_control.h @@ -84,7 +84,7 @@ static inline uint16_t mavlink_msg_manual_control_pack(uint8_t system_id, uint8_ * @brief Pack a manual_control message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target The system to be controlled. * @param x X-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to forward(1000)-backward(-1000) movement on a joystick and the pitch of a vehicle. @@ -129,7 +129,7 @@ static inline uint16_t mavlink_msg_manual_control_pack_chan(uint8_t system_id, u } /** - * @brief Encode a manual_control struct into a message + * @brief Encode a manual_control struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -141,6 +141,20 @@ static inline uint16_t mavlink_msg_manual_control_encode(uint8_t system_id, uint return mavlink_msg_manual_control_pack(system_id, component_id, msg, manual_control->target, manual_control->x, manual_control->y, manual_control->z, manual_control->r, manual_control->buttons); } +/** + * @brief Encode a manual_control struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param manual_control C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_manual_control_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_manual_control_t* manual_control) +{ + return mavlink_msg_manual_control_pack_chan(system_id, component_id, chan, msg, manual_control->target, manual_control->x, manual_control->y, manual_control->z, manual_control->r, manual_control->buttons); +} + /** * @brief Send a manual_control message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_manual_setpoint.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_manual_setpoint.h index d59e212921c6494a6571c1241bc1f9ace13b36bf..a694947c12b8bceec096a0346203f51be229670e 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_manual_setpoint.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_manual_setpoint.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_manual_setpoint_pack(uint8_t system_id, uint8 * @brief Pack a manual_setpoint message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp in milliseconds since system boot * @param roll Desired roll rate in radians per second @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_manual_setpoint_pack_chan(uint8_t system_id, } /** - * @brief Encode a manual_setpoint struct into a message + * @brief Encode a manual_setpoint struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_manual_setpoint_encode(uint8_t system_id, uin return mavlink_msg_manual_setpoint_pack(system_id, component_id, msg, manual_setpoint->time_boot_ms, manual_setpoint->roll, manual_setpoint->pitch, manual_setpoint->yaw, manual_setpoint->thrust, manual_setpoint->mode_switch, manual_setpoint->manual_override_switch); } +/** + * @brief Encode a manual_setpoint struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param manual_setpoint C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_manual_setpoint_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_manual_setpoint_t* manual_setpoint) +{ + return mavlink_msg_manual_setpoint_pack_chan(system_id, component_id, chan, msg, manual_setpoint->time_boot_ms, manual_setpoint->roll, manual_setpoint->pitch, manual_setpoint->yaw, manual_setpoint->thrust, manual_setpoint->mode_switch, manual_setpoint->manual_override_switch); +} + /** * @brief Send a manual_setpoint message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_memory_vect.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_memory_vect.h index f8ae21b05cbe8fbd830ce48f7b61d0cda5ed245b..5f79329c25de24f0332e7aa34c7910ab9bf590d6 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_memory_vect.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_memory_vect.h @@ -72,7 +72,7 @@ static inline uint16_t mavlink_msg_memory_vect_pack(uint8_t system_id, uint8_t c * @brief Pack a memory_vect message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param address Starting address of the debug variables * @param ver Version code of the type variable. 0=unknown, type ignored and assumed int16_t. 1=as below @@ -109,7 +109,7 @@ static inline uint16_t mavlink_msg_memory_vect_pack_chan(uint8_t system_id, uint } /** - * @brief Encode a memory_vect struct into a message + * @brief Encode a memory_vect struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -121,6 +121,20 @@ static inline uint16_t mavlink_msg_memory_vect_encode(uint8_t system_id, uint8_t return mavlink_msg_memory_vect_pack(system_id, component_id, msg, memory_vect->address, memory_vect->ver, memory_vect->type, memory_vect->value); } +/** + * @brief Encode a memory_vect struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param memory_vect C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_memory_vect_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_memory_vect_t* memory_vect) +{ + return mavlink_msg_memory_vect_pack_chan(system_id, component_id, chan, msg, memory_vect->address, memory_vect->ver, memory_vect->type, memory_vect->value); +} + /** * @brief Send a memory_vect message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_ack.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_ack.h index 32825647f924bfcd05e3ef20725ec08583db5045..7421d8394a5f7cfda675701361811e3520971bff 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_ack.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_ack.h @@ -69,7 +69,7 @@ static inline uint16_t mavlink_msg_mission_ack_pack(uint8_t system_id, uint8_t c * @brief Pack a mission_ack message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -105,7 +105,7 @@ static inline uint16_t mavlink_msg_mission_ack_pack_chan(uint8_t system_id, uint } /** - * @brief Encode a mission_ack struct into a message + * @brief Encode a mission_ack struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -117,6 +117,20 @@ static inline uint16_t mavlink_msg_mission_ack_encode(uint8_t system_id, uint8_t return mavlink_msg_mission_ack_pack(system_id, component_id, msg, mission_ack->target_system, mission_ack->target_component, mission_ack->type); } +/** + * @brief Encode a mission_ack struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param mission_ack C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mission_ack_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_ack_t* mission_ack) +{ + return mavlink_msg_mission_ack_pack_chan(system_id, component_id, chan, msg, mission_ack->target_system, mission_ack->target_component, mission_ack->type); +} + /** * @brief Send a mission_ack message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_clear_all.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_clear_all.h index 06d2ac2e7976fcd755a0b5b7ed1dad456531d9fa..8f441c8e5c571557c3e948000c34a96628b0ceb2 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_clear_all.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_clear_all.h @@ -64,7 +64,7 @@ static inline uint16_t mavlink_msg_mission_clear_all_pack(uint8_t system_id, uin * @brief Pack a mission_clear_all message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -97,7 +97,7 @@ static inline uint16_t mavlink_msg_mission_clear_all_pack_chan(uint8_t system_id } /** - * @brief Encode a mission_clear_all struct into a message + * @brief Encode a mission_clear_all struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -109,6 +109,20 @@ static inline uint16_t mavlink_msg_mission_clear_all_encode(uint8_t system_id, u return mavlink_msg_mission_clear_all_pack(system_id, component_id, msg, mission_clear_all->target_system, mission_clear_all->target_component); } +/** + * @brief Encode a mission_clear_all struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param mission_clear_all C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mission_clear_all_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_clear_all_t* mission_clear_all) +{ + return mavlink_msg_mission_clear_all_pack_chan(system_id, component_id, chan, msg, mission_clear_all->target_system, mission_clear_all->target_component); +} + /** * @brief Send a mission_clear_all message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_count.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_count.h index b28cec6f6d8ec23b2bdcc31aa323b750e0cb0ea1..eac7793067f294bc95d9f5d849f2ed9ddab8c545 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_count.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_count.h @@ -69,7 +69,7 @@ static inline uint16_t mavlink_msg_mission_count_pack(uint8_t system_id, uint8_t * @brief Pack a mission_count message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -105,7 +105,7 @@ static inline uint16_t mavlink_msg_mission_count_pack_chan(uint8_t system_id, ui } /** - * @brief Encode a mission_count struct into a message + * @brief Encode a mission_count struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -117,6 +117,20 @@ static inline uint16_t mavlink_msg_mission_count_encode(uint8_t system_id, uint8 return mavlink_msg_mission_count_pack(system_id, component_id, msg, mission_count->target_system, mission_count->target_component, mission_count->count); } +/** + * @brief Encode a mission_count struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param mission_count C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mission_count_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_count_t* mission_count) +{ + return mavlink_msg_mission_count_pack_chan(system_id, component_id, chan, msg, mission_count->target_system, mission_count->target_component, mission_count->count); +} + /** * @brief Send a mission_count message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_current.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_current.h index 5bf0899beac5b85bab96dc56c737a10a9329942e..dbcdbd3f9cd81c795506139f765df3e8fcd79b8d 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_current.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_current.h @@ -59,7 +59,7 @@ static inline uint16_t mavlink_msg_mission_current_pack(uint8_t system_id, uint8 * @brief Pack a mission_current message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param seq Sequence * @return length of the message in bytes (excluding serial stream start sign) @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_mission_current_pack_chan(uint8_t system_id, } /** - * @brief Encode a mission_current struct into a message + * @brief Encode a mission_current struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -101,6 +101,20 @@ static inline uint16_t mavlink_msg_mission_current_encode(uint8_t system_id, uin return mavlink_msg_mission_current_pack(system_id, component_id, msg, mission_current->seq); } +/** + * @brief Encode a mission_current struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param mission_current C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mission_current_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_current_t* mission_current) +{ + return mavlink_msg_mission_current_pack_chan(system_id, component_id, chan, msg, mission_current->seq); +} + /** * @brief Send a mission_current message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_item.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_item.h index ed9d6e4af71c3145a85831f669608644d0ee8c76..634f80c379cd3b1182d217cc4961379fabe48f11 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_item.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_item.h @@ -124,7 +124,7 @@ static inline uint16_t mavlink_msg_mission_item_pack(uint8_t system_id, uint8_t * @brief Pack a mission_item message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -193,7 +193,7 @@ static inline uint16_t mavlink_msg_mission_item_pack_chan(uint8_t system_id, uin } /** - * @brief Encode a mission_item struct into a message + * @brief Encode a mission_item struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -205,6 +205,20 @@ static inline uint16_t mavlink_msg_mission_item_encode(uint8_t system_id, uint8_ return mavlink_msg_mission_item_pack(system_id, component_id, msg, mission_item->target_system, mission_item->target_component, mission_item->seq, mission_item->frame, mission_item->command, mission_item->current, mission_item->autocontinue, mission_item->param1, mission_item->param2, mission_item->param3, mission_item->param4, mission_item->x, mission_item->y, mission_item->z); } +/** + * @brief Encode a mission_item struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param mission_item C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mission_item_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_item_t* mission_item) +{ + return mavlink_msg_mission_item_pack_chan(system_id, component_id, chan, msg, mission_item->target_system, mission_item->target_component, mission_item->seq, mission_item->frame, mission_item->command, mission_item->current, mission_item->autocontinue, mission_item->param1, mission_item->param2, mission_item->param3, mission_item->param4, mission_item->x, mission_item->y, mission_item->z); +} + /** * @brief Send a mission_item message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_item_reached.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_item_reached.h index 3f8a51a13485abd25dabc9b9ac306e0fb8a29ca2..f3744fde6cf6005b992072b70edf0c68790e2f85 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_item_reached.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_item_reached.h @@ -59,7 +59,7 @@ static inline uint16_t mavlink_msg_mission_item_reached_pack(uint8_t system_id, * @brief Pack a mission_item_reached message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param seq Sequence * @return length of the message in bytes (excluding serial stream start sign) @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_mission_item_reached_pack_chan(uint8_t system } /** - * @brief Encode a mission_item_reached struct into a message + * @brief Encode a mission_item_reached struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -101,6 +101,20 @@ static inline uint16_t mavlink_msg_mission_item_reached_encode(uint8_t system_id return mavlink_msg_mission_item_reached_pack(system_id, component_id, msg, mission_item_reached->seq); } +/** + * @brief Encode a mission_item_reached struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param mission_item_reached C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mission_item_reached_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_item_reached_t* mission_item_reached) +{ + return mavlink_msg_mission_item_reached_pack_chan(system_id, component_id, chan, msg, mission_item_reached->seq); +} + /** * @brief Send a mission_item_reached message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_request.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_request.h index 0ced17614e7e83e4bde1633e5a58c7d2bc30f314..ac84e355404de83d4db45843d069e8a81a47207a 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_request.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_request.h @@ -69,7 +69,7 @@ static inline uint16_t mavlink_msg_mission_request_pack(uint8_t system_id, uint8 * @brief Pack a mission_request message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -105,7 +105,7 @@ static inline uint16_t mavlink_msg_mission_request_pack_chan(uint8_t system_id, } /** - * @brief Encode a mission_request struct into a message + * @brief Encode a mission_request struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -117,6 +117,20 @@ static inline uint16_t mavlink_msg_mission_request_encode(uint8_t system_id, uin return mavlink_msg_mission_request_pack(system_id, component_id, msg, mission_request->target_system, mission_request->target_component, mission_request->seq); } +/** + * @brief Encode a mission_request struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param mission_request C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mission_request_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_request_t* mission_request) +{ + return mavlink_msg_mission_request_pack_chan(system_id, component_id, chan, msg, mission_request->target_system, mission_request->target_component, mission_request->seq); +} + /** * @brief Send a mission_request message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_request_list.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_request_list.h index 391df7f4daace3d29ad6982894265352284443f2..d999babdbd730fb7704f6b3a39fab3753391659e 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_request_list.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_request_list.h @@ -64,7 +64,7 @@ static inline uint16_t mavlink_msg_mission_request_list_pack(uint8_t system_id, * @brief Pack a mission_request_list message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -97,7 +97,7 @@ static inline uint16_t mavlink_msg_mission_request_list_pack_chan(uint8_t system } /** - * @brief Encode a mission_request_list struct into a message + * @brief Encode a mission_request_list struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -109,6 +109,20 @@ static inline uint16_t mavlink_msg_mission_request_list_encode(uint8_t system_id return mavlink_msg_mission_request_list_pack(system_id, component_id, msg, mission_request_list->target_system, mission_request_list->target_component); } +/** + * @brief Encode a mission_request_list struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param mission_request_list C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mission_request_list_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_request_list_t* mission_request_list) +{ + return mavlink_msg_mission_request_list_pack_chan(system_id, component_id, chan, msg, mission_request_list->target_system, mission_request_list->target_component); +} + /** * @brief Send a mission_request_list message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_request_partial_list.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_request_partial_list.h index d5a1c69397362af4793617b17ca1b11100ff4f81..35c7e1285699b9d3799278da12efb558d369da96 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_request_partial_list.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_request_partial_list.h @@ -74,7 +74,7 @@ static inline uint16_t mavlink_msg_mission_request_partial_list_pack(uint8_t sys * @brief Pack a mission_request_partial_list message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -113,7 +113,7 @@ static inline uint16_t mavlink_msg_mission_request_partial_list_pack_chan(uint8_ } /** - * @brief Encode a mission_request_partial_list struct into a message + * @brief Encode a mission_request_partial_list struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -125,6 +125,20 @@ static inline uint16_t mavlink_msg_mission_request_partial_list_encode(uint8_t s return mavlink_msg_mission_request_partial_list_pack(system_id, component_id, msg, mission_request_partial_list->target_system, mission_request_partial_list->target_component, mission_request_partial_list->start_index, mission_request_partial_list->end_index); } +/** + * @brief Encode a mission_request_partial_list struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param mission_request_partial_list C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mission_request_partial_list_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_request_partial_list_t* mission_request_partial_list) +{ + return mavlink_msg_mission_request_partial_list_pack_chan(system_id, component_id, chan, msg, mission_request_partial_list->target_system, mission_request_partial_list->target_component, mission_request_partial_list->start_index, mission_request_partial_list->end_index); +} + /** * @brief Send a mission_request_partial_list message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_set_current.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_set_current.h index 2e145aa3e997c7c17383f98a6ebc958cff74b696..63b37cf8c8f57cca7e21f87d1e9a636630eb4f05 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_set_current.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_set_current.h @@ -69,7 +69,7 @@ static inline uint16_t mavlink_msg_mission_set_current_pack(uint8_t system_id, u * @brief Pack a mission_set_current message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -105,7 +105,7 @@ static inline uint16_t mavlink_msg_mission_set_current_pack_chan(uint8_t system_ } /** - * @brief Encode a mission_set_current struct into a message + * @brief Encode a mission_set_current struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -117,6 +117,20 @@ static inline uint16_t mavlink_msg_mission_set_current_encode(uint8_t system_id, return mavlink_msg_mission_set_current_pack(system_id, component_id, msg, mission_set_current->target_system, mission_set_current->target_component, mission_set_current->seq); } +/** + * @brief Encode a mission_set_current struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param mission_set_current C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mission_set_current_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_set_current_t* mission_set_current) +{ + return mavlink_msg_mission_set_current_pack_chan(system_id, component_id, chan, msg, mission_set_current->target_system, mission_set_current->target_component, mission_set_current->seq); +} + /** * @brief Send a mission_set_current message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_write_partial_list.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_write_partial_list.h index 6342f60383c82824bfd1e8004de200e9392c4043..7de38bd7b5c11b4c7403498e06f75a866aa2592c 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_write_partial_list.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_mission_write_partial_list.h @@ -74,7 +74,7 @@ static inline uint16_t mavlink_msg_mission_write_partial_list_pack(uint8_t syste * @brief Pack a mission_write_partial_list message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -113,7 +113,7 @@ static inline uint16_t mavlink_msg_mission_write_partial_list_pack_chan(uint8_t } /** - * @brief Encode a mission_write_partial_list struct into a message + * @brief Encode a mission_write_partial_list struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -125,6 +125,20 @@ static inline uint16_t mavlink_msg_mission_write_partial_list_encode(uint8_t sys return mavlink_msg_mission_write_partial_list_pack(system_id, component_id, msg, mission_write_partial_list->target_system, mission_write_partial_list->target_component, mission_write_partial_list->start_index, mission_write_partial_list->end_index); } +/** + * @brief Encode a mission_write_partial_list struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param mission_write_partial_list C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mission_write_partial_list_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_write_partial_list_t* mission_write_partial_list) +{ + return mavlink_msg_mission_write_partial_list_pack_chan(system_id, component_id, chan, msg, mission_write_partial_list->target_system, mission_write_partial_list->target_component, mission_write_partial_list->start_index, mission_write_partial_list->end_index); +} + /** * @brief Send a mission_write_partial_list message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_named_value_float.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_named_value_float.h index a9d28a3d05a88c59275954cebdfb49878a756eb6..fbf4f75c95f461d3940f6c232b80e2fabff7040c 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_named_value_float.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_named_value_float.h @@ -67,7 +67,7 @@ static inline uint16_t mavlink_msg_named_value_float_pack(uint8_t system_id, uin * @brief Pack a named_value_float message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp (milliseconds since system boot) * @param name Name of the debug variable @@ -101,7 +101,7 @@ static inline uint16_t mavlink_msg_named_value_float_pack_chan(uint8_t system_id } /** - * @brief Encode a named_value_float struct into a message + * @brief Encode a named_value_float struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -113,6 +113,20 @@ static inline uint16_t mavlink_msg_named_value_float_encode(uint8_t system_id, u return mavlink_msg_named_value_float_pack(system_id, component_id, msg, named_value_float->time_boot_ms, named_value_float->name, named_value_float->value); } +/** + * @brief Encode a named_value_float struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param named_value_float C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_named_value_float_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_named_value_float_t* named_value_float) +{ + return mavlink_msg_named_value_float_pack_chan(system_id, component_id, chan, msg, named_value_float->time_boot_ms, named_value_float->name, named_value_float->value); +} + /** * @brief Send a named_value_float message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_named_value_int.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_named_value_int.h index ea53ea888d2cfa824a597a01c85bdd5805bc71a0..052f2479357680e7445e3254675abd3c983630c5 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_named_value_int.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_named_value_int.h @@ -67,7 +67,7 @@ static inline uint16_t mavlink_msg_named_value_int_pack(uint8_t system_id, uint8 * @brief Pack a named_value_int message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp (milliseconds since system boot) * @param name Name of the debug variable @@ -101,7 +101,7 @@ static inline uint16_t mavlink_msg_named_value_int_pack_chan(uint8_t system_id, } /** - * @brief Encode a named_value_int struct into a message + * @brief Encode a named_value_int struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -113,6 +113,20 @@ static inline uint16_t mavlink_msg_named_value_int_encode(uint8_t system_id, uin return mavlink_msg_named_value_int_pack(system_id, component_id, msg, named_value_int->time_boot_ms, named_value_int->name, named_value_int->value); } +/** + * @brief Encode a named_value_int struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param named_value_int C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_named_value_int_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_named_value_int_t* named_value_int) +{ + return mavlink_msg_named_value_int_pack_chan(system_id, component_id, chan, msg, named_value_int->time_boot_ms, named_value_int->name, named_value_int->value); +} + /** * @brief Send a named_value_int message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_nav_controller_output.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_nav_controller_output.h index e9fa0f522008dc5fcb91008bd043d780ea5df9bf..e95c144de7aab320d6a3301077ba2a36ca60e30b 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_nav_controller_output.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_nav_controller_output.h @@ -94,7 +94,7 @@ static inline uint16_t mavlink_msg_nav_controller_output_pack(uint8_t system_id, * @brief Pack a nav_controller_output message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param nav_roll Current desired roll in degrees * @param nav_pitch Current desired pitch in degrees @@ -145,7 +145,7 @@ static inline uint16_t mavlink_msg_nav_controller_output_pack_chan(uint8_t syste } /** - * @brief Encode a nav_controller_output struct into a message + * @brief Encode a nav_controller_output struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -157,6 +157,20 @@ static inline uint16_t mavlink_msg_nav_controller_output_encode(uint8_t system_i return mavlink_msg_nav_controller_output_pack(system_id, component_id, msg, nav_controller_output->nav_roll, nav_controller_output->nav_pitch, nav_controller_output->nav_bearing, nav_controller_output->target_bearing, nav_controller_output->wp_dist, nav_controller_output->alt_error, nav_controller_output->aspd_error, nav_controller_output->xtrack_error); } +/** + * @brief Encode a nav_controller_output struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param nav_controller_output C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_nav_controller_output_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_nav_controller_output_t* nav_controller_output) +{ + return mavlink_msg_nav_controller_output_pack_chan(system_id, component_id, chan, msg, nav_controller_output->nav_roll, nav_controller_output->nav_pitch, nav_controller_output->nav_bearing, nav_controller_output->target_bearing, nav_controller_output->wp_dist, nav_controller_output->alt_error, nav_controller_output->aspd_error, nav_controller_output->xtrack_error); +} + /** * @brief Send a nav_controller_output message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_omnidirectional_flow.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_omnidirectional_flow.h index c0e765a444fd9816edbaef3d9b90fd37e5502f50..4debb6e6630d5783804e68d7364cd0e5814e874b 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_omnidirectional_flow.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_omnidirectional_flow.h @@ -83,7 +83,7 @@ static inline uint16_t mavlink_msg_omnidirectional_flow_pack(uint8_t system_id, * @brief Pack a omnidirectional_flow message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_usec Timestamp (microseconds, synced to UNIX time or since system boot) * @param sensor_id Sensor ID @@ -126,7 +126,7 @@ static inline uint16_t mavlink_msg_omnidirectional_flow_pack_chan(uint8_t system } /** - * @brief Encode a omnidirectional_flow struct into a message + * @brief Encode a omnidirectional_flow struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -138,6 +138,20 @@ static inline uint16_t mavlink_msg_omnidirectional_flow_encode(uint8_t system_id return mavlink_msg_omnidirectional_flow_pack(system_id, component_id, msg, omnidirectional_flow->time_usec, omnidirectional_flow->sensor_id, omnidirectional_flow->left, omnidirectional_flow->right, omnidirectional_flow->quality, omnidirectional_flow->front_distance_m); } +/** + * @brief Encode a omnidirectional_flow struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param omnidirectional_flow C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_omnidirectional_flow_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_omnidirectional_flow_t* omnidirectional_flow) +{ + return mavlink_msg_omnidirectional_flow_pack_chan(system_id, component_id, chan, msg, omnidirectional_flow->time_usec, omnidirectional_flow->sensor_id, omnidirectional_flow->left, omnidirectional_flow->right, omnidirectional_flow->quality, omnidirectional_flow->front_distance_m); +} + /** * @brief Send a omnidirectional_flow message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_optical_flow.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_optical_flow.h index e01dc5e79cf8bfcd62e51e7303c7c54420ae7a5d..cf6db9147e0dd1a75999394d50758e9d58f87be2 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_optical_flow.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_optical_flow.h @@ -8,8 +8,8 @@ typedef struct __mavlink_optical_flow_t float flow_comp_m_x; ///< Flow in meters in x-sensor direction, angular-speed compensated float flow_comp_m_y; ///< Flow in meters in y-sensor direction, angular-speed compensated float ground_distance; ///< Ground distance in meters. Positive value: distance known. Negative value: Unknown distance - int16_t flow_x; ///< Flow in pixels in x-sensor direction - int16_t flow_y; ///< Flow in pixels in y-sensor direction + int16_t flow_x; ///< Flow in pixels * 10 in x-sensor direction (dezi-pixels) + int16_t flow_y; ///< Flow in pixels * 10 in y-sensor direction (dezi-pixels) uint8_t sensor_id; ///< Sensor ID uint8_t quality; ///< Optical flow quality / confidence. 0: bad, 255: maximum quality } mavlink_optical_flow_t; @@ -45,8 +45,8 @@ typedef struct __mavlink_optical_flow_t * * @param time_usec Timestamp (UNIX) * @param sensor_id Sensor ID - * @param flow_x Flow in pixels in x-sensor direction - * @param flow_y Flow in pixels in y-sensor direction + * @param flow_x Flow in pixels * 10 in x-sensor direction (dezi-pixels) + * @param flow_y Flow in pixels * 10 in y-sensor direction (dezi-pixels) * @param flow_comp_m_x Flow in meters in x-sensor direction, angular-speed compensated * @param flow_comp_m_y Flow in meters in y-sensor direction, angular-speed compensated * @param quality Optical flow quality / confidence. 0: bad, 255: maximum quality @@ -94,12 +94,12 @@ static inline uint16_t mavlink_msg_optical_flow_pack(uint8_t system_id, uint8_t * @brief Pack a optical_flow message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_usec Timestamp (UNIX) * @param sensor_id Sensor ID - * @param flow_x Flow in pixels in x-sensor direction - * @param flow_y Flow in pixels in y-sensor direction + * @param flow_x Flow in pixels * 10 in x-sensor direction (dezi-pixels) + * @param flow_y Flow in pixels * 10 in y-sensor direction (dezi-pixels) * @param flow_comp_m_x Flow in meters in x-sensor direction, angular-speed compensated * @param flow_comp_m_y Flow in meters in y-sensor direction, angular-speed compensated * @param quality Optical flow quality / confidence. 0: bad, 255: maximum quality @@ -145,7 +145,7 @@ static inline uint16_t mavlink_msg_optical_flow_pack_chan(uint8_t system_id, uin } /** - * @brief Encode a optical_flow struct into a message + * @brief Encode a optical_flow struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -157,14 +157,28 @@ static inline uint16_t mavlink_msg_optical_flow_encode(uint8_t system_id, uint8_ return mavlink_msg_optical_flow_pack(system_id, component_id, msg, optical_flow->time_usec, optical_flow->sensor_id, optical_flow->flow_x, optical_flow->flow_y, optical_flow->flow_comp_m_x, optical_flow->flow_comp_m_y, optical_flow->quality, optical_flow->ground_distance); } +/** + * @brief Encode a optical_flow struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param optical_flow C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_optical_flow_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_optical_flow_t* optical_flow) +{ + return mavlink_msg_optical_flow_pack_chan(system_id, component_id, chan, msg, optical_flow->time_usec, optical_flow->sensor_id, optical_flow->flow_x, optical_flow->flow_y, optical_flow->flow_comp_m_x, optical_flow->flow_comp_m_y, optical_flow->quality, optical_flow->ground_distance); +} + /** * @brief Send a optical_flow message * @param chan MAVLink channel to send the message * * @param time_usec Timestamp (UNIX) * @param sensor_id Sensor ID - * @param flow_x Flow in pixels in x-sensor direction - * @param flow_y Flow in pixels in y-sensor direction + * @param flow_x Flow in pixels * 10 in x-sensor direction (dezi-pixels) + * @param flow_y Flow in pixels * 10 in y-sensor direction (dezi-pixels) * @param flow_comp_m_x Flow in meters in x-sensor direction, angular-speed compensated * @param flow_comp_m_y Flow in meters in y-sensor direction, angular-speed compensated * @param quality Optical flow quality / confidence. 0: bad, 255: maximum quality @@ -237,7 +251,7 @@ static inline uint8_t mavlink_msg_optical_flow_get_sensor_id(const mavlink_messa /** * @brief Get field flow_x from optical_flow message * - * @return Flow in pixels in x-sensor direction + * @return Flow in pixels * 10 in x-sensor direction (dezi-pixels) */ static inline int16_t mavlink_msg_optical_flow_get_flow_x(const mavlink_message_t* msg) { @@ -247,7 +261,7 @@ static inline int16_t mavlink_msg_optical_flow_get_flow_x(const mavlink_message_ /** * @brief Get field flow_y from optical_flow message * - * @return Flow in pixels in y-sensor direction + * @return Flow in pixels * 10 in y-sensor direction (dezi-pixels) */ static inline int16_t mavlink_msg_optical_flow_get_flow_y(const mavlink_message_t* msg) { diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_param_request_list.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_param_request_list.h index da61181b2c9e009c1293690f4d6c0a02c61f7dcc..39e0072741c0db3cf2190a435f9c4d33a6be853a 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_param_request_list.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_param_request_list.h @@ -64,7 +64,7 @@ static inline uint16_t mavlink_msg_param_request_list_pack(uint8_t system_id, ui * @brief Pack a param_request_list message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -97,7 +97,7 @@ static inline uint16_t mavlink_msg_param_request_list_pack_chan(uint8_t system_i } /** - * @brief Encode a param_request_list struct into a message + * @brief Encode a param_request_list struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -109,6 +109,20 @@ static inline uint16_t mavlink_msg_param_request_list_encode(uint8_t system_id, return mavlink_msg_param_request_list_pack(system_id, component_id, msg, param_request_list->target_system, param_request_list->target_component); } +/** + * @brief Encode a param_request_list struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param param_request_list C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_param_request_list_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_param_request_list_t* param_request_list) +{ + return mavlink_msg_param_request_list_pack_chan(system_id, component_id, chan, msg, param_request_list->target_system, param_request_list->target_component); +} + /** * @brief Send a param_request_list message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_param_request_read.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_param_request_read.h index 6b156802609e9648d45f3bea7b722a5d72f39ca3..5d9113114bd6f66fffc64c7b534e0e4efda542ae 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_param_request_read.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_param_request_read.h @@ -72,7 +72,7 @@ static inline uint16_t mavlink_msg_param_request_read_pack(uint8_t system_id, ui * @brief Pack a param_request_read message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -109,7 +109,7 @@ static inline uint16_t mavlink_msg_param_request_read_pack_chan(uint8_t system_i } /** - * @brief Encode a param_request_read struct into a message + * @brief Encode a param_request_read struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -121,6 +121,20 @@ static inline uint16_t mavlink_msg_param_request_read_encode(uint8_t system_id, return mavlink_msg_param_request_read_pack(system_id, component_id, msg, param_request_read->target_system, param_request_read->target_component, param_request_read->param_id, param_request_read->param_index); } +/** + * @brief Encode a param_request_read struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param param_request_read C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_param_request_read_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_param_request_read_t* param_request_read) +{ + return mavlink_msg_param_request_read_pack_chan(system_id, component_id, chan, msg, param_request_read->target_system, param_request_read->target_component, param_request_read->param_id, param_request_read->param_index); +} + /** * @brief Send a param_request_read message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_param_set.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_param_set.h index 66b0f6629b8b664dcc2c878d058d94d09a9d4107..1bd1f005961d5bbd8834c68dc8282b59d4b98e32 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_param_set.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_param_set.h @@ -77,7 +77,7 @@ static inline uint16_t mavlink_msg_param_set_pack(uint8_t system_id, uint8_t com * @brief Pack a param_set message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -117,7 +117,7 @@ static inline uint16_t mavlink_msg_param_set_pack_chan(uint8_t system_id, uint8_ } /** - * @brief Encode a param_set struct into a message + * @brief Encode a param_set struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -129,6 +129,20 @@ static inline uint16_t mavlink_msg_param_set_encode(uint8_t system_id, uint8_t c return mavlink_msg_param_set_pack(system_id, component_id, msg, param_set->target_system, param_set->target_component, param_set->param_id, param_set->param_value, param_set->param_type); } +/** + * @brief Encode a param_set struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param param_set C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_param_set_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_param_set_t* param_set) +{ + return mavlink_msg_param_set_pack_chan(system_id, component_id, chan, msg, param_set->target_system, param_set->target_component, param_set->param_id, param_set->param_value, param_set->param_type); +} + /** * @brief Send a param_set message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_param_value.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_param_value.h index 5991393746f17c1c2d6cf6fb4e73c305b50e198e..17c759811ffd53afbfd3ae3d6bda649467e49e64 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_param_value.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_param_value.h @@ -77,7 +77,7 @@ static inline uint16_t mavlink_msg_param_value_pack(uint8_t system_id, uint8_t c * @brief Pack a param_value message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param param_id Onboard parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string * @param param_value Onboard parameter value @@ -117,7 +117,7 @@ static inline uint16_t mavlink_msg_param_value_pack_chan(uint8_t system_id, uint } /** - * @brief Encode a param_value struct into a message + * @brief Encode a param_value struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -129,6 +129,20 @@ static inline uint16_t mavlink_msg_param_value_encode(uint8_t system_id, uint8_t return mavlink_msg_param_value_pack(system_id, component_id, msg, param_value->param_id, param_value->param_value, param_value->param_type, param_value->param_count, param_value->param_index); } +/** + * @brief Encode a param_value struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param param_value C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_param_value_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_param_value_t* param_value) +{ + return mavlink_msg_param_value_pack_chan(system_id, component_id, chan, msg, param_value->param_id, param_value->param_value, param_value->param_type, param_value->param_count, param_value->param_index); +} + /** * @brief Send a param_value message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_ping.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_ping.h index 5a4c50907de6d47f89f2aeb43a7bc10dd36ff2d3..0c68ca1765fb55550456e32d0c85ba153f34106d 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_ping.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_ping.h @@ -74,7 +74,7 @@ static inline uint16_t mavlink_msg_ping_pack(uint8_t system_id, uint8_t componen * @brief Pack a ping message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_usec Unix timestamp in microseconds * @param seq PING sequence @@ -113,7 +113,7 @@ static inline uint16_t mavlink_msg_ping_pack_chan(uint8_t system_id, uint8_t com } /** - * @brief Encode a ping struct into a message + * @brief Encode a ping struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -125,6 +125,20 @@ static inline uint16_t mavlink_msg_ping_encode(uint8_t system_id, uint8_t compon return mavlink_msg_ping_pack(system_id, component_id, msg, ping->time_usec, ping->seq, ping->target_system, ping->target_component); } +/** + * @brief Encode a ping struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param ping C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_ping_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_ping_t* ping) +{ + return mavlink_msg_ping_pack_chan(system_id, component_id, chan, msg, ping->time_usec, ping->seq, ping->target_system, ping->target_component); +} + /** * @brief Send a ping message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_radio_status.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_radio_status.h index 06e6a55425586a85f70fdb276d83403256fc7915..fceb7d1688e7be667835c6ec4f353b1db599b273 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_radio_status.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_radio_status.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_radio_status_pack(uint8_t system_id, uint8_t * @brief Pack a radio_status message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param rssi local signal strength * @param remrssi remote signal strength @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_radio_status_pack_chan(uint8_t system_id, uin } /** - * @brief Encode a radio_status struct into a message + * @brief Encode a radio_status struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_radio_status_encode(uint8_t system_id, uint8_ return mavlink_msg_radio_status_pack(system_id, component_id, msg, radio_status->rssi, radio_status->remrssi, radio_status->txbuf, radio_status->noise, radio_status->remnoise, radio_status->rxerrors, radio_status->fixed); } +/** + * @brief Encode a radio_status struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param radio_status C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_radio_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_radio_status_t* radio_status) +{ + return mavlink_msg_radio_status_pack_chan(system_id, component_id, chan, msg, radio_status->rssi, radio_status->remrssi, radio_status->txbuf, radio_status->noise, radio_status->remnoise, radio_status->rxerrors, radio_status->fixed); +} + /** * @brief Send a radio_status message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_raw_imu.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_raw_imu.h index ce88636473d4131d20e3ea26d53b78dbf2cdefe4..62a9b6eeaee58b283d9529d8f2b6dc82a008711d 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_raw_imu.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_raw_imu.h @@ -104,7 +104,7 @@ static inline uint16_t mavlink_msg_raw_imu_pack(uint8_t system_id, uint8_t compo * @brief Pack a raw_imu message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) * @param xacc X acceleration (raw) @@ -161,7 +161,7 @@ static inline uint16_t mavlink_msg_raw_imu_pack_chan(uint8_t system_id, uint8_t } /** - * @brief Encode a raw_imu struct into a message + * @brief Encode a raw_imu struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -173,6 +173,20 @@ static inline uint16_t mavlink_msg_raw_imu_encode(uint8_t system_id, uint8_t com return mavlink_msg_raw_imu_pack(system_id, component_id, msg, raw_imu->time_usec, raw_imu->xacc, raw_imu->yacc, raw_imu->zacc, raw_imu->xgyro, raw_imu->ygyro, raw_imu->zgyro, raw_imu->xmag, raw_imu->ymag, raw_imu->zmag); } +/** + * @brief Encode a raw_imu struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param raw_imu C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_raw_imu_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_raw_imu_t* raw_imu) +{ + return mavlink_msg_raw_imu_pack_chan(system_id, component_id, chan, msg, raw_imu->time_usec, raw_imu->xacc, raw_imu->yacc, raw_imu->zacc, raw_imu->xgyro, raw_imu->ygyro, raw_imu->zgyro, raw_imu->xmag, raw_imu->ymag, raw_imu->zmag); +} + /** * @brief Send a raw_imu message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_raw_pressure.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_raw_pressure.h index dcc2cbe063ff22063e2cc51bf1870b26a593eeb6..82c5fad4ab0e169f2c9d94109cc6698398f3d11b 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_raw_pressure.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_raw_pressure.h @@ -79,7 +79,7 @@ static inline uint16_t mavlink_msg_raw_pressure_pack(uint8_t system_id, uint8_t * @brief Pack a raw_pressure message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) * @param press_abs Absolute pressure (raw) @@ -121,7 +121,7 @@ static inline uint16_t mavlink_msg_raw_pressure_pack_chan(uint8_t system_id, uin } /** - * @brief Encode a raw_pressure struct into a message + * @brief Encode a raw_pressure struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -133,6 +133,20 @@ static inline uint16_t mavlink_msg_raw_pressure_encode(uint8_t system_id, uint8_ return mavlink_msg_raw_pressure_pack(system_id, component_id, msg, raw_pressure->time_usec, raw_pressure->press_abs, raw_pressure->press_diff1, raw_pressure->press_diff2, raw_pressure->temperature); } +/** + * @brief Encode a raw_pressure struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param raw_pressure C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_raw_pressure_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_raw_pressure_t* raw_pressure) +{ + return mavlink_msg_raw_pressure_pack_chan(system_id, component_id, chan, msg, raw_pressure->time_usec, raw_pressure->press_abs, raw_pressure->press_diff1, raw_pressure->press_diff2, raw_pressure->temperature); +} + /** * @brief Send a raw_pressure message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_rc_channels_override.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_rc_channels_override.h index 9854a190cebc67e777d0315d3c8659fadaf2b2c3..0d8a1514b1bdb037c11925814dddce521541b728 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_rc_channels_override.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_rc_channels_override.h @@ -4,14 +4,14 @@ typedef struct __mavlink_rc_channels_override_t { - uint16_t chan1_raw; ///< RC channel 1 value, in microseconds - uint16_t chan2_raw; ///< RC channel 2 value, in microseconds - uint16_t chan3_raw; ///< RC channel 3 value, in microseconds - uint16_t chan4_raw; ///< RC channel 4 value, in microseconds - uint16_t chan5_raw; ///< RC channel 5 value, in microseconds - uint16_t chan6_raw; ///< RC channel 6 value, in microseconds - uint16_t chan7_raw; ///< RC channel 7 value, in microseconds - uint16_t chan8_raw; ///< RC channel 8 value, in microseconds + uint16_t chan1_raw; ///< RC channel 1 value, in microseconds. A value of UINT16_MAX means to ignore this field. + uint16_t chan2_raw; ///< RC channel 2 value, in microseconds. A value of UINT16_MAX means to ignore this field. + uint16_t chan3_raw; ///< RC channel 3 value, in microseconds. A value of UINT16_MAX means to ignore this field. + uint16_t chan4_raw; ///< RC channel 4 value, in microseconds. A value of UINT16_MAX means to ignore this field. + uint16_t chan5_raw; ///< RC channel 5 value, in microseconds. A value of UINT16_MAX means to ignore this field. + uint16_t chan6_raw; ///< RC channel 6 value, in microseconds. A value of UINT16_MAX means to ignore this field. + uint16_t chan7_raw; ///< RC channel 7 value, in microseconds. A value of UINT16_MAX means to ignore this field. + uint16_t chan8_raw; ///< RC channel 8 value, in microseconds. A value of UINT16_MAX means to ignore this field. uint8_t target_system; ///< System ID uint8_t target_component; ///< Component ID } mavlink_rc_channels_override_t; @@ -49,14 +49,14 @@ typedef struct __mavlink_rc_channels_override_t * * @param target_system System ID * @param target_component Component ID - * @param chan1_raw RC channel 1 value, in microseconds - * @param chan2_raw RC channel 2 value, in microseconds - * @param chan3_raw RC channel 3 value, in microseconds - * @param chan4_raw RC channel 4 value, in microseconds - * @param chan5_raw RC channel 5 value, in microseconds - * @param chan6_raw RC channel 6 value, in microseconds - * @param chan7_raw RC channel 7 value, in microseconds - * @param chan8_raw RC channel 8 value, in microseconds + * @param chan1_raw RC channel 1 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan2_raw RC channel 2 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan3_raw RC channel 3 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan4_raw RC channel 4 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan5_raw RC channel 5 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan6_raw RC channel 6 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan7_raw RC channel 7 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan8_raw RC channel 8 value, in microseconds. A value of UINT16_MAX means to ignore this field. * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_rc_channels_override_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, @@ -104,18 +104,18 @@ static inline uint16_t mavlink_msg_rc_channels_override_pack(uint8_t system_id, * @brief Pack a rc_channels_override message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID - * @param chan1_raw RC channel 1 value, in microseconds - * @param chan2_raw RC channel 2 value, in microseconds - * @param chan3_raw RC channel 3 value, in microseconds - * @param chan4_raw RC channel 4 value, in microseconds - * @param chan5_raw RC channel 5 value, in microseconds - * @param chan6_raw RC channel 6 value, in microseconds - * @param chan7_raw RC channel 7 value, in microseconds - * @param chan8_raw RC channel 8 value, in microseconds + * @param chan1_raw RC channel 1 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan2_raw RC channel 2 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan3_raw RC channel 3 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan4_raw RC channel 4 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan5_raw RC channel 5 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan6_raw RC channel 6 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan7_raw RC channel 7 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan8_raw RC channel 8 value, in microseconds. A value of UINT16_MAX means to ignore this field. * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_rc_channels_override_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, @@ -161,7 +161,7 @@ static inline uint16_t mavlink_msg_rc_channels_override_pack_chan(uint8_t system } /** - * @brief Encode a rc_channels_override struct into a message + * @brief Encode a rc_channels_override struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -173,20 +173,34 @@ static inline uint16_t mavlink_msg_rc_channels_override_encode(uint8_t system_id return mavlink_msg_rc_channels_override_pack(system_id, component_id, msg, rc_channels_override->target_system, rc_channels_override->target_component, rc_channels_override->chan1_raw, rc_channels_override->chan2_raw, rc_channels_override->chan3_raw, rc_channels_override->chan4_raw, rc_channels_override->chan5_raw, rc_channels_override->chan6_raw, rc_channels_override->chan7_raw, rc_channels_override->chan8_raw); } +/** + * @brief Encode a rc_channels_override struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param rc_channels_override C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_rc_channels_override_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_rc_channels_override_t* rc_channels_override) +{ + return mavlink_msg_rc_channels_override_pack_chan(system_id, component_id, chan, msg, rc_channels_override->target_system, rc_channels_override->target_component, rc_channels_override->chan1_raw, rc_channels_override->chan2_raw, rc_channels_override->chan3_raw, rc_channels_override->chan4_raw, rc_channels_override->chan5_raw, rc_channels_override->chan6_raw, rc_channels_override->chan7_raw, rc_channels_override->chan8_raw); +} + /** * @brief Send a rc_channels_override message * @param chan MAVLink channel to send the message * * @param target_system System ID * @param target_component Component ID - * @param chan1_raw RC channel 1 value, in microseconds - * @param chan2_raw RC channel 2 value, in microseconds - * @param chan3_raw RC channel 3 value, in microseconds - * @param chan4_raw RC channel 4 value, in microseconds - * @param chan5_raw RC channel 5 value, in microseconds - * @param chan6_raw RC channel 6 value, in microseconds - * @param chan7_raw RC channel 7 value, in microseconds - * @param chan8_raw RC channel 8 value, in microseconds + * @param chan1_raw RC channel 1 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan2_raw RC channel 2 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan3_raw RC channel 3 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan4_raw RC channel 4 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan5_raw RC channel 5 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan6_raw RC channel 6 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan7_raw RC channel 7 value, in microseconds. A value of UINT16_MAX means to ignore this field. + * @param chan8_raw RC channel 8 value, in microseconds. A value of UINT16_MAX means to ignore this field. */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS @@ -259,7 +273,7 @@ static inline uint8_t mavlink_msg_rc_channels_override_get_target_component(cons /** * @brief Get field chan1_raw from rc_channels_override message * - * @return RC channel 1 value, in microseconds + * @return RC channel 1 value, in microseconds. A value of UINT16_MAX means to ignore this field. */ static inline uint16_t mavlink_msg_rc_channels_override_get_chan1_raw(const mavlink_message_t* msg) { @@ -269,7 +283,7 @@ static inline uint16_t mavlink_msg_rc_channels_override_get_chan1_raw(const mavl /** * @brief Get field chan2_raw from rc_channels_override message * - * @return RC channel 2 value, in microseconds + * @return RC channel 2 value, in microseconds. A value of UINT16_MAX means to ignore this field. */ static inline uint16_t mavlink_msg_rc_channels_override_get_chan2_raw(const mavlink_message_t* msg) { @@ -279,7 +293,7 @@ static inline uint16_t mavlink_msg_rc_channels_override_get_chan2_raw(const mavl /** * @brief Get field chan3_raw from rc_channels_override message * - * @return RC channel 3 value, in microseconds + * @return RC channel 3 value, in microseconds. A value of UINT16_MAX means to ignore this field. */ static inline uint16_t mavlink_msg_rc_channels_override_get_chan3_raw(const mavlink_message_t* msg) { @@ -289,7 +303,7 @@ static inline uint16_t mavlink_msg_rc_channels_override_get_chan3_raw(const mavl /** * @brief Get field chan4_raw from rc_channels_override message * - * @return RC channel 4 value, in microseconds + * @return RC channel 4 value, in microseconds. A value of UINT16_MAX means to ignore this field. */ static inline uint16_t mavlink_msg_rc_channels_override_get_chan4_raw(const mavlink_message_t* msg) { @@ -299,7 +313,7 @@ static inline uint16_t mavlink_msg_rc_channels_override_get_chan4_raw(const mavl /** * @brief Get field chan5_raw from rc_channels_override message * - * @return RC channel 5 value, in microseconds + * @return RC channel 5 value, in microseconds. A value of UINT16_MAX means to ignore this field. */ static inline uint16_t mavlink_msg_rc_channels_override_get_chan5_raw(const mavlink_message_t* msg) { @@ -309,7 +323,7 @@ static inline uint16_t mavlink_msg_rc_channels_override_get_chan5_raw(const mavl /** * @brief Get field chan6_raw from rc_channels_override message * - * @return RC channel 6 value, in microseconds + * @return RC channel 6 value, in microseconds. A value of UINT16_MAX means to ignore this field. */ static inline uint16_t mavlink_msg_rc_channels_override_get_chan6_raw(const mavlink_message_t* msg) { @@ -319,7 +333,7 @@ static inline uint16_t mavlink_msg_rc_channels_override_get_chan6_raw(const mavl /** * @brief Get field chan7_raw from rc_channels_override message * - * @return RC channel 7 value, in microseconds + * @return RC channel 7 value, in microseconds. A value of UINT16_MAX means to ignore this field. */ static inline uint16_t mavlink_msg_rc_channels_override_get_chan7_raw(const mavlink_message_t* msg) { @@ -329,7 +343,7 @@ static inline uint16_t mavlink_msg_rc_channels_override_get_chan7_raw(const mavl /** * @brief Get field chan8_raw from rc_channels_override message * - * @return RC channel 8 value, in microseconds + * @return RC channel 8 value, in microseconds. A value of UINT16_MAX means to ignore this field. */ static inline uint16_t mavlink_msg_rc_channels_override_get_chan8_raw(const mavlink_message_t* msg) { diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_rc_channels_raw.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_rc_channels_raw.h index 4c1315bed22d0d1ccb1c5e5c8df2ad9d6fee43e7..3c0aed02021e726d206b83555d39dce98d3e2657 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_rc_channels_raw.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_rc_channels_raw.h @@ -5,14 +5,14 @@ typedef struct __mavlink_rc_channels_raw_t { uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - uint16_t chan1_raw; ///< RC channel 1 value, in microseconds. A value of 65535 implies the channel is unused. - uint16_t chan2_raw; ///< RC channel 2 value, in microseconds. A value of 65535 implies the channel is unused. - uint16_t chan3_raw; ///< RC channel 3 value, in microseconds. A value of 65535 implies the channel is unused. - uint16_t chan4_raw; ///< RC channel 4 value, in microseconds. A value of 65535 implies the channel is unused. - uint16_t chan5_raw; ///< RC channel 5 value, in microseconds. A value of 65535 implies the channel is unused. - uint16_t chan6_raw; ///< RC channel 6 value, in microseconds. A value of 65535 implies the channel is unused. - uint16_t chan7_raw; ///< RC channel 7 value, in microseconds. A value of 65535 implies the channel is unused. - uint16_t chan8_raw; ///< RC channel 8 value, in microseconds. A value of 65535 implies the channel is unused. + uint16_t chan1_raw; ///< RC channel 1 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + uint16_t chan2_raw; ///< RC channel 2 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + uint16_t chan3_raw; ///< RC channel 3 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + uint16_t chan4_raw; ///< RC channel 4 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + uint16_t chan5_raw; ///< RC channel 5 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + uint16_t chan6_raw; ///< RC channel 6 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + uint16_t chan7_raw; ///< RC channel 7 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + uint16_t chan8_raw; ///< RC channel 8 value, in microseconds. A value of UINT16_MAX implies the channel is unused. uint8_t port; ///< Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows for more than 8 servos. uint8_t rssi; ///< Receive signal strength indicator, 0: 0%, 100: 100%, 255: invalid/unknown. } mavlink_rc_channels_raw_t; @@ -51,14 +51,14 @@ typedef struct __mavlink_rc_channels_raw_t * * @param time_boot_ms Timestamp (milliseconds since system boot) * @param port Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows for more than 8 servos. - * @param chan1_raw RC channel 1 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan2_raw RC channel 2 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan3_raw RC channel 3 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan4_raw RC channel 4 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan5_raw RC channel 5 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan6_raw RC channel 6 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan7_raw RC channel 7 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan8_raw RC channel 8 value, in microseconds. A value of 65535 implies the channel is unused. + * @param chan1_raw RC channel 1 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan2_raw RC channel 2 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan3_raw RC channel 3 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan4_raw RC channel 4 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan5_raw RC channel 5 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan6_raw RC channel 6 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan7_raw RC channel 7 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan8_raw RC channel 8 value, in microseconds. A value of UINT16_MAX implies the channel is unused. * @param rssi Receive signal strength indicator, 0: 0%, 100: 100%, 255: invalid/unknown. * @return length of the message in bytes (excluding serial stream start sign) */ @@ -109,18 +109,18 @@ static inline uint16_t mavlink_msg_rc_channels_raw_pack(uint8_t system_id, uint8 * @brief Pack a rc_channels_raw message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp (milliseconds since system boot) * @param port Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows for more than 8 servos. - * @param chan1_raw RC channel 1 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan2_raw RC channel 2 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan3_raw RC channel 3 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan4_raw RC channel 4 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan5_raw RC channel 5 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan6_raw RC channel 6 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan7_raw RC channel 7 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan8_raw RC channel 8 value, in microseconds. A value of 65535 implies the channel is unused. + * @param chan1_raw RC channel 1 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan2_raw RC channel 2 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan3_raw RC channel 3 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan4_raw RC channel 4 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan5_raw RC channel 5 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan6_raw RC channel 6 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan7_raw RC channel 7 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan8_raw RC channel 8 value, in microseconds. A value of UINT16_MAX implies the channel is unused. * @param rssi Receive signal strength indicator, 0: 0%, 100: 100%, 255: invalid/unknown. * @return length of the message in bytes (excluding serial stream start sign) */ @@ -169,7 +169,7 @@ static inline uint16_t mavlink_msg_rc_channels_raw_pack_chan(uint8_t system_id, } /** - * @brief Encode a rc_channels_raw struct into a message + * @brief Encode a rc_channels_raw struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -181,20 +181,34 @@ static inline uint16_t mavlink_msg_rc_channels_raw_encode(uint8_t system_id, uin return mavlink_msg_rc_channels_raw_pack(system_id, component_id, msg, rc_channels_raw->time_boot_ms, rc_channels_raw->port, rc_channels_raw->chan1_raw, rc_channels_raw->chan2_raw, rc_channels_raw->chan3_raw, rc_channels_raw->chan4_raw, rc_channels_raw->chan5_raw, rc_channels_raw->chan6_raw, rc_channels_raw->chan7_raw, rc_channels_raw->chan8_raw, rc_channels_raw->rssi); } +/** + * @brief Encode a rc_channels_raw struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param rc_channels_raw C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_rc_channels_raw_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_rc_channels_raw_t* rc_channels_raw) +{ + return mavlink_msg_rc_channels_raw_pack_chan(system_id, component_id, chan, msg, rc_channels_raw->time_boot_ms, rc_channels_raw->port, rc_channels_raw->chan1_raw, rc_channels_raw->chan2_raw, rc_channels_raw->chan3_raw, rc_channels_raw->chan4_raw, rc_channels_raw->chan5_raw, rc_channels_raw->chan6_raw, rc_channels_raw->chan7_raw, rc_channels_raw->chan8_raw, rc_channels_raw->rssi); +} + /** * @brief Send a rc_channels_raw message * @param chan MAVLink channel to send the message * * @param time_boot_ms Timestamp (milliseconds since system boot) * @param port Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows for more than 8 servos. - * @param chan1_raw RC channel 1 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan2_raw RC channel 2 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan3_raw RC channel 3 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan4_raw RC channel 4 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan5_raw RC channel 5 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan6_raw RC channel 6 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan7_raw RC channel 7 value, in microseconds. A value of 65535 implies the channel is unused. - * @param chan8_raw RC channel 8 value, in microseconds. A value of 65535 implies the channel is unused. + * @param chan1_raw RC channel 1 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan2_raw RC channel 2 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan3_raw RC channel 3 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan4_raw RC channel 4 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan5_raw RC channel 5 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan6_raw RC channel 6 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan7_raw RC channel 7 value, in microseconds. A value of UINT16_MAX implies the channel is unused. + * @param chan8_raw RC channel 8 value, in microseconds. A value of UINT16_MAX implies the channel is unused. * @param rssi Receive signal strength indicator, 0: 0%, 100: 100%, 255: invalid/unknown. */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS @@ -270,7 +284,7 @@ static inline uint8_t mavlink_msg_rc_channels_raw_get_port(const mavlink_message /** * @brief Get field chan1_raw from rc_channels_raw message * - * @return RC channel 1 value, in microseconds. A value of 65535 implies the channel is unused. + * @return RC channel 1 value, in microseconds. A value of UINT16_MAX implies the channel is unused. */ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan1_raw(const mavlink_message_t* msg) { @@ -280,7 +294,7 @@ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan1_raw(const mavlink_m /** * @brief Get field chan2_raw from rc_channels_raw message * - * @return RC channel 2 value, in microseconds. A value of 65535 implies the channel is unused. + * @return RC channel 2 value, in microseconds. A value of UINT16_MAX implies the channel is unused. */ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan2_raw(const mavlink_message_t* msg) { @@ -290,7 +304,7 @@ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan2_raw(const mavlink_m /** * @brief Get field chan3_raw from rc_channels_raw message * - * @return RC channel 3 value, in microseconds. A value of 65535 implies the channel is unused. + * @return RC channel 3 value, in microseconds. A value of UINT16_MAX implies the channel is unused. */ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan3_raw(const mavlink_message_t* msg) { @@ -300,7 +314,7 @@ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan3_raw(const mavlink_m /** * @brief Get field chan4_raw from rc_channels_raw message * - * @return RC channel 4 value, in microseconds. A value of 65535 implies the channel is unused. + * @return RC channel 4 value, in microseconds. A value of UINT16_MAX implies the channel is unused. */ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan4_raw(const mavlink_message_t* msg) { @@ -310,7 +324,7 @@ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan4_raw(const mavlink_m /** * @brief Get field chan5_raw from rc_channels_raw message * - * @return RC channel 5 value, in microseconds. A value of 65535 implies the channel is unused. + * @return RC channel 5 value, in microseconds. A value of UINT16_MAX implies the channel is unused. */ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan5_raw(const mavlink_message_t* msg) { @@ -320,7 +334,7 @@ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan5_raw(const mavlink_m /** * @brief Get field chan6_raw from rc_channels_raw message * - * @return RC channel 6 value, in microseconds. A value of 65535 implies the channel is unused. + * @return RC channel 6 value, in microseconds. A value of UINT16_MAX implies the channel is unused. */ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan6_raw(const mavlink_message_t* msg) { @@ -330,7 +344,7 @@ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan6_raw(const mavlink_m /** * @brief Get field chan7_raw from rc_channels_raw message * - * @return RC channel 7 value, in microseconds. A value of 65535 implies the channel is unused. + * @return RC channel 7 value, in microseconds. A value of UINT16_MAX implies the channel is unused. */ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan7_raw(const mavlink_message_t* msg) { @@ -340,7 +354,7 @@ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan7_raw(const mavlink_m /** * @brief Get field chan8_raw from rc_channels_raw message * - * @return RC channel 8 value, in microseconds. A value of 65535 implies the channel is unused. + * @return RC channel 8 value, in microseconds. A value of UINT16_MAX implies the channel is unused. */ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan8_raw(const mavlink_message_t* msg) { diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_rc_channels_scaled.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_rc_channels_scaled.h index be6322bcd3f3c602cda6a98296216a8c5dffad5f..2153ab392888da481e2d74d67767d8db85a1e310 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_rc_channels_scaled.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_rc_channels_scaled.h @@ -5,14 +5,14 @@ typedef struct __mavlink_rc_channels_scaled_t { uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - int16_t chan1_scaled; ///< RC channel 1 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - int16_t chan2_scaled; ///< RC channel 2 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - int16_t chan3_scaled; ///< RC channel 3 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - int16_t chan4_scaled; ///< RC channel 4 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - int16_t chan5_scaled; ///< RC channel 5 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - int16_t chan6_scaled; ///< RC channel 6 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - int16_t chan7_scaled; ///< RC channel 7 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - int16_t chan8_scaled; ///< RC channel 8 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. + int16_t chan1_scaled; ///< RC channel 1 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + int16_t chan2_scaled; ///< RC channel 2 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + int16_t chan3_scaled; ///< RC channel 3 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + int16_t chan4_scaled; ///< RC channel 4 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + int16_t chan5_scaled; ///< RC channel 5 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + int16_t chan6_scaled; ///< RC channel 6 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + int16_t chan7_scaled; ///< RC channel 7 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + int16_t chan8_scaled; ///< RC channel 8 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. uint8_t port; ///< Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows for more than 8 servos. uint8_t rssi; ///< Receive signal strength indicator, 0: 0%, 100: 100%, 255: invalid/unknown. } mavlink_rc_channels_scaled_t; @@ -51,14 +51,14 @@ typedef struct __mavlink_rc_channels_scaled_t * * @param time_boot_ms Timestamp (milliseconds since system boot) * @param port Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows for more than 8 servos. - * @param chan1_scaled RC channel 1 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan2_scaled RC channel 2 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan3_scaled RC channel 3 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan4_scaled RC channel 4 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan5_scaled RC channel 5 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan6_scaled RC channel 6 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan7_scaled RC channel 7 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan8_scaled RC channel 8 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. + * @param chan1_scaled RC channel 1 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan2_scaled RC channel 2 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan3_scaled RC channel 3 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan4_scaled RC channel 4 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan5_scaled RC channel 5 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan6_scaled RC channel 6 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan7_scaled RC channel 7 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan8_scaled RC channel 8 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. * @param rssi Receive signal strength indicator, 0: 0%, 100: 100%, 255: invalid/unknown. * @return length of the message in bytes (excluding serial stream start sign) */ @@ -109,18 +109,18 @@ static inline uint16_t mavlink_msg_rc_channels_scaled_pack(uint8_t system_id, ui * @brief Pack a rc_channels_scaled message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp (milliseconds since system boot) * @param port Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows for more than 8 servos. - * @param chan1_scaled RC channel 1 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan2_scaled RC channel 2 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan3_scaled RC channel 3 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan4_scaled RC channel 4 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan5_scaled RC channel 5 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan6_scaled RC channel 6 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan7_scaled RC channel 7 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan8_scaled RC channel 8 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. + * @param chan1_scaled RC channel 1 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan2_scaled RC channel 2 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan3_scaled RC channel 3 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan4_scaled RC channel 4 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan5_scaled RC channel 5 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan6_scaled RC channel 6 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan7_scaled RC channel 7 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan8_scaled RC channel 8 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. * @param rssi Receive signal strength indicator, 0: 0%, 100: 100%, 255: invalid/unknown. * @return length of the message in bytes (excluding serial stream start sign) */ @@ -169,7 +169,7 @@ static inline uint16_t mavlink_msg_rc_channels_scaled_pack_chan(uint8_t system_i } /** - * @brief Encode a rc_channels_scaled struct into a message + * @brief Encode a rc_channels_scaled struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -181,20 +181,34 @@ static inline uint16_t mavlink_msg_rc_channels_scaled_encode(uint8_t system_id, return mavlink_msg_rc_channels_scaled_pack(system_id, component_id, msg, rc_channels_scaled->time_boot_ms, rc_channels_scaled->port, rc_channels_scaled->chan1_scaled, rc_channels_scaled->chan2_scaled, rc_channels_scaled->chan3_scaled, rc_channels_scaled->chan4_scaled, rc_channels_scaled->chan5_scaled, rc_channels_scaled->chan6_scaled, rc_channels_scaled->chan7_scaled, rc_channels_scaled->chan8_scaled, rc_channels_scaled->rssi); } +/** + * @brief Encode a rc_channels_scaled struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param rc_channels_scaled C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_rc_channels_scaled_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_rc_channels_scaled_t* rc_channels_scaled) +{ + return mavlink_msg_rc_channels_scaled_pack_chan(system_id, component_id, chan, msg, rc_channels_scaled->time_boot_ms, rc_channels_scaled->port, rc_channels_scaled->chan1_scaled, rc_channels_scaled->chan2_scaled, rc_channels_scaled->chan3_scaled, rc_channels_scaled->chan4_scaled, rc_channels_scaled->chan5_scaled, rc_channels_scaled->chan6_scaled, rc_channels_scaled->chan7_scaled, rc_channels_scaled->chan8_scaled, rc_channels_scaled->rssi); +} + /** * @brief Send a rc_channels_scaled message * @param chan MAVLink channel to send the message * * @param time_boot_ms Timestamp (milliseconds since system boot) * @param port Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows for more than 8 servos. - * @param chan1_scaled RC channel 1 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan2_scaled RC channel 2 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan3_scaled RC channel 3 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan4_scaled RC channel 4 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan5_scaled RC channel 5 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan6_scaled RC channel 6 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan7_scaled RC channel 7 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. - * @param chan8_scaled RC channel 8 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. + * @param chan1_scaled RC channel 1 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan2_scaled RC channel 2 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan3_scaled RC channel 3 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan4_scaled RC channel 4 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan5_scaled RC channel 5 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan6_scaled RC channel 6 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan7_scaled RC channel 7 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. + * @param chan8_scaled RC channel 8 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. * @param rssi Receive signal strength indicator, 0: 0%, 100: 100%, 255: invalid/unknown. */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS @@ -270,7 +284,7 @@ static inline uint8_t mavlink_msg_rc_channels_scaled_get_port(const mavlink_mess /** * @brief Get field chan1_scaled from rc_channels_scaled message * - * @return RC channel 1 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. + * @return RC channel 1 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. */ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan1_scaled(const mavlink_message_t* msg) { @@ -280,7 +294,7 @@ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan1_scaled(const mavl /** * @brief Get field chan2_scaled from rc_channels_scaled message * - * @return RC channel 2 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. + * @return RC channel 2 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. */ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan2_scaled(const mavlink_message_t* msg) { @@ -290,7 +304,7 @@ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan2_scaled(const mavl /** * @brief Get field chan3_scaled from rc_channels_scaled message * - * @return RC channel 3 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. + * @return RC channel 3 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. */ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan3_scaled(const mavlink_message_t* msg) { @@ -300,7 +314,7 @@ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan3_scaled(const mavl /** * @brief Get field chan4_scaled from rc_channels_scaled message * - * @return RC channel 4 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. + * @return RC channel 4 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. */ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan4_scaled(const mavlink_message_t* msg) { @@ -310,7 +324,7 @@ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan4_scaled(const mavl /** * @brief Get field chan5_scaled from rc_channels_scaled message * - * @return RC channel 5 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. + * @return RC channel 5 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. */ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan5_scaled(const mavlink_message_t* msg) { @@ -320,7 +334,7 @@ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan5_scaled(const mavl /** * @brief Get field chan6_scaled from rc_channels_scaled message * - * @return RC channel 6 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. + * @return RC channel 6 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. */ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan6_scaled(const mavlink_message_t* msg) { @@ -330,7 +344,7 @@ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan6_scaled(const mavl /** * @brief Get field chan7_scaled from rc_channels_scaled message * - * @return RC channel 7 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. + * @return RC channel 7 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. */ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan7_scaled(const mavlink_message_t* msg) { @@ -340,7 +354,7 @@ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan7_scaled(const mavl /** * @brief Get field chan8_scaled from rc_channels_scaled message * - * @return RC channel 8 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) 32767. + * @return RC channel 8 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. */ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan8_scaled(const mavlink_message_t* msg) { diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_request_data_stream.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_request_data_stream.h index ee21d1fe07b191cbda7e1ec6e4cf13437c8d41f5..c754ad8761da8620ac24946fdb4264eb9caa8b38 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_request_data_stream.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_request_data_stream.h @@ -79,7 +79,7 @@ static inline uint16_t mavlink_msg_request_data_stream_pack(uint8_t system_id, u * @brief Pack a request_data_stream message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system The target requested to send the message stream. * @param target_component The target requested to send the message stream. @@ -121,7 +121,7 @@ static inline uint16_t mavlink_msg_request_data_stream_pack_chan(uint8_t system_ } /** - * @brief Encode a request_data_stream struct into a message + * @brief Encode a request_data_stream struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -133,6 +133,20 @@ static inline uint16_t mavlink_msg_request_data_stream_encode(uint8_t system_id, return mavlink_msg_request_data_stream_pack(system_id, component_id, msg, request_data_stream->target_system, request_data_stream->target_component, request_data_stream->req_stream_id, request_data_stream->req_message_rate, request_data_stream->start_stop); } +/** + * @brief Encode a request_data_stream struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param request_data_stream C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_request_data_stream_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_request_data_stream_t* request_data_stream) +{ + return mavlink_msg_request_data_stream_pack_chan(system_id, component_id, chan, msg, request_data_stream->target_system, request_data_stream->target_component, request_data_stream->req_stream_id, request_data_stream->req_message_rate, request_data_stream->start_stop); +} + /** * @brief Send a request_data_stream message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_roll_pitch_yaw_rates_thrust_setpoint.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_roll_pitch_yaw_rates_thrust_setpoint.h index a7e9df94be42a5ae92b82ccc5cc8857bbd790a8d..ac3ef4fa9fda6b09915ec6301a9ccbb237e8d14a 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_roll_pitch_yaw_rates_thrust_setpoint.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_roll_pitch_yaw_rates_thrust_setpoint.h @@ -79,7 +79,7 @@ static inline uint16_t mavlink_msg_roll_pitch_yaw_rates_thrust_setpoint_pack(uin * @brief Pack a roll_pitch_yaw_rates_thrust_setpoint message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp in milliseconds since system boot * @param roll_rate Desired roll rate in radians per second @@ -121,7 +121,7 @@ static inline uint16_t mavlink_msg_roll_pitch_yaw_rates_thrust_setpoint_pack_cha } /** - * @brief Encode a roll_pitch_yaw_rates_thrust_setpoint struct into a message + * @brief Encode a roll_pitch_yaw_rates_thrust_setpoint struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -133,6 +133,20 @@ static inline uint16_t mavlink_msg_roll_pitch_yaw_rates_thrust_setpoint_encode(u return mavlink_msg_roll_pitch_yaw_rates_thrust_setpoint_pack(system_id, component_id, msg, roll_pitch_yaw_rates_thrust_setpoint->time_boot_ms, roll_pitch_yaw_rates_thrust_setpoint->roll_rate, roll_pitch_yaw_rates_thrust_setpoint->pitch_rate, roll_pitch_yaw_rates_thrust_setpoint->yaw_rate, roll_pitch_yaw_rates_thrust_setpoint->thrust); } +/** + * @brief Encode a roll_pitch_yaw_rates_thrust_setpoint struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param roll_pitch_yaw_rates_thrust_setpoint C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_roll_pitch_yaw_rates_thrust_setpoint_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_roll_pitch_yaw_rates_thrust_setpoint_t* roll_pitch_yaw_rates_thrust_setpoint) +{ + return mavlink_msg_roll_pitch_yaw_rates_thrust_setpoint_pack_chan(system_id, component_id, chan, msg, roll_pitch_yaw_rates_thrust_setpoint->time_boot_ms, roll_pitch_yaw_rates_thrust_setpoint->roll_rate, roll_pitch_yaw_rates_thrust_setpoint->pitch_rate, roll_pitch_yaw_rates_thrust_setpoint->yaw_rate, roll_pitch_yaw_rates_thrust_setpoint->thrust); +} + /** * @brief Send a roll_pitch_yaw_rates_thrust_setpoint message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_roll_pitch_yaw_speed_thrust_setpoint.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_roll_pitch_yaw_speed_thrust_setpoint.h index 517797655ce353b3cdb00545bd0fa4c618e58f61..626477322b1cd1facc71c9b96fef5ab09a2e925a 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_roll_pitch_yaw_speed_thrust_setpoint.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_roll_pitch_yaw_speed_thrust_setpoint.h @@ -79,7 +79,7 @@ static inline uint16_t mavlink_msg_roll_pitch_yaw_speed_thrust_setpoint_pack(uin * @brief Pack a roll_pitch_yaw_speed_thrust_setpoint message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp in milliseconds since system boot * @param roll_speed Desired roll angular speed in rad/s @@ -121,7 +121,7 @@ static inline uint16_t mavlink_msg_roll_pitch_yaw_speed_thrust_setpoint_pack_cha } /** - * @brief Encode a roll_pitch_yaw_speed_thrust_setpoint struct into a message + * @brief Encode a roll_pitch_yaw_speed_thrust_setpoint struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -133,6 +133,20 @@ static inline uint16_t mavlink_msg_roll_pitch_yaw_speed_thrust_setpoint_encode(u return mavlink_msg_roll_pitch_yaw_speed_thrust_setpoint_pack(system_id, component_id, msg, roll_pitch_yaw_speed_thrust_setpoint->time_boot_ms, roll_pitch_yaw_speed_thrust_setpoint->roll_speed, roll_pitch_yaw_speed_thrust_setpoint->pitch_speed, roll_pitch_yaw_speed_thrust_setpoint->yaw_speed, roll_pitch_yaw_speed_thrust_setpoint->thrust); } +/** + * @brief Encode a roll_pitch_yaw_speed_thrust_setpoint struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param roll_pitch_yaw_speed_thrust_setpoint C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_roll_pitch_yaw_speed_thrust_setpoint_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_roll_pitch_yaw_speed_thrust_setpoint_t* roll_pitch_yaw_speed_thrust_setpoint) +{ + return mavlink_msg_roll_pitch_yaw_speed_thrust_setpoint_pack_chan(system_id, component_id, chan, msg, roll_pitch_yaw_speed_thrust_setpoint->time_boot_ms, roll_pitch_yaw_speed_thrust_setpoint->roll_speed, roll_pitch_yaw_speed_thrust_setpoint->pitch_speed, roll_pitch_yaw_speed_thrust_setpoint->yaw_speed, roll_pitch_yaw_speed_thrust_setpoint->thrust); +} + /** * @brief Send a roll_pitch_yaw_speed_thrust_setpoint message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_roll_pitch_yaw_thrust_setpoint.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_roll_pitch_yaw_thrust_setpoint.h index aee036022b0abf15ddc177738119cee017f358f0..ffcdc547b44a6b52c446bdac77ffc86593a84758 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_roll_pitch_yaw_thrust_setpoint.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_roll_pitch_yaw_thrust_setpoint.h @@ -79,7 +79,7 @@ static inline uint16_t mavlink_msg_roll_pitch_yaw_thrust_setpoint_pack(uint8_t s * @brief Pack a roll_pitch_yaw_thrust_setpoint message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp in milliseconds since system boot * @param roll Desired roll angle in radians @@ -121,7 +121,7 @@ static inline uint16_t mavlink_msg_roll_pitch_yaw_thrust_setpoint_pack_chan(uint } /** - * @brief Encode a roll_pitch_yaw_thrust_setpoint struct into a message + * @brief Encode a roll_pitch_yaw_thrust_setpoint struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -133,6 +133,20 @@ static inline uint16_t mavlink_msg_roll_pitch_yaw_thrust_setpoint_encode(uint8_t return mavlink_msg_roll_pitch_yaw_thrust_setpoint_pack(system_id, component_id, msg, roll_pitch_yaw_thrust_setpoint->time_boot_ms, roll_pitch_yaw_thrust_setpoint->roll, roll_pitch_yaw_thrust_setpoint->pitch, roll_pitch_yaw_thrust_setpoint->yaw, roll_pitch_yaw_thrust_setpoint->thrust); } +/** + * @brief Encode a roll_pitch_yaw_thrust_setpoint struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param roll_pitch_yaw_thrust_setpoint C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_roll_pitch_yaw_thrust_setpoint_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_roll_pitch_yaw_thrust_setpoint_t* roll_pitch_yaw_thrust_setpoint) +{ + return mavlink_msg_roll_pitch_yaw_thrust_setpoint_pack_chan(system_id, component_id, chan, msg, roll_pitch_yaw_thrust_setpoint->time_boot_ms, roll_pitch_yaw_thrust_setpoint->roll, roll_pitch_yaw_thrust_setpoint->pitch, roll_pitch_yaw_thrust_setpoint->yaw, roll_pitch_yaw_thrust_setpoint->thrust); +} + /** * @brief Send a roll_pitch_yaw_thrust_setpoint message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_safety_allowed_area.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_safety_allowed_area.h index 100fabf16eb340bd2a35a82bf340a982032c1db5..fcd54cbb78577dfe9c967ba6ecc2e7bc658aff80 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_safety_allowed_area.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_safety_allowed_area.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_safety_allowed_area_pack(uint8_t system_id, u * @brief Pack a safety_allowed_area message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param frame Coordinate frame, as defined by MAV_FRAME enum in mavlink_types.h. Can be either global, GPS, right-handed with Z axis up or local, right handed, Z axis down. * @param p1x x position 1 / Latitude 1 @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_safety_allowed_area_pack_chan(uint8_t system_ } /** - * @brief Encode a safety_allowed_area struct into a message + * @brief Encode a safety_allowed_area struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_safety_allowed_area_encode(uint8_t system_id, return mavlink_msg_safety_allowed_area_pack(system_id, component_id, msg, safety_allowed_area->frame, safety_allowed_area->p1x, safety_allowed_area->p1y, safety_allowed_area->p1z, safety_allowed_area->p2x, safety_allowed_area->p2y, safety_allowed_area->p2z); } +/** + * @brief Encode a safety_allowed_area struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param safety_allowed_area C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_safety_allowed_area_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_safety_allowed_area_t* safety_allowed_area) +{ + return mavlink_msg_safety_allowed_area_pack_chan(system_id, component_id, chan, msg, safety_allowed_area->frame, safety_allowed_area->p1x, safety_allowed_area->p1y, safety_allowed_area->p1z, safety_allowed_area->p2x, safety_allowed_area->p2y, safety_allowed_area->p2z); +} + /** * @brief Send a safety_allowed_area message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_safety_set_allowed_area.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_safety_set_allowed_area.h index d365b7aedc4e1515167ccfb4c2cc7429292eb105..61f6af1554f00117d2a036b0ce445adbf3cc5596 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_safety_set_allowed_area.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_safety_set_allowed_area.h @@ -99,7 +99,7 @@ static inline uint16_t mavlink_msg_safety_set_allowed_area_pack(uint8_t system_i * @brief Pack a safety_set_allowed_area message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -153,7 +153,7 @@ static inline uint16_t mavlink_msg_safety_set_allowed_area_pack_chan(uint8_t sys } /** - * @brief Encode a safety_set_allowed_area struct into a message + * @brief Encode a safety_set_allowed_area struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -165,6 +165,20 @@ static inline uint16_t mavlink_msg_safety_set_allowed_area_encode(uint8_t system return mavlink_msg_safety_set_allowed_area_pack(system_id, component_id, msg, safety_set_allowed_area->target_system, safety_set_allowed_area->target_component, safety_set_allowed_area->frame, safety_set_allowed_area->p1x, safety_set_allowed_area->p1y, safety_set_allowed_area->p1z, safety_set_allowed_area->p2x, safety_set_allowed_area->p2y, safety_set_allowed_area->p2z); } +/** + * @brief Encode a safety_set_allowed_area struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param safety_set_allowed_area C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_safety_set_allowed_area_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_safety_set_allowed_area_t* safety_set_allowed_area) +{ + return mavlink_msg_safety_set_allowed_area_pack_chan(system_id, component_id, chan, msg, safety_set_allowed_area->target_system, safety_set_allowed_area->target_component, safety_set_allowed_area->frame, safety_set_allowed_area->p1x, safety_set_allowed_area->p1y, safety_set_allowed_area->p1z, safety_set_allowed_area->p2x, safety_set_allowed_area->p2y, safety_set_allowed_area->p2z); +} + /** * @brief Send a safety_set_allowed_area message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_scaled_imu.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_scaled_imu.h index 2751ddfe7ae88f2c038b96137247476dbc6f9042..3010d051afee872226e29315101b8887a77f11c8 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_scaled_imu.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_scaled_imu.h @@ -104,7 +104,7 @@ static inline uint16_t mavlink_msg_scaled_imu_pack(uint8_t system_id, uint8_t co * @brief Pack a scaled_imu message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp (milliseconds since system boot) * @param xacc X acceleration (mg) @@ -161,7 +161,7 @@ static inline uint16_t mavlink_msg_scaled_imu_pack_chan(uint8_t system_id, uint8 } /** - * @brief Encode a scaled_imu struct into a message + * @brief Encode a scaled_imu struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -173,6 +173,20 @@ static inline uint16_t mavlink_msg_scaled_imu_encode(uint8_t system_id, uint8_t return mavlink_msg_scaled_imu_pack(system_id, component_id, msg, scaled_imu->time_boot_ms, scaled_imu->xacc, scaled_imu->yacc, scaled_imu->zacc, scaled_imu->xgyro, scaled_imu->ygyro, scaled_imu->zgyro, scaled_imu->xmag, scaled_imu->ymag, scaled_imu->zmag); } +/** + * @brief Encode a scaled_imu struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param scaled_imu C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_scaled_imu_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_scaled_imu_t* scaled_imu) +{ + return mavlink_msg_scaled_imu_pack_chan(system_id, component_id, chan, msg, scaled_imu->time_boot_ms, scaled_imu->xacc, scaled_imu->yacc, scaled_imu->zacc, scaled_imu->xgyro, scaled_imu->ygyro, scaled_imu->zgyro, scaled_imu->xmag, scaled_imu->ymag, scaled_imu->zmag); +} + /** * @brief Send a scaled_imu message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_scaled_pressure.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_scaled_pressure.h index f54e2819586a539622e3fc181edc25a80fd12a16..10324bc9415aae2efa915af5faa677496ebd7164 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_scaled_pressure.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_scaled_pressure.h @@ -74,7 +74,7 @@ static inline uint16_t mavlink_msg_scaled_pressure_pack(uint8_t system_id, uint8 * @brief Pack a scaled_pressure message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp (milliseconds since system boot) * @param press_abs Absolute pressure (hectopascal) @@ -113,7 +113,7 @@ static inline uint16_t mavlink_msg_scaled_pressure_pack_chan(uint8_t system_id, } /** - * @brief Encode a scaled_pressure struct into a message + * @brief Encode a scaled_pressure struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -125,6 +125,20 @@ static inline uint16_t mavlink_msg_scaled_pressure_encode(uint8_t system_id, uin return mavlink_msg_scaled_pressure_pack(system_id, component_id, msg, scaled_pressure->time_boot_ms, scaled_pressure->press_abs, scaled_pressure->press_diff, scaled_pressure->temperature); } +/** + * @brief Encode a scaled_pressure struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param scaled_pressure C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_scaled_pressure_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_scaled_pressure_t* scaled_pressure) +{ + return mavlink_msg_scaled_pressure_pack_chan(system_id, component_id, chan, msg, scaled_pressure->time_boot_ms, scaled_pressure->press_abs, scaled_pressure->press_diff, scaled_pressure->temperature); +} + /** * @brief Send a scaled_pressure message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_servo_output_raw.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_servo_output_raw.h index 10bdcbc8c20abc3cebdd0ed4be4a2e4636b4abea..6a14e93ed36777cb8f1a0a5bf8c73ea969de15c3 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_servo_output_raw.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_servo_output_raw.h @@ -104,7 +104,7 @@ static inline uint16_t mavlink_msg_servo_output_raw_pack(uint8_t system_id, uint * @brief Pack a servo_output_raw message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_usec Timestamp (microseconds since system boot) * @param port Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows to encode more than 8 servos. @@ -161,7 +161,7 @@ static inline uint16_t mavlink_msg_servo_output_raw_pack_chan(uint8_t system_id, } /** - * @brief Encode a servo_output_raw struct into a message + * @brief Encode a servo_output_raw struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -173,6 +173,20 @@ static inline uint16_t mavlink_msg_servo_output_raw_encode(uint8_t system_id, ui return mavlink_msg_servo_output_raw_pack(system_id, component_id, msg, servo_output_raw->time_usec, servo_output_raw->port, servo_output_raw->servo1_raw, servo_output_raw->servo2_raw, servo_output_raw->servo3_raw, servo_output_raw->servo4_raw, servo_output_raw->servo5_raw, servo_output_raw->servo6_raw, servo_output_raw->servo7_raw, servo_output_raw->servo8_raw); } +/** + * @brief Encode a servo_output_raw struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param servo_output_raw C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_servo_output_raw_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_servo_output_raw_t* servo_output_raw) +{ + return mavlink_msg_servo_output_raw_pack_chan(system_id, component_id, chan, msg, servo_output_raw->time_usec, servo_output_raw->port, servo_output_raw->servo1_raw, servo_output_raw->servo2_raw, servo_output_raw->servo3_raw, servo_output_raw->servo4_raw, servo_output_raw->servo5_raw, servo_output_raw->servo6_raw, servo_output_raw->servo7_raw, servo_output_raw->servo8_raw); +} + /** * @brief Send a servo_output_raw message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_global_position_setpoint_int.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_global_position_setpoint_int.h index 0364b42415b7b2fb5c3781a13dec099e643b3e9a..6f0d7a69daa2fa892bfb679f7b66dd82410f0a08 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_global_position_setpoint_int.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_global_position_setpoint_int.h @@ -79,7 +79,7 @@ static inline uint16_t mavlink_msg_set_global_position_setpoint_int_pack(uint8_t * @brief Pack a set_global_position_setpoint_int message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param coordinate_frame Coordinate frame - valid values are only MAV_FRAME_GLOBAL or MAV_FRAME_GLOBAL_RELATIVE_ALT * @param latitude Latitude (WGS84), in degrees * 1E7 @@ -121,7 +121,7 @@ static inline uint16_t mavlink_msg_set_global_position_setpoint_int_pack_chan(ui } /** - * @brief Encode a set_global_position_setpoint_int struct into a message + * @brief Encode a set_global_position_setpoint_int struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -133,6 +133,20 @@ static inline uint16_t mavlink_msg_set_global_position_setpoint_int_encode(uint8 return mavlink_msg_set_global_position_setpoint_int_pack(system_id, component_id, msg, set_global_position_setpoint_int->coordinate_frame, set_global_position_setpoint_int->latitude, set_global_position_setpoint_int->longitude, set_global_position_setpoint_int->altitude, set_global_position_setpoint_int->yaw); } +/** + * @brief Encode a set_global_position_setpoint_int struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param set_global_position_setpoint_int C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_set_global_position_setpoint_int_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_global_position_setpoint_int_t* set_global_position_setpoint_int) +{ + return mavlink_msg_set_global_position_setpoint_int_pack_chan(system_id, component_id, chan, msg, set_global_position_setpoint_int->coordinate_frame, set_global_position_setpoint_int->latitude, set_global_position_setpoint_int->longitude, set_global_position_setpoint_int->altitude, set_global_position_setpoint_int->yaw); +} + /** * @brief Send a set_global_position_setpoint_int message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_gps_global_origin.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_gps_global_origin.h index e3cd4f44191de8d1cde80f98d754b3448a633d30..c444d8d52cf2fb7a3262d93a0f9bb0c61d5adaaf 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_gps_global_origin.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_gps_global_origin.h @@ -74,7 +74,7 @@ static inline uint16_t mavlink_msg_set_gps_global_origin_pack(uint8_t system_id, * @brief Pack a set_gps_global_origin message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param latitude Latitude (WGS84), in degrees * 1E7 @@ -113,7 +113,7 @@ static inline uint16_t mavlink_msg_set_gps_global_origin_pack_chan(uint8_t syste } /** - * @brief Encode a set_gps_global_origin struct into a message + * @brief Encode a set_gps_global_origin struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -125,6 +125,20 @@ static inline uint16_t mavlink_msg_set_gps_global_origin_encode(uint8_t system_i return mavlink_msg_set_gps_global_origin_pack(system_id, component_id, msg, set_gps_global_origin->target_system, set_gps_global_origin->latitude, set_gps_global_origin->longitude, set_gps_global_origin->altitude); } +/** + * @brief Encode a set_gps_global_origin struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param set_gps_global_origin C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_set_gps_global_origin_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_gps_global_origin_t* set_gps_global_origin) +{ + return mavlink_msg_set_gps_global_origin_pack_chan(system_id, component_id, chan, msg, set_gps_global_origin->target_system, set_gps_global_origin->latitude, set_gps_global_origin->longitude, set_gps_global_origin->altitude); +} + /** * @brief Send a set_gps_global_origin message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_local_position_setpoint.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_local_position_setpoint.h index b92c0560e93731db9f2067f94486b02ca4b88be2..6f2835e0312b8f88afd1b6fec21be01b041514af 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_local_position_setpoint.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_local_position_setpoint.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_set_local_position_setpoint_pack(uint8_t syst * @brief Pack a set_local_position_setpoint message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_set_local_position_setpoint_pack_chan(uint8_t } /** - * @brief Encode a set_local_position_setpoint struct into a message + * @brief Encode a set_local_position_setpoint struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_set_local_position_setpoint_encode(uint8_t sy return mavlink_msg_set_local_position_setpoint_pack(system_id, component_id, msg, set_local_position_setpoint->target_system, set_local_position_setpoint->target_component, set_local_position_setpoint->coordinate_frame, set_local_position_setpoint->x, set_local_position_setpoint->y, set_local_position_setpoint->z, set_local_position_setpoint->yaw); } +/** + * @brief Encode a set_local_position_setpoint struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param set_local_position_setpoint C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_set_local_position_setpoint_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_local_position_setpoint_t* set_local_position_setpoint) +{ + return mavlink_msg_set_local_position_setpoint_pack_chan(system_id, component_id, chan, msg, set_local_position_setpoint->target_system, set_local_position_setpoint->target_component, set_local_position_setpoint->coordinate_frame, set_local_position_setpoint->x, set_local_position_setpoint->y, set_local_position_setpoint->z, set_local_position_setpoint->yaw); +} + /** * @brief Send a set_local_position_setpoint message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_mode.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_mode.h index 08ec7330983ec14f3857ad45e6a71ff1a4ca8b88..1aff42cce3c40070a4d21b2756c98d5c08cdc688 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_mode.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_mode.h @@ -69,7 +69,7 @@ static inline uint16_t mavlink_msg_set_mode_pack(uint8_t system_id, uint8_t comp * @brief Pack a set_mode message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system The system setting the mode * @param base_mode The new base mode @@ -105,7 +105,7 @@ static inline uint16_t mavlink_msg_set_mode_pack_chan(uint8_t system_id, uint8_t } /** - * @brief Encode a set_mode struct into a message + * @brief Encode a set_mode struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -117,6 +117,20 @@ static inline uint16_t mavlink_msg_set_mode_encode(uint8_t system_id, uint8_t co return mavlink_msg_set_mode_pack(system_id, component_id, msg, set_mode->target_system, set_mode->base_mode, set_mode->custom_mode); } +/** + * @brief Encode a set_mode struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param set_mode C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_set_mode_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_mode_t* set_mode) +{ + return mavlink_msg_set_mode_pack_chan(system_id, component_id, chan, msg, set_mode->target_system, set_mode->base_mode, set_mode->custom_mode); +} + /** * @brief Send a set_mode message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_quad_motors_setpoint.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_quad_motors_setpoint.h index b79114e1a51da6781d98c0c06ef5b680334047cd..8ceb8888fc5d91af22d7c7b2d9e9860eb53d2e80 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_quad_motors_setpoint.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_quad_motors_setpoint.h @@ -79,7 +79,7 @@ static inline uint16_t mavlink_msg_set_quad_motors_setpoint_pack(uint8_t system_ * @brief Pack a set_quad_motors_setpoint message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID of the system that should set these motor commands * @param motor_front_nw Front motor in + configuration, front left motor in x configuration @@ -121,7 +121,7 @@ static inline uint16_t mavlink_msg_set_quad_motors_setpoint_pack_chan(uint8_t sy } /** - * @brief Encode a set_quad_motors_setpoint struct into a message + * @brief Encode a set_quad_motors_setpoint struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -133,6 +133,20 @@ static inline uint16_t mavlink_msg_set_quad_motors_setpoint_encode(uint8_t syste return mavlink_msg_set_quad_motors_setpoint_pack(system_id, component_id, msg, set_quad_motors_setpoint->target_system, set_quad_motors_setpoint->motor_front_nw, set_quad_motors_setpoint->motor_right_ne, set_quad_motors_setpoint->motor_back_se, set_quad_motors_setpoint->motor_left_sw); } +/** + * @brief Encode a set_quad_motors_setpoint struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param set_quad_motors_setpoint C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_set_quad_motors_setpoint_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_quad_motors_setpoint_t* set_quad_motors_setpoint) +{ + return mavlink_msg_set_quad_motors_setpoint_pack_chan(system_id, component_id, chan, msg, set_quad_motors_setpoint->target_system, set_quad_motors_setpoint->motor_front_nw, set_quad_motors_setpoint->motor_right_ne, set_quad_motors_setpoint->motor_back_se, set_quad_motors_setpoint->motor_left_sw); +} + /** * @brief Send a set_quad_motors_setpoint message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust.h index 06223845f485d8f83a6d66b85a8d037364eea375..9ef294cc97336cce63eb575d1c8d79a9a9c6266e 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust.h @@ -4,10 +4,10 @@ typedef struct __mavlink_set_quad_swarm_led_roll_pitch_yaw_thrust_t { - int16_t roll[4]; ///< Desired roll angle in radians +-PI (+-32767) - int16_t pitch[4]; ///< Desired pitch angle in radians +-PI (+-32767) - int16_t yaw[4]; ///< Desired yaw angle in radians, scaled to int16 +-PI (+-32767) - uint16_t thrust[4]; ///< Collective thrust, scaled to uint16 (0..65535) + int16_t roll[4]; ///< Desired roll angle in radians +-PI (+-INT16_MAX) + int16_t pitch[4]; ///< Desired pitch angle in radians +-PI (+-INT16_MAX) + int16_t yaw[4]; ///< Desired yaw angle in radians, scaled to int16 +-PI (+-INT16_MAX) + uint16_t thrust[4]; ///< Collective thrust, scaled to uint16 (0..UINT16_MAX) uint8_t group; ///< ID of the quadrotor group (0 - 255, up to 256 groups supported) uint8_t mode; ///< ID of the flight mode (0 - 255, up to 256 modes supported) uint8_t led_red[4]; ///< RGB red channel (0-255) @@ -56,10 +56,10 @@ typedef struct __mavlink_set_quad_swarm_led_roll_pitch_yaw_thrust_t * @param led_red RGB red channel (0-255) * @param led_blue RGB green channel (0-255) * @param led_green RGB blue channel (0-255) - * @param roll Desired roll angle in radians +-PI (+-32767) - * @param pitch Desired pitch angle in radians +-PI (+-32767) - * @param yaw Desired yaw angle in radians, scaled to int16 +-PI (+-32767) - * @param thrust Collective thrust, scaled to uint16 (0..65535) + * @param roll Desired roll angle in radians +-PI (+-INT16_MAX) + * @param pitch Desired pitch angle in radians +-PI (+-INT16_MAX) + * @param yaw Desired yaw angle in radians, scaled to int16 +-PI (+-INT16_MAX) + * @param thrust Collective thrust, scaled to uint16 (0..UINT16_MAX) * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, @@ -103,17 +103,17 @@ static inline uint16_t mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust_pack * @brief Pack a set_quad_swarm_led_roll_pitch_yaw_thrust message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param group ID of the quadrotor group (0 - 255, up to 256 groups supported) * @param mode ID of the flight mode (0 - 255, up to 256 modes supported) * @param led_red RGB red channel (0-255) * @param led_blue RGB green channel (0-255) * @param led_green RGB blue channel (0-255) - * @param roll Desired roll angle in radians +-PI (+-32767) - * @param pitch Desired pitch angle in radians +-PI (+-32767) - * @param yaw Desired yaw angle in radians, scaled to int16 +-PI (+-32767) - * @param thrust Collective thrust, scaled to uint16 (0..65535) + * @param roll Desired roll angle in radians +-PI (+-INT16_MAX) + * @param pitch Desired pitch angle in radians +-PI (+-INT16_MAX) + * @param yaw Desired yaw angle in radians, scaled to int16 +-PI (+-INT16_MAX) + * @param thrust Collective thrust, scaled to uint16 (0..UINT16_MAX) * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, @@ -155,7 +155,7 @@ static inline uint16_t mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust_pack } /** - * @brief Encode a set_quad_swarm_led_roll_pitch_yaw_thrust struct into a message + * @brief Encode a set_quad_swarm_led_roll_pitch_yaw_thrust struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -167,6 +167,20 @@ static inline uint16_t mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust_enco return mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust_pack(system_id, component_id, msg, set_quad_swarm_led_roll_pitch_yaw_thrust->group, set_quad_swarm_led_roll_pitch_yaw_thrust->mode, set_quad_swarm_led_roll_pitch_yaw_thrust->led_red, set_quad_swarm_led_roll_pitch_yaw_thrust->led_blue, set_quad_swarm_led_roll_pitch_yaw_thrust->led_green, set_quad_swarm_led_roll_pitch_yaw_thrust->roll, set_quad_swarm_led_roll_pitch_yaw_thrust->pitch, set_quad_swarm_led_roll_pitch_yaw_thrust->yaw, set_quad_swarm_led_roll_pitch_yaw_thrust->thrust); } +/** + * @brief Encode a set_quad_swarm_led_roll_pitch_yaw_thrust struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param set_quad_swarm_led_roll_pitch_yaw_thrust C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_quad_swarm_led_roll_pitch_yaw_thrust_t* set_quad_swarm_led_roll_pitch_yaw_thrust) +{ + return mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust_pack_chan(system_id, component_id, chan, msg, set_quad_swarm_led_roll_pitch_yaw_thrust->group, set_quad_swarm_led_roll_pitch_yaw_thrust->mode, set_quad_swarm_led_roll_pitch_yaw_thrust->led_red, set_quad_swarm_led_roll_pitch_yaw_thrust->led_blue, set_quad_swarm_led_roll_pitch_yaw_thrust->led_green, set_quad_swarm_led_roll_pitch_yaw_thrust->roll, set_quad_swarm_led_roll_pitch_yaw_thrust->pitch, set_quad_swarm_led_roll_pitch_yaw_thrust->yaw, set_quad_swarm_led_roll_pitch_yaw_thrust->thrust); +} + /** * @brief Send a set_quad_swarm_led_roll_pitch_yaw_thrust message * @param chan MAVLink channel to send the message @@ -176,10 +190,10 @@ static inline uint16_t mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust_enco * @param led_red RGB red channel (0-255) * @param led_blue RGB green channel (0-255) * @param led_green RGB blue channel (0-255) - * @param roll Desired roll angle in radians +-PI (+-32767) - * @param pitch Desired pitch angle in radians +-PI (+-32767) - * @param yaw Desired yaw angle in radians, scaled to int16 +-PI (+-32767) - * @param thrust Collective thrust, scaled to uint16 (0..65535) + * @param roll Desired roll angle in radians +-PI (+-INT16_MAX) + * @param pitch Desired pitch angle in radians +-PI (+-INT16_MAX) + * @param yaw Desired yaw angle in radians, scaled to int16 +-PI (+-INT16_MAX) + * @param thrust Collective thrust, scaled to uint16 (0..UINT16_MAX) */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS @@ -278,7 +292,7 @@ static inline uint16_t mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust_get_ /** * @brief Get field roll from set_quad_swarm_led_roll_pitch_yaw_thrust message * - * @return Desired roll angle in radians +-PI (+-32767) + * @return Desired roll angle in radians +-PI (+-INT16_MAX) */ static inline uint16_t mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust_get_roll(const mavlink_message_t* msg, int16_t *roll) { @@ -288,7 +302,7 @@ static inline uint16_t mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust_get_ /** * @brief Get field pitch from set_quad_swarm_led_roll_pitch_yaw_thrust message * - * @return Desired pitch angle in radians +-PI (+-32767) + * @return Desired pitch angle in radians +-PI (+-INT16_MAX) */ static inline uint16_t mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust_get_pitch(const mavlink_message_t* msg, int16_t *pitch) { @@ -298,7 +312,7 @@ static inline uint16_t mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust_get_ /** * @brief Get field yaw from set_quad_swarm_led_roll_pitch_yaw_thrust message * - * @return Desired yaw angle in radians, scaled to int16 +-PI (+-32767) + * @return Desired yaw angle in radians, scaled to int16 +-PI (+-INT16_MAX) */ static inline uint16_t mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust_get_yaw(const mavlink_message_t* msg, int16_t *yaw) { @@ -308,7 +322,7 @@ static inline uint16_t mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust_get_ /** * @brief Get field thrust from set_quad_swarm_led_roll_pitch_yaw_thrust message * - * @return Collective thrust, scaled to uint16 (0..65535) + * @return Collective thrust, scaled to uint16 (0..UINT16_MAX) */ static inline uint16_t mavlink_msg_set_quad_swarm_led_roll_pitch_yaw_thrust_get_thrust(const mavlink_message_t* msg, uint16_t *thrust) { diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust.h index 6c62b35305da648aec6f1dc48cf271c251536da0..7d8d526f8b664ec791aa0f6cf07d829fba50311e 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust.h @@ -4,10 +4,10 @@ typedef struct __mavlink_set_quad_swarm_roll_pitch_yaw_thrust_t { - int16_t roll[4]; ///< Desired roll angle in radians +-PI (+-32767) - int16_t pitch[4]; ///< Desired pitch angle in radians +-PI (+-32767) - int16_t yaw[4]; ///< Desired yaw angle in radians, scaled to int16 +-PI (+-32767) - uint16_t thrust[4]; ///< Collective thrust, scaled to uint16 (0..65535) + int16_t roll[4]; ///< Desired roll angle in radians +-PI (+-INT16_MAX) + int16_t pitch[4]; ///< Desired pitch angle in radians +-PI (+-INT16_MAX) + int16_t yaw[4]; ///< Desired yaw angle in radians, scaled to int16 +-PI (+-INT16_MAX) + uint16_t thrust[4]; ///< Collective thrust, scaled to uint16 (0..UINT16_MAX) uint8_t group; ///< ID of the quadrotor group (0 - 255, up to 256 groups supported) uint8_t mode; ///< ID of the flight mode (0 - 255, up to 256 modes supported) } mavlink_set_quad_swarm_roll_pitch_yaw_thrust_t; @@ -44,10 +44,10 @@ typedef struct __mavlink_set_quad_swarm_roll_pitch_yaw_thrust_t * * @param group ID of the quadrotor group (0 - 255, up to 256 groups supported) * @param mode ID of the flight mode (0 - 255, up to 256 modes supported) - * @param roll Desired roll angle in radians +-PI (+-32767) - * @param pitch Desired pitch angle in radians +-PI (+-32767) - * @param yaw Desired yaw angle in radians, scaled to int16 +-PI (+-32767) - * @param thrust Collective thrust, scaled to uint16 (0..65535) + * @param roll Desired roll angle in radians +-PI (+-INT16_MAX) + * @param pitch Desired pitch angle in radians +-PI (+-INT16_MAX) + * @param yaw Desired yaw angle in radians, scaled to int16 +-PI (+-INT16_MAX) + * @param thrust Collective thrust, scaled to uint16 (0..UINT16_MAX) * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, @@ -85,14 +85,14 @@ static inline uint16_t mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust_pack(uin * @brief Pack a set_quad_swarm_roll_pitch_yaw_thrust message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param group ID of the quadrotor group (0 - 255, up to 256 groups supported) * @param mode ID of the flight mode (0 - 255, up to 256 modes supported) - * @param roll Desired roll angle in radians +-PI (+-32767) - * @param pitch Desired pitch angle in radians +-PI (+-32767) - * @param yaw Desired yaw angle in radians, scaled to int16 +-PI (+-32767) - * @param thrust Collective thrust, scaled to uint16 (0..65535) + * @param roll Desired roll angle in radians +-PI (+-INT16_MAX) + * @param pitch Desired pitch angle in radians +-PI (+-INT16_MAX) + * @param yaw Desired yaw angle in radians, scaled to int16 +-PI (+-INT16_MAX) + * @param thrust Collective thrust, scaled to uint16 (0..UINT16_MAX) * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, @@ -128,7 +128,7 @@ static inline uint16_t mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust_pack_cha } /** - * @brief Encode a set_quad_swarm_roll_pitch_yaw_thrust struct into a message + * @brief Encode a set_quad_swarm_roll_pitch_yaw_thrust struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -140,16 +140,30 @@ static inline uint16_t mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust_encode(u return mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust_pack(system_id, component_id, msg, set_quad_swarm_roll_pitch_yaw_thrust->group, set_quad_swarm_roll_pitch_yaw_thrust->mode, set_quad_swarm_roll_pitch_yaw_thrust->roll, set_quad_swarm_roll_pitch_yaw_thrust->pitch, set_quad_swarm_roll_pitch_yaw_thrust->yaw, set_quad_swarm_roll_pitch_yaw_thrust->thrust); } +/** + * @brief Encode a set_quad_swarm_roll_pitch_yaw_thrust struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param set_quad_swarm_roll_pitch_yaw_thrust C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_quad_swarm_roll_pitch_yaw_thrust_t* set_quad_swarm_roll_pitch_yaw_thrust) +{ + return mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust_pack_chan(system_id, component_id, chan, msg, set_quad_swarm_roll_pitch_yaw_thrust->group, set_quad_swarm_roll_pitch_yaw_thrust->mode, set_quad_swarm_roll_pitch_yaw_thrust->roll, set_quad_swarm_roll_pitch_yaw_thrust->pitch, set_quad_swarm_roll_pitch_yaw_thrust->yaw, set_quad_swarm_roll_pitch_yaw_thrust->thrust); +} + /** * @brief Send a set_quad_swarm_roll_pitch_yaw_thrust message * @param chan MAVLink channel to send the message * * @param group ID of the quadrotor group (0 - 255, up to 256 groups supported) * @param mode ID of the flight mode (0 - 255, up to 256 modes supported) - * @param roll Desired roll angle in radians +-PI (+-32767) - * @param pitch Desired pitch angle in radians +-PI (+-32767) - * @param yaw Desired yaw angle in radians, scaled to int16 +-PI (+-32767) - * @param thrust Collective thrust, scaled to uint16 (0..65535) + * @param roll Desired roll angle in radians +-PI (+-INT16_MAX) + * @param pitch Desired pitch angle in radians +-PI (+-INT16_MAX) + * @param yaw Desired yaw angle in radians, scaled to int16 +-PI (+-INT16_MAX) + * @param thrust Collective thrust, scaled to uint16 (0..UINT16_MAX) */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS @@ -212,7 +226,7 @@ static inline uint8_t mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust_get_mode( /** * @brief Get field roll from set_quad_swarm_roll_pitch_yaw_thrust message * - * @return Desired roll angle in radians +-PI (+-32767) + * @return Desired roll angle in radians +-PI (+-INT16_MAX) */ static inline uint16_t mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust_get_roll(const mavlink_message_t* msg, int16_t *roll) { @@ -222,7 +236,7 @@ static inline uint16_t mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust_get_roll /** * @brief Get field pitch from set_quad_swarm_roll_pitch_yaw_thrust message * - * @return Desired pitch angle in radians +-PI (+-32767) + * @return Desired pitch angle in radians +-PI (+-INT16_MAX) */ static inline uint16_t mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust_get_pitch(const mavlink_message_t* msg, int16_t *pitch) { @@ -232,7 +246,7 @@ static inline uint16_t mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust_get_pitc /** * @brief Get field yaw from set_quad_swarm_roll_pitch_yaw_thrust message * - * @return Desired yaw angle in radians, scaled to int16 +-PI (+-32767) + * @return Desired yaw angle in radians, scaled to int16 +-PI (+-INT16_MAX) */ static inline uint16_t mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust_get_yaw(const mavlink_message_t* msg, int16_t *yaw) { @@ -242,7 +256,7 @@ static inline uint16_t mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust_get_yaw( /** * @brief Get field thrust from set_quad_swarm_roll_pitch_yaw_thrust message * - * @return Collective thrust, scaled to uint16 (0..65535) + * @return Collective thrust, scaled to uint16 (0..UINT16_MAX) */ static inline uint16_t mavlink_msg_set_quad_swarm_roll_pitch_yaw_thrust_get_thrust(const mavlink_message_t* msg, uint16_t *thrust) { diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_roll_pitch_yaw_speed_thrust.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_roll_pitch_yaw_speed_thrust.h index c379a75d9bb8bac484be0d53464de6f0ddde647e..5846ba41f7e2b342d37dad3c40a730e99d9f6ec9 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_roll_pitch_yaw_speed_thrust.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_roll_pitch_yaw_speed_thrust.h @@ -84,7 +84,7 @@ static inline uint16_t mavlink_msg_set_roll_pitch_yaw_speed_thrust_pack(uint8_t * @brief Pack a set_roll_pitch_yaw_speed_thrust message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -129,7 +129,7 @@ static inline uint16_t mavlink_msg_set_roll_pitch_yaw_speed_thrust_pack_chan(uin } /** - * @brief Encode a set_roll_pitch_yaw_speed_thrust struct into a message + * @brief Encode a set_roll_pitch_yaw_speed_thrust struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -141,6 +141,20 @@ static inline uint16_t mavlink_msg_set_roll_pitch_yaw_speed_thrust_encode(uint8_ return mavlink_msg_set_roll_pitch_yaw_speed_thrust_pack(system_id, component_id, msg, set_roll_pitch_yaw_speed_thrust->target_system, set_roll_pitch_yaw_speed_thrust->target_component, set_roll_pitch_yaw_speed_thrust->roll_speed, set_roll_pitch_yaw_speed_thrust->pitch_speed, set_roll_pitch_yaw_speed_thrust->yaw_speed, set_roll_pitch_yaw_speed_thrust->thrust); } +/** + * @brief Encode a set_roll_pitch_yaw_speed_thrust struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param set_roll_pitch_yaw_speed_thrust C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_set_roll_pitch_yaw_speed_thrust_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_roll_pitch_yaw_speed_thrust_t* set_roll_pitch_yaw_speed_thrust) +{ + return mavlink_msg_set_roll_pitch_yaw_speed_thrust_pack_chan(system_id, component_id, chan, msg, set_roll_pitch_yaw_speed_thrust->target_system, set_roll_pitch_yaw_speed_thrust->target_component, set_roll_pitch_yaw_speed_thrust->roll_speed, set_roll_pitch_yaw_speed_thrust->pitch_speed, set_roll_pitch_yaw_speed_thrust->yaw_speed, set_roll_pitch_yaw_speed_thrust->thrust); +} + /** * @brief Send a set_roll_pitch_yaw_speed_thrust message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_roll_pitch_yaw_thrust.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_roll_pitch_yaw_thrust.h index 146891eafb1b8ca6a78a9d2ebe3df1c62d469612..334fd39e36e1b874b46dc27926efb120565bbedf 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_roll_pitch_yaw_thrust.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_set_roll_pitch_yaw_thrust.h @@ -84,7 +84,7 @@ static inline uint16_t mavlink_msg_set_roll_pitch_yaw_thrust_pack(uint8_t system * @brief Pack a set_roll_pitch_yaw_thrust message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -129,7 +129,7 @@ static inline uint16_t mavlink_msg_set_roll_pitch_yaw_thrust_pack_chan(uint8_t s } /** - * @brief Encode a set_roll_pitch_yaw_thrust struct into a message + * @brief Encode a set_roll_pitch_yaw_thrust struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -141,6 +141,20 @@ static inline uint16_t mavlink_msg_set_roll_pitch_yaw_thrust_encode(uint8_t syst return mavlink_msg_set_roll_pitch_yaw_thrust_pack(system_id, component_id, msg, set_roll_pitch_yaw_thrust->target_system, set_roll_pitch_yaw_thrust->target_component, set_roll_pitch_yaw_thrust->roll, set_roll_pitch_yaw_thrust->pitch, set_roll_pitch_yaw_thrust->yaw, set_roll_pitch_yaw_thrust->thrust); } +/** + * @brief Encode a set_roll_pitch_yaw_thrust struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param set_roll_pitch_yaw_thrust C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_set_roll_pitch_yaw_thrust_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_roll_pitch_yaw_thrust_t* set_roll_pitch_yaw_thrust) +{ + return mavlink_msg_set_roll_pitch_yaw_thrust_pack_chan(system_id, component_id, chan, msg, set_roll_pitch_yaw_thrust->target_system, set_roll_pitch_yaw_thrust->target_component, set_roll_pitch_yaw_thrust->roll, set_roll_pitch_yaw_thrust->pitch, set_roll_pitch_yaw_thrust->yaw, set_roll_pitch_yaw_thrust->thrust); +} + /** * @brief Send a set_roll_pitch_yaw_thrust message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_setpoint_6dof.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_setpoint_6dof.h index f352617a266d09c1a7110b13d7ac6a1c99a64b26..93ce345b65cfdb909c2b6988f9dcc626b0167535 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_setpoint_6dof.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_setpoint_6dof.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_setpoint_6dof_pack(uint8_t system_id, uint8_t * @brief Pack a setpoint_6dof message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param trans_x Translational Component in x @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_setpoint_6dof_pack_chan(uint8_t system_id, ui } /** - * @brief Encode a setpoint_6dof struct into a message + * @brief Encode a setpoint_6dof struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_setpoint_6dof_encode(uint8_t system_id, uint8 return mavlink_msg_setpoint_6dof_pack(system_id, component_id, msg, setpoint_6dof->target_system, setpoint_6dof->trans_x, setpoint_6dof->trans_y, setpoint_6dof->trans_z, setpoint_6dof->rot_x, setpoint_6dof->rot_y, setpoint_6dof->rot_z); } +/** + * @brief Encode a setpoint_6dof struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param setpoint_6dof C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_setpoint_6dof_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_setpoint_6dof_t* setpoint_6dof) +{ + return mavlink_msg_setpoint_6dof_pack_chan(system_id, component_id, chan, msg, setpoint_6dof->target_system, setpoint_6dof->trans_x, setpoint_6dof->trans_y, setpoint_6dof->trans_z, setpoint_6dof->rot_x, setpoint_6dof->rot_y, setpoint_6dof->rot_z); +} + /** * @brief Send a setpoint_6dof message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_setpoint_8dof.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_setpoint_8dof.h index d7622b6965d97d2a99f3e2136060554ddd3ca951..de80e46459307eb8893f1be63bfcdf6f0087fc8a 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_setpoint_8dof.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_setpoint_8dof.h @@ -99,7 +99,7 @@ static inline uint16_t mavlink_msg_setpoint_8dof_pack(uint8_t system_id, uint8_t * @brief Pack a setpoint_8dof message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param val1 Value 1 @@ -153,7 +153,7 @@ static inline uint16_t mavlink_msg_setpoint_8dof_pack_chan(uint8_t system_id, ui } /** - * @brief Encode a setpoint_8dof struct into a message + * @brief Encode a setpoint_8dof struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -165,6 +165,20 @@ static inline uint16_t mavlink_msg_setpoint_8dof_encode(uint8_t system_id, uint8 return mavlink_msg_setpoint_8dof_pack(system_id, component_id, msg, setpoint_8dof->target_system, setpoint_8dof->val1, setpoint_8dof->val2, setpoint_8dof->val3, setpoint_8dof->val4, setpoint_8dof->val5, setpoint_8dof->val6, setpoint_8dof->val7, setpoint_8dof->val8); } +/** + * @brief Encode a setpoint_8dof struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param setpoint_8dof C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_setpoint_8dof_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_setpoint_8dof_t* setpoint_8dof) +{ + return mavlink_msg_setpoint_8dof_pack_chan(system_id, component_id, chan, msg, setpoint_8dof->target_system, setpoint_8dof->val1, setpoint_8dof->val2, setpoint_8dof->val3, setpoint_8dof->val4, setpoint_8dof->val5, setpoint_8dof->val6, setpoint_8dof->val7, setpoint_8dof->val8); +} + /** * @brief Send a setpoint_8dof message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_sim_state.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_sim_state.h index 6fd32abd256cce49acc72d94a40cae9379b2e54c..ebd657cf38bcc47b3b3a6f191b61775407953735 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_sim_state.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_sim_state.h @@ -159,7 +159,7 @@ static inline uint16_t mavlink_msg_sim_state_pack(uint8_t system_id, uint8_t com * @brief Pack a sim_state message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param q1 True attitude quaternion component 1 * @param q2 True attitude quaternion component 2 @@ -249,7 +249,7 @@ static inline uint16_t mavlink_msg_sim_state_pack_chan(uint8_t system_id, uint8_ } /** - * @brief Encode a sim_state struct into a message + * @brief Encode a sim_state struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -261,6 +261,20 @@ static inline uint16_t mavlink_msg_sim_state_encode(uint8_t system_id, uint8_t c return mavlink_msg_sim_state_pack(system_id, component_id, msg, sim_state->q1, sim_state->q2, sim_state->q3, sim_state->q4, sim_state->roll, sim_state->pitch, sim_state->yaw, sim_state->xacc, sim_state->yacc, sim_state->zacc, sim_state->xgyro, sim_state->ygyro, sim_state->zgyro, sim_state->lat, sim_state->lon, sim_state->alt, sim_state->std_dev_horz, sim_state->std_dev_vert, sim_state->vn, sim_state->ve, sim_state->vd); } +/** + * @brief Encode a sim_state struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param sim_state C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_sim_state_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_sim_state_t* sim_state) +{ + return mavlink_msg_sim_state_pack_chan(system_id, component_id, chan, msg, sim_state->q1, sim_state->q2, sim_state->q3, sim_state->q4, sim_state->roll, sim_state->pitch, sim_state->yaw, sim_state->xacc, sim_state->yacc, sim_state->zacc, sim_state->xgyro, sim_state->ygyro, sim_state->zgyro, sim_state->lat, sim_state->lon, sim_state->alt, sim_state->std_dev_horz, sim_state->std_dev_vert, sim_state->vn, sim_state->ve, sim_state->vd); +} + /** * @brief Send a sim_state message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_state_correction.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_state_correction.h index 8a002fc11327eb91481f3598614275199790e324..2db627b96a9a7da0b5d00ac64e7f107af7372913 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_state_correction.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_state_correction.h @@ -99,7 +99,7 @@ static inline uint16_t mavlink_msg_state_correction_pack(uint8_t system_id, uint * @brief Pack a state_correction message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param xErr x position error * @param yErr y position error @@ -153,7 +153,7 @@ static inline uint16_t mavlink_msg_state_correction_pack_chan(uint8_t system_id, } /** - * @brief Encode a state_correction struct into a message + * @brief Encode a state_correction struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -165,6 +165,20 @@ static inline uint16_t mavlink_msg_state_correction_encode(uint8_t system_id, ui return mavlink_msg_state_correction_pack(system_id, component_id, msg, state_correction->xErr, state_correction->yErr, state_correction->zErr, state_correction->rollErr, state_correction->pitchErr, state_correction->yawErr, state_correction->vxErr, state_correction->vyErr, state_correction->vzErr); } +/** + * @brief Encode a state_correction struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param state_correction C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_state_correction_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_state_correction_t* state_correction) +{ + return mavlink_msg_state_correction_pack_chan(system_id, component_id, chan, msg, state_correction->xErr, state_correction->yErr, state_correction->zErr, state_correction->rollErr, state_correction->pitchErr, state_correction->yawErr, state_correction->vxErr, state_correction->vyErr, state_correction->vzErr); +} + /** * @brief Send a state_correction message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_statustext.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_statustext.h index 103486863cedcf18a0057378c7a8670272b1f273..536ca063495fd8ad902739b3c37b8705abfa543d 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_statustext.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_statustext.h @@ -62,7 +62,7 @@ static inline uint16_t mavlink_msg_statustext_pack(uint8_t system_id, uint8_t co * @brief Pack a statustext message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param severity Severity of status. Relies on the definitions within RFC-5424. See enum MAV_SEVERITY. * @param text Status text message, without null termination character @@ -93,7 +93,7 @@ static inline uint16_t mavlink_msg_statustext_pack_chan(uint8_t system_id, uint8 } /** - * @brief Encode a statustext struct into a message + * @brief Encode a statustext struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -105,6 +105,20 @@ static inline uint16_t mavlink_msg_statustext_encode(uint8_t system_id, uint8_t return mavlink_msg_statustext_pack(system_id, component_id, msg, statustext->severity, statustext->text); } +/** + * @brief Encode a statustext struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param statustext C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_statustext_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_statustext_t* statustext) +{ + return mavlink_msg_statustext_pack_chan(system_id, component_id, chan, msg, statustext->severity, statustext->text); +} + /** * @brief Send a statustext message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_sys_status.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_sys_status.h index 916bc4f07b2f9e717b393bb10e7efb61beb8bb55..058c630dddfa9ea9da2ef73c2bba7d5645af75d5 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_sys_status.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_sys_status.h @@ -119,7 +119,7 @@ static inline uint16_t mavlink_msg_sys_status_pack(uint8_t system_id, uint8_t co * @brief Pack a sys_status message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param onboard_control_sensors_present Bitmask showing which onboard controllers and sensors are present. Value of 0: not present. Value of 1: present. Indices: 0: 3D gyro, 1: 3D acc, 2: 3D mag, 3: absolute pressure, 4: differential pressure, 5: GPS, 6: optical flow, 7: computer vision position, 8: laser based position, 9: external ground-truth (Vicon or Leica). Controllers: 10: 3D angular rate control 11: attitude stabilization, 12: yaw position, 13: z/altitude control, 14: x/y position control, 15: motor outputs / control * @param onboard_control_sensors_enabled Bitmask showing which onboard controllers and sensors are enabled: Value of 0: not enabled. Value of 1: enabled. Indices: 0: 3D gyro, 1: 3D acc, 2: 3D mag, 3: absolute pressure, 4: differential pressure, 5: GPS, 6: optical flow, 7: computer vision position, 8: laser based position, 9: external ground-truth (Vicon or Leica). Controllers: 10: 3D angular rate control 11: attitude stabilization, 12: yaw position, 13: z/altitude control, 14: x/y position control, 15: motor outputs / control @@ -185,7 +185,7 @@ static inline uint16_t mavlink_msg_sys_status_pack_chan(uint8_t system_id, uint8 } /** - * @brief Encode a sys_status struct into a message + * @brief Encode a sys_status struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -197,6 +197,20 @@ static inline uint16_t mavlink_msg_sys_status_encode(uint8_t system_id, uint8_t return mavlink_msg_sys_status_pack(system_id, component_id, msg, sys_status->onboard_control_sensors_present, sys_status->onboard_control_sensors_enabled, sys_status->onboard_control_sensors_health, sys_status->load, sys_status->voltage_battery, sys_status->current_battery, sys_status->battery_remaining, sys_status->drop_rate_comm, sys_status->errors_comm, sys_status->errors_count1, sys_status->errors_count2, sys_status->errors_count3, sys_status->errors_count4); } +/** + * @brief Encode a sys_status struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param sys_status C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_sys_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_sys_status_t* sys_status) +{ + return mavlink_msg_sys_status_pack_chan(system_id, component_id, chan, msg, sys_status->onboard_control_sensors_present, sys_status->onboard_control_sensors_enabled, sys_status->onboard_control_sensors_health, sys_status->load, sys_status->voltage_battery, sys_status->current_battery, sys_status->battery_remaining, sys_status->drop_rate_comm, sys_status->errors_comm, sys_status->errors_count1, sys_status->errors_count2, sys_status->errors_count3, sys_status->errors_count4); +} + /** * @brief Send a sys_status message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_system_time.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_system_time.h index b235fe20560affeeafa39ce1317280b9fba7ae26..1807567aea1b9a916056dfd7f265c35ee3d4b204 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_system_time.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_system_time.h @@ -64,7 +64,7 @@ static inline uint16_t mavlink_msg_system_time_pack(uint8_t system_id, uint8_t c * @brief Pack a system_time message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_unix_usec Timestamp of the master clock in microseconds since UNIX epoch. * @param time_boot_ms Timestamp of the component clock since boot time in milliseconds. @@ -97,7 +97,7 @@ static inline uint16_t mavlink_msg_system_time_pack_chan(uint8_t system_id, uint } /** - * @brief Encode a system_time struct into a message + * @brief Encode a system_time struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -109,6 +109,20 @@ static inline uint16_t mavlink_msg_system_time_encode(uint8_t system_id, uint8_t return mavlink_msg_system_time_pack(system_id, component_id, msg, system_time->time_unix_usec, system_time->time_boot_ms); } +/** + * @brief Encode a system_time struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param system_time C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_system_time_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_system_time_t* system_time) +{ + return mavlink_msg_system_time_pack_chan(system_id, component_id, chan, msg, system_time->time_unix_usec, system_time->time_boot_ms); +} + /** * @brief Send a system_time message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_vfr_hud.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_vfr_hud.h index 9d459921fe55d65ef4532f627ee522ba7413439e..5b1093a3d79de552de97d177c61a613e403f6a91 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_vfr_hud.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_vfr_hud.h @@ -84,7 +84,7 @@ static inline uint16_t mavlink_msg_vfr_hud_pack(uint8_t system_id, uint8_t compo * @brief Pack a vfr_hud message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param airspeed Current airspeed in m/s * @param groundspeed Current ground speed in m/s @@ -129,7 +129,7 @@ static inline uint16_t mavlink_msg_vfr_hud_pack_chan(uint8_t system_id, uint8_t } /** - * @brief Encode a vfr_hud struct into a message + * @brief Encode a vfr_hud struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -141,6 +141,20 @@ static inline uint16_t mavlink_msg_vfr_hud_encode(uint8_t system_id, uint8_t com return mavlink_msg_vfr_hud_pack(system_id, component_id, msg, vfr_hud->airspeed, vfr_hud->groundspeed, vfr_hud->heading, vfr_hud->throttle, vfr_hud->alt, vfr_hud->climb); } +/** + * @brief Encode a vfr_hud struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param vfr_hud C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_vfr_hud_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_vfr_hud_t* vfr_hud) +{ + return mavlink_msg_vfr_hud_pack_chan(system_id, component_id, chan, msg, vfr_hud->airspeed, vfr_hud->groundspeed, vfr_hud->heading, vfr_hud->throttle, vfr_hud->alt, vfr_hud->climb); +} + /** * @brief Send a vfr_hud message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_vicon_position_estimate.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_vicon_position_estimate.h index 75e4b5b7abdafb099d7415ab502d0e6fb564ff84..a254202e4ed00c2d91af1b259975ea2d8c4f4cc4 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_vicon_position_estimate.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_vicon_position_estimate.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_vicon_position_estimate_pack(uint8_t system_i * @brief Pack a vicon_position_estimate message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param usec Timestamp (microseconds, synced to UNIX time or since system boot) * @param x Global X position @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_vicon_position_estimate_pack_chan(uint8_t sys } /** - * @brief Encode a vicon_position_estimate struct into a message + * @brief Encode a vicon_position_estimate struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_vicon_position_estimate_encode(uint8_t system return mavlink_msg_vicon_position_estimate_pack(system_id, component_id, msg, vicon_position_estimate->usec, vicon_position_estimate->x, vicon_position_estimate->y, vicon_position_estimate->z, vicon_position_estimate->roll, vicon_position_estimate->pitch, vicon_position_estimate->yaw); } +/** + * @brief Encode a vicon_position_estimate struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param vicon_position_estimate C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_vicon_position_estimate_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_vicon_position_estimate_t* vicon_position_estimate) +{ + return mavlink_msg_vicon_position_estimate_pack_chan(system_id, component_id, chan, msg, vicon_position_estimate->usec, vicon_position_estimate->x, vicon_position_estimate->y, vicon_position_estimate->z, vicon_position_estimate->roll, vicon_position_estimate->pitch, vicon_position_estimate->yaw); +} + /** * @brief Send a vicon_position_estimate message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_vision_position_estimate.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_vision_position_estimate.h index 47ccb11ec0dc1942142f3e5dfe02f9cbf181a3ab..f7a741b09e1ec14b77f9f5890608c69901184495 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_vision_position_estimate.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_vision_position_estimate.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_vision_position_estimate_pack(uint8_t system_ * @brief Pack a vision_position_estimate message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param usec Timestamp (microseconds, synced to UNIX time or since system boot) * @param x Global X position @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_vision_position_estimate_pack_chan(uint8_t sy } /** - * @brief Encode a vision_position_estimate struct into a message + * @brief Encode a vision_position_estimate struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_vision_position_estimate_encode(uint8_t syste return mavlink_msg_vision_position_estimate_pack(system_id, component_id, msg, vision_position_estimate->usec, vision_position_estimate->x, vision_position_estimate->y, vision_position_estimate->z, vision_position_estimate->roll, vision_position_estimate->pitch, vision_position_estimate->yaw); } +/** + * @brief Encode a vision_position_estimate struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param vision_position_estimate C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_vision_position_estimate_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_vision_position_estimate_t* vision_position_estimate) +{ + return mavlink_msg_vision_position_estimate_pack_chan(system_id, component_id, chan, msg, vision_position_estimate->usec, vision_position_estimate->x, vision_position_estimate->y, vision_position_estimate->z, vision_position_estimate->roll, vision_position_estimate->pitch, vision_position_estimate->yaw); +} + /** * @brief Send a vision_position_estimate message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_vision_speed_estimate.h b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_vision_speed_estimate.h index c38eee62c00c88813933f6aa86d0b36f4b37c3f5..6602251283d1d6fc4d006d9ef82c2612fc19216c 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_vision_speed_estimate.h +++ b/libs/mavlink/include/mavlink/v1.0/common/mavlink_msg_vision_speed_estimate.h @@ -74,7 +74,7 @@ static inline uint16_t mavlink_msg_vision_speed_estimate_pack(uint8_t system_id, * @brief Pack a vision_speed_estimate message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param usec Timestamp (microseconds, synced to UNIX time or since system boot) * @param x Global X speed @@ -113,7 +113,7 @@ static inline uint16_t mavlink_msg_vision_speed_estimate_pack_chan(uint8_t syste } /** - * @brief Encode a vision_speed_estimate struct into a message + * @brief Encode a vision_speed_estimate struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -125,6 +125,20 @@ static inline uint16_t mavlink_msg_vision_speed_estimate_encode(uint8_t system_i return mavlink_msg_vision_speed_estimate_pack(system_id, component_id, msg, vision_speed_estimate->usec, vision_speed_estimate->x, vision_speed_estimate->y, vision_speed_estimate->z); } +/** + * @brief Encode a vision_speed_estimate struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param vision_speed_estimate C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_vision_speed_estimate_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_vision_speed_estimate_t* vision_speed_estimate) +{ + return mavlink_msg_vision_speed_estimate_pack_chan(system_id, component_id, chan, msg, vision_speed_estimate->usec, vision_speed_estimate->x, vision_speed_estimate->y, vision_speed_estimate->z); +} + /** * @brief Send a vision_speed_estimate message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/common/version.h b/libs/mavlink/include/mavlink/v1.0/common/version.h index c91a641de8350638fcc3b583822b5a8083f2e1da..3c354f42296446b7f2a98b398db1d8960594fce4 100644 --- a/libs/mavlink/include/mavlink/v1.0/common/version.h +++ b/libs/mavlink/include/mavlink/v1.0/common/version.h @@ -5,7 +5,7 @@ #ifndef MAVLINK_VERSION_H #define MAVLINK_VERSION_H -#define MAVLINK_BUILD_DATE "Thu Jul 4 13:47:40 2013" +#define MAVLINK_BUILD_DATE "Tue Sep 10 23:50:05 2013" #define MAVLINK_WIRE_PROTOCOL_VERSION "1.0" #define MAVLINK_MAX_DIALECT_PAYLOAD_SIZE 254 diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/matrixpilot.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/matrixpilot.h index f5576255ed415d72bf247a312c8c81550b7ff724..f590cda800ab7f18f6220616917d5d1517e4bac4 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/matrixpilot.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/matrixpilot.h @@ -77,6 +77,7 @@ enum MAV_CMD MAV_CMD_DO_SET_SERVO=183, /* Set a servo to a desired PWM value. |Servo number| PWM (microseconds, 1000 to 2000 typical)| Empty| Empty| Empty| Empty| Empty| */ MAV_CMD_DO_REPEAT_SERVO=184, /* Cycle a between its nominal setting and a desired PWM for a desired number of cycles with a desired period. |Servo number| PWM (microseconds, 1000 to 2000 typical)| Cycle count| Cycle time (seconds)| Empty| Empty| Empty| */ MAV_CMD_DO_CONTROL_VIDEO=200, /* Control onboard camera system. |Camera ID (-1 for all)| Transmission: 0: disabled, 1: enabled compressed, 2: enabled raw| Transmission mode: 0: video stream, >0: single images every n seconds (decimal)| Recording: 0: disabled, 1: enabled compressed, 2: enabled raw| Empty| Empty| Empty| */ + MAV_CMD_DO_SET_ROI=201, /* Sets the region of interest (ROI) for a sensor set or the vehicle itself. This can then be used by the vehicles control system to control the vehicle attitude and the attitude of various sensors such as cameras. |Region of intereset mode. (see MAV_ROI enum)| MISSION index/ target ID. (see MAV_ROI enum)| ROI index (allows a vehicle to manage multiple ROI's)| Empty| x the location of the fixed ROI (see MAV_FRAME)| y| z| */ MAV_CMD_DO_LAST=240, /* NOP - This command is only used to mark the upper limit of the DO commands in the enumeration |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ MAV_CMD_PREFLIGHT_CALIBRATION=241, /* Trigger calibration. This command will be only accepted if in pre-flight mode. |Gyro calibration: 0: no, 1: yes| Magnetometer calibration: 0: no, 1: yes| Ground pressure: 0: no, 1: yes| Radio calibration: 0: no, 1: yes| Accelerometer calibration: 0: no, 1: yes| Empty| Empty| */ MAV_CMD_PREFLIGHT_SET_SENSOR_OFFSETS=242, /* Set sensor offsets. This command will be only accepted if in pre-flight mode. |Sensor to adjust the offsets for: 0: gyros, 1: accelerometer, 2: magnetometer, 3: barometer, 4: optical flow| X axis offset (or generic dimension 1), in the sensor's raw units| Y axis offset (or generic dimension 2), in the sensor's raw units| Z axis offset (or generic dimension 3), in the sensor's raw units| Generic dimension 4, in the sensor's raw units| Generic dimension 5, in the sensor's raw units| Generic dimension 6, in the sensor's raw units| */ @@ -85,7 +86,8 @@ enum MAV_CMD MAV_CMD_OVERRIDE_GOTO=252, /* Hold / continue the current action |MAV_GOTO_DO_HOLD: hold MAV_GOTO_DO_CONTINUE: continue with next item in mission plan| MAV_GOTO_HOLD_AT_CURRENT_POSITION: Hold at current position MAV_GOTO_HOLD_AT_SPECIFIED_POSITION: hold at specified position| MAV_FRAME coordinate frame of hold point| Desired yaw angle in degrees| Latitude / X position| Longitude / Y position| Altitude / Z position| */ MAV_CMD_MISSION_START=300, /* start running a mission |first_item: the first mission item to run| last_item: the last mission item to run (after this item is run, the mission ends)| */ MAV_CMD_COMPONENT_ARM_DISARM=400, /* Arms / Disarms a component |1 to arm, 0 to disarm| */ - MAV_CMD_ENUM_END=401, /* | */ + MAV_CMD_START_RX_PAIR=500, /* Starts receiver pairing |0:Spektrum| 0:Spektrum DSM2, 1:Spektrum DSMX| */ + MAV_CMD_ENUM_END=501, /* | */ }; #endif diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_airspeeds.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_airspeeds.h index bd0be342fa45942e240c1371a08e69685e2c349f..bc47a547add896b8db2bb591f7e3712699401d9c 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_airspeeds.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_airspeeds.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_airspeeds_pack(uint8_t system_id, uint8_t com * @brief Pack a airspeeds message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp (milliseconds since system boot) * @param airspeed_imu Airspeed estimate from IMU, cm/s @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_airspeeds_pack_chan(uint8_t system_id, uint8_ } /** - * @brief Encode a airspeeds struct into a message + * @brief Encode a airspeeds struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_airspeeds_encode(uint8_t system_id, uint8_t c return mavlink_msg_airspeeds_pack(system_id, component_id, msg, airspeeds->time_boot_ms, airspeeds->airspeed_imu, airspeeds->airspeed_pitot, airspeeds->airspeed_hot_wire, airspeeds->airspeed_ultrasonic, airspeeds->aoa, airspeeds->aoy); } +/** + * @brief Encode a airspeeds struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param airspeeds C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_airspeeds_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_airspeeds_t* airspeeds) +{ + return mavlink_msg_airspeeds_pack_chan(system_id, component_id, chan, msg, airspeeds->time_boot_ms, airspeeds->airspeed_imu, airspeeds->airspeed_pitot, airspeeds->airspeed_hot_wire, airspeeds->airspeed_ultrasonic, airspeeds->aoa, airspeeds->aoy); +} + /** * @brief Send a airspeeds message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_altitudes.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_altitudes.h index c1ce66875ce9ae05710fcf8c00f4581d47564b3a..e64787cc73670913aeb0a678b67eaf5463ff23c7 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_altitudes.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_altitudes.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_altitudes_pack(uint8_t system_id, uint8_t com * @brief Pack a altitudes message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp (milliseconds since system boot) * @param alt_gps GPS altitude in meters, expressed as * 1000 (millimeters), above MSL @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_altitudes_pack_chan(uint8_t system_id, uint8_ } /** - * @brief Encode a altitudes struct into a message + * @brief Encode a altitudes struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_altitudes_encode(uint8_t system_id, uint8_t c return mavlink_msg_altitudes_pack(system_id, component_id, msg, altitudes->time_boot_ms, altitudes->alt_gps, altitudes->alt_imu, altitudes->alt_barometric, altitudes->alt_optical_flow, altitudes->alt_range_finder, altitudes->alt_extra); } +/** + * @brief Encode a altitudes struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param altitudes C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_altitudes_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_altitudes_t* altitudes) +{ + return mavlink_msg_altitudes_pack_chan(system_id, component_id, chan, msg, altitudes->time_boot_ms, altitudes->alt_gps, altitudes->alt_imu, altitudes->alt_barometric, altitudes->alt_optical_flow, altitudes->alt_range_finder, altitudes->alt_extra); +} + /** * @brief Send a altitudes message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_buffer_function.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_buffer_function.h index d72a4dcacbf5b6aebd9f0db17e6e5979b914bd3f..581bd35dc514aa8eca41cdc4e7f69ca9d7bf24e6 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_buffer_function.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_buffer_function.h @@ -87,7 +87,7 @@ static inline uint16_t mavlink_msg_flexifunction_buffer_function_pack(uint8_t sy * @brief Pack a flexifunction_buffer_function message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -133,7 +133,7 @@ static inline uint16_t mavlink_msg_flexifunction_buffer_function_pack_chan(uint8 } /** - * @brief Encode a flexifunction_buffer_function struct into a message + * @brief Encode a flexifunction_buffer_function struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -145,6 +145,20 @@ static inline uint16_t mavlink_msg_flexifunction_buffer_function_encode(uint8_t return mavlink_msg_flexifunction_buffer_function_pack(system_id, component_id, msg, flexifunction_buffer_function->target_system, flexifunction_buffer_function->target_component, flexifunction_buffer_function->func_index, flexifunction_buffer_function->func_count, flexifunction_buffer_function->data_address, flexifunction_buffer_function->data_size, flexifunction_buffer_function->data); } +/** + * @brief Encode a flexifunction_buffer_function struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param flexifunction_buffer_function C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_flexifunction_buffer_function_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_flexifunction_buffer_function_t* flexifunction_buffer_function) +{ + return mavlink_msg_flexifunction_buffer_function_pack_chan(system_id, component_id, chan, msg, flexifunction_buffer_function->target_system, flexifunction_buffer_function->target_component, flexifunction_buffer_function->func_index, flexifunction_buffer_function->func_count, flexifunction_buffer_function->data_address, flexifunction_buffer_function->data_size, flexifunction_buffer_function->data); +} + /** * @brief Send a flexifunction_buffer_function message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_buffer_function_ack.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_buffer_function_ack.h index 58f1786ef910acac730e3375e42cea12537e8a4a..790afd52b34eedc7b55295be3b9386cb455581f6 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_buffer_function_ack.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_buffer_function_ack.h @@ -74,7 +74,7 @@ static inline uint16_t mavlink_msg_flexifunction_buffer_function_ack_pack(uint8_ * @brief Pack a flexifunction_buffer_function_ack message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -113,7 +113,7 @@ static inline uint16_t mavlink_msg_flexifunction_buffer_function_ack_pack_chan(u } /** - * @brief Encode a flexifunction_buffer_function_ack struct into a message + * @brief Encode a flexifunction_buffer_function_ack struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -125,6 +125,20 @@ static inline uint16_t mavlink_msg_flexifunction_buffer_function_ack_encode(uint return mavlink_msg_flexifunction_buffer_function_ack_pack(system_id, component_id, msg, flexifunction_buffer_function_ack->target_system, flexifunction_buffer_function_ack->target_component, flexifunction_buffer_function_ack->func_index, flexifunction_buffer_function_ack->result); } +/** + * @brief Encode a flexifunction_buffer_function_ack struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param flexifunction_buffer_function_ack C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_flexifunction_buffer_function_ack_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_flexifunction_buffer_function_ack_t* flexifunction_buffer_function_ack) +{ + return mavlink_msg_flexifunction_buffer_function_ack_pack_chan(system_id, component_id, chan, msg, flexifunction_buffer_function_ack->target_system, flexifunction_buffer_function_ack->target_component, flexifunction_buffer_function_ack->func_index, flexifunction_buffer_function_ack->result); +} + /** * @brief Send a flexifunction_buffer_function_ack message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_command.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_command.h index 2f6668cf95bc2a99b41b079f880a817e84b71311..ce722c8a4da57848dd53d992532d203d62fdb42d 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_command.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_command.h @@ -69,7 +69,7 @@ static inline uint16_t mavlink_msg_flexifunction_command_pack(uint8_t system_id, * @brief Pack a flexifunction_command message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -105,7 +105,7 @@ static inline uint16_t mavlink_msg_flexifunction_command_pack_chan(uint8_t syste } /** - * @brief Encode a flexifunction_command struct into a message + * @brief Encode a flexifunction_command struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -117,6 +117,20 @@ static inline uint16_t mavlink_msg_flexifunction_command_encode(uint8_t system_i return mavlink_msg_flexifunction_command_pack(system_id, component_id, msg, flexifunction_command->target_system, flexifunction_command->target_component, flexifunction_command->command_type); } +/** + * @brief Encode a flexifunction_command struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param flexifunction_command C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_flexifunction_command_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_flexifunction_command_t* flexifunction_command) +{ + return mavlink_msg_flexifunction_command_pack_chan(system_id, component_id, chan, msg, flexifunction_command->target_system, flexifunction_command->target_component, flexifunction_command->command_type); +} + /** * @brief Send a flexifunction_command message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_command_ack.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_command_ack.h index 4798febb01c76cd4430d6f98bd570bfbb5274b8c..070dc4bf8d775585c801a3a8975e37d26a7582c7 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_command_ack.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_command_ack.h @@ -64,7 +64,7 @@ static inline uint16_t mavlink_msg_flexifunction_command_ack_pack(uint8_t system * @brief Pack a flexifunction_command_ack message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param command_type Command acknowledged * @param result result of acknowledge @@ -97,7 +97,7 @@ static inline uint16_t mavlink_msg_flexifunction_command_ack_pack_chan(uint8_t s } /** - * @brief Encode a flexifunction_command_ack struct into a message + * @brief Encode a flexifunction_command_ack struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -109,6 +109,20 @@ static inline uint16_t mavlink_msg_flexifunction_command_ack_encode(uint8_t syst return mavlink_msg_flexifunction_command_ack_pack(system_id, component_id, msg, flexifunction_command_ack->command_type, flexifunction_command_ack->result); } +/** + * @brief Encode a flexifunction_command_ack struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param flexifunction_command_ack C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_flexifunction_command_ack_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_flexifunction_command_ack_t* flexifunction_command_ack) +{ + return mavlink_msg_flexifunction_command_ack_pack_chan(system_id, component_id, chan, msg, flexifunction_command_ack->command_type, flexifunction_command_ack->result); +} + /** * @brief Send a flexifunction_command_ack message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_directory.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_directory.h index 947bfc591112f2140ccaa12153c0e7731d6c0822..ef262a6b1dc7e5c155d79ccfa36191554b47e887 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_directory.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_directory.h @@ -82,7 +82,7 @@ static inline uint16_t mavlink_msg_flexifunction_directory_pack(uint8_t system_i * @brief Pack a flexifunction_directory message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -125,7 +125,7 @@ static inline uint16_t mavlink_msg_flexifunction_directory_pack_chan(uint8_t sys } /** - * @brief Encode a flexifunction_directory struct into a message + * @brief Encode a flexifunction_directory struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -137,6 +137,20 @@ static inline uint16_t mavlink_msg_flexifunction_directory_encode(uint8_t system return mavlink_msg_flexifunction_directory_pack(system_id, component_id, msg, flexifunction_directory->target_system, flexifunction_directory->target_component, flexifunction_directory->directory_type, flexifunction_directory->start_index, flexifunction_directory->count, flexifunction_directory->directory_data); } +/** + * @brief Encode a flexifunction_directory struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param flexifunction_directory C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_flexifunction_directory_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_flexifunction_directory_t* flexifunction_directory) +{ + return mavlink_msg_flexifunction_directory_pack_chan(system_id, component_id, chan, msg, flexifunction_directory->target_system, flexifunction_directory->target_component, flexifunction_directory->directory_type, flexifunction_directory->start_index, flexifunction_directory->count, flexifunction_directory->directory_data); +} + /** * @brief Send a flexifunction_directory message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_directory_ack.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_directory_ack.h index 5489dd6b5e19abcb5a8b8bca859964ac55d7a9eb..d3a386ce54dc0fe0b2a7b4293a895a97fecba325 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_directory_ack.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_directory_ack.h @@ -84,7 +84,7 @@ static inline uint16_t mavlink_msg_flexifunction_directory_ack_pack(uint8_t syst * @brief Pack a flexifunction_directory_ack message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -129,7 +129,7 @@ static inline uint16_t mavlink_msg_flexifunction_directory_ack_pack_chan(uint8_t } /** - * @brief Encode a flexifunction_directory_ack struct into a message + * @brief Encode a flexifunction_directory_ack struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -141,6 +141,20 @@ static inline uint16_t mavlink_msg_flexifunction_directory_ack_encode(uint8_t sy return mavlink_msg_flexifunction_directory_ack_pack(system_id, component_id, msg, flexifunction_directory_ack->target_system, flexifunction_directory_ack->target_component, flexifunction_directory_ack->directory_type, flexifunction_directory_ack->start_index, flexifunction_directory_ack->count, flexifunction_directory_ack->result); } +/** + * @brief Encode a flexifunction_directory_ack struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param flexifunction_directory_ack C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_flexifunction_directory_ack_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_flexifunction_directory_ack_t* flexifunction_directory_ack) +{ + return mavlink_msg_flexifunction_directory_ack_pack_chan(system_id, component_id, chan, msg, flexifunction_directory_ack->target_system, flexifunction_directory_ack->target_component, flexifunction_directory_ack->directory_type, flexifunction_directory_ack->start_index, flexifunction_directory_ack->count, flexifunction_directory_ack->result); +} + /** * @brief Send a flexifunction_directory_ack message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_read_req.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_read_req.h index 9ffc2caa5f1ec045d2b565c0df720ae96e1468c8..e50f77b080ccb70a94be79f4ddb980bd140a493e 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_read_req.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_read_req.h @@ -74,7 +74,7 @@ static inline uint16_t mavlink_msg_flexifunction_read_req_pack(uint8_t system_id * @brief Pack a flexifunction_read_req message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -113,7 +113,7 @@ static inline uint16_t mavlink_msg_flexifunction_read_req_pack_chan(uint8_t syst } /** - * @brief Encode a flexifunction_read_req struct into a message + * @brief Encode a flexifunction_read_req struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -125,6 +125,20 @@ static inline uint16_t mavlink_msg_flexifunction_read_req_encode(uint8_t system_ return mavlink_msg_flexifunction_read_req_pack(system_id, component_id, msg, flexifunction_read_req->target_system, flexifunction_read_req->target_component, flexifunction_read_req->read_req_type, flexifunction_read_req->data_index); } +/** + * @brief Encode a flexifunction_read_req struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param flexifunction_read_req C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_flexifunction_read_req_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_flexifunction_read_req_t* flexifunction_read_req) +{ + return mavlink_msg_flexifunction_read_req_pack_chan(system_id, component_id, chan, msg, flexifunction_read_req->target_system, flexifunction_read_req->target_component, flexifunction_read_req->read_req_type, flexifunction_read_req->data_index); +} + /** * @brief Send a flexifunction_read_req message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_set.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_set.h index fc7d1d2f8e6a9fba3e1beb892eaf6cf34768dba9..41afb3811dde2737c6bede489ed8a3a44f9a6f66 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_set.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_flexifunction_set.h @@ -64,7 +64,7 @@ static inline uint16_t mavlink_msg_flexifunction_set_pack(uint8_t system_id, uin * @brief Pack a flexifunction_set message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -97,7 +97,7 @@ static inline uint16_t mavlink_msg_flexifunction_set_pack_chan(uint8_t system_id } /** - * @brief Encode a flexifunction_set struct into a message + * @brief Encode a flexifunction_set struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -109,6 +109,20 @@ static inline uint16_t mavlink_msg_flexifunction_set_encode(uint8_t system_id, u return mavlink_msg_flexifunction_set_pack(system_id, component_id, msg, flexifunction_set->target_system, flexifunction_set->target_component); } +/** + * @brief Encode a flexifunction_set struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param flexifunction_set C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_flexifunction_set_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_flexifunction_set_t* flexifunction_set) +{ + return mavlink_msg_flexifunction_set_pack_chan(system_id, component_id, chan, msg, flexifunction_set->target_system, flexifunction_set->target_component); +} + /** * @brief Send a flexifunction_set message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f13.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f13.h index df5645e765a2e6932357b960de998cc6d73158d5..d21ab48168493a739a6d365d85ca9a08b2f636fe 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f13.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f13.h @@ -74,7 +74,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f13_pack(uint8_t system_id, * @brief Pack a serial_udb_extra_f13 message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param sue_week_no Serial UDB Extra GPS Week Number * @param sue_lat_origin Serial UDB Extra MP Origin Latitude @@ -113,7 +113,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f13_pack_chan(uint8_t system } /** - * @brief Encode a serial_udb_extra_f13 struct into a message + * @brief Encode a serial_udb_extra_f13 struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -125,6 +125,20 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f13_encode(uint8_t system_id return mavlink_msg_serial_udb_extra_f13_pack(system_id, component_id, msg, serial_udb_extra_f13->sue_week_no, serial_udb_extra_f13->sue_lat_origin, serial_udb_extra_f13->sue_lon_origin, serial_udb_extra_f13->sue_alt_origin); } +/** + * @brief Encode a serial_udb_extra_f13 struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param serial_udb_extra_f13 C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_serial_udb_extra_f13_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_serial_udb_extra_f13_t* serial_udb_extra_f13) +{ + return mavlink_msg_serial_udb_extra_f13_pack_chan(system_id, component_id, chan, msg, serial_udb_extra_f13->sue_week_no, serial_udb_extra_f13->sue_lat_origin, serial_udb_extra_f13->sue_lon_origin, serial_udb_extra_f13->sue_alt_origin); +} + /** * @brief Send a serial_udb_extra_f13 message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f14.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f14.h index 5e38a590a46e159ab14e516de04423aaee846fca..6ac12f28a6529fff38c3e37d55b6219eca93562a 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f14.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f14.h @@ -109,7 +109,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f14_pack(uint8_t system_id, * @brief Pack a serial_udb_extra_f14 message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param sue_WIND_ESTIMATION Serial UDB Extra Wind Estimation Enabled * @param sue_GPS_TYPE Serial UDB Extra Type of GPS Unit @@ -169,7 +169,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f14_pack_chan(uint8_t system } /** - * @brief Encode a serial_udb_extra_f14 struct into a message + * @brief Encode a serial_udb_extra_f14 struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -181,6 +181,20 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f14_encode(uint8_t system_id return mavlink_msg_serial_udb_extra_f14_pack(system_id, component_id, msg, serial_udb_extra_f14->sue_WIND_ESTIMATION, serial_udb_extra_f14->sue_GPS_TYPE, serial_udb_extra_f14->sue_DR, serial_udb_extra_f14->sue_BOARD_TYPE, serial_udb_extra_f14->sue_AIRFRAME, serial_udb_extra_f14->sue_RCON, serial_udb_extra_f14->sue_TRAP_FLAGS, serial_udb_extra_f14->sue_TRAP_SOURCE, serial_udb_extra_f14->sue_osc_fail_count, serial_udb_extra_f14->sue_CLOCK_CONFIG, serial_udb_extra_f14->sue_FLIGHT_PLAN_TYPE); } +/** + * @brief Encode a serial_udb_extra_f14 struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param serial_udb_extra_f14 C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_serial_udb_extra_f14_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_serial_udb_extra_f14_t* serial_udb_extra_f14) +{ + return mavlink_msg_serial_udb_extra_f14_pack_chan(system_id, component_id, chan, msg, serial_udb_extra_f14->sue_WIND_ESTIMATION, serial_udb_extra_f14->sue_GPS_TYPE, serial_udb_extra_f14->sue_DR, serial_udb_extra_f14->sue_BOARD_TYPE, serial_udb_extra_f14->sue_AIRFRAME, serial_udb_extra_f14->sue_RCON, serial_udb_extra_f14->sue_TRAP_FLAGS, serial_udb_extra_f14->sue_TRAP_SOURCE, serial_udb_extra_f14->sue_osc_fail_count, serial_udb_extra_f14->sue_CLOCK_CONFIG, serial_udb_extra_f14->sue_FLIGHT_PLAN_TYPE); +} + /** * @brief Send a serial_udb_extra_f14 message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f15.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f15.h index 8779b25ff5f5366307fab0af08baa500d9aac610..10c3f4ca4fe84243cff49c36b8a0e35aac0f60b4 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f15.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f15.h @@ -65,7 +65,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f15_pack(uint8_t system_id, * @brief Pack a serial_udb_extra_f15 message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param sue_ID_VEHICLE_MODEL_NAME Serial UDB Extra Model Name Of Vehicle * @param sue_ID_VEHICLE_REGISTRATION Serial UDB Extra Registraton Number of Vehicle @@ -98,7 +98,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f15_pack_chan(uint8_t system } /** - * @brief Encode a serial_udb_extra_f15 struct into a message + * @brief Encode a serial_udb_extra_f15 struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -110,6 +110,20 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f15_encode(uint8_t system_id return mavlink_msg_serial_udb_extra_f15_pack(system_id, component_id, msg, serial_udb_extra_f15->sue_ID_VEHICLE_MODEL_NAME, serial_udb_extra_f15->sue_ID_VEHICLE_REGISTRATION); } +/** + * @brief Encode a serial_udb_extra_f15 struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param serial_udb_extra_f15 C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_serial_udb_extra_f15_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_serial_udb_extra_f15_t* serial_udb_extra_f15) +{ + return mavlink_msg_serial_udb_extra_f15_pack_chan(system_id, component_id, chan, msg, serial_udb_extra_f15->sue_ID_VEHICLE_MODEL_NAME, serial_udb_extra_f15->sue_ID_VEHICLE_REGISTRATION); +} + /** * @brief Send a serial_udb_extra_f15 message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f16.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f16.h index 1a173bfe448453ae80b853f6b60854062d3373ab..659e6b7c5278f225f0fadbf70a1525aeebe2c8b1 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f16.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f16.h @@ -65,7 +65,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f16_pack(uint8_t system_id, * @brief Pack a serial_udb_extra_f16 message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param sue_ID_LEAD_PILOT Serial UDB Extra Name of Expected Lead Pilot * @param sue_ID_DIY_DRONES_URL Serial UDB Extra URL of Lead Pilot or Team @@ -98,7 +98,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f16_pack_chan(uint8_t system } /** - * @brief Encode a serial_udb_extra_f16 struct into a message + * @brief Encode a serial_udb_extra_f16 struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -110,6 +110,20 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f16_encode(uint8_t system_id return mavlink_msg_serial_udb_extra_f16_pack(system_id, component_id, msg, serial_udb_extra_f16->sue_ID_LEAD_PILOT, serial_udb_extra_f16->sue_ID_DIY_DRONES_URL); } +/** + * @brief Encode a serial_udb_extra_f16 struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param serial_udb_extra_f16 C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_serial_udb_extra_f16_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_serial_udb_extra_f16_t* serial_udb_extra_f16) +{ + return mavlink_msg_serial_udb_extra_f16_pack_chan(system_id, component_id, chan, msg, serial_udb_extra_f16->sue_ID_LEAD_PILOT, serial_udb_extra_f16->sue_ID_DIY_DRONES_URL); +} + /** * @brief Send a serial_udb_extra_f16 message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f2_a.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f2_a.h index ddfc236ba40aa69f3713e991f76994005aa769dd..15ba68a3467ad877ce931c0d0c1c19a5b1b1429a 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f2_a.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f2_a.h @@ -194,7 +194,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f2_a_pack(uint8_t system_id, * @brief Pack a serial_udb_extra_f2_a message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param sue_time Serial UDB Extra Time * @param sue_status Serial UDB Extra Status @@ -305,7 +305,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f2_a_pack_chan(uint8_t syste } /** - * @brief Encode a serial_udb_extra_f2_a struct into a message + * @brief Encode a serial_udb_extra_f2_a struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -317,6 +317,20 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f2_a_encode(uint8_t system_i return mavlink_msg_serial_udb_extra_f2_a_pack(system_id, component_id, msg, serial_udb_extra_f2_a->sue_time, serial_udb_extra_f2_a->sue_status, serial_udb_extra_f2_a->sue_latitude, serial_udb_extra_f2_a->sue_longitude, serial_udb_extra_f2_a->sue_altitude, serial_udb_extra_f2_a->sue_waypoint_index, serial_udb_extra_f2_a->sue_rmat0, serial_udb_extra_f2_a->sue_rmat1, serial_udb_extra_f2_a->sue_rmat2, serial_udb_extra_f2_a->sue_rmat3, serial_udb_extra_f2_a->sue_rmat4, serial_udb_extra_f2_a->sue_rmat5, serial_udb_extra_f2_a->sue_rmat6, serial_udb_extra_f2_a->sue_rmat7, serial_udb_extra_f2_a->sue_rmat8, serial_udb_extra_f2_a->sue_cog, serial_udb_extra_f2_a->sue_sog, serial_udb_extra_f2_a->sue_cpu_load, serial_udb_extra_f2_a->sue_voltage_milis, serial_udb_extra_f2_a->sue_air_speed_3DIMU, serial_udb_extra_f2_a->sue_estimated_wind_0, serial_udb_extra_f2_a->sue_estimated_wind_1, serial_udb_extra_f2_a->sue_estimated_wind_2, serial_udb_extra_f2_a->sue_magFieldEarth0, serial_udb_extra_f2_a->sue_magFieldEarth1, serial_udb_extra_f2_a->sue_magFieldEarth2, serial_udb_extra_f2_a->sue_svs, serial_udb_extra_f2_a->sue_hdop); } +/** + * @brief Encode a serial_udb_extra_f2_a struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param serial_udb_extra_f2_a C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_serial_udb_extra_f2_a_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_serial_udb_extra_f2_a_t* serial_udb_extra_f2_a) +{ + return mavlink_msg_serial_udb_extra_f2_a_pack_chan(system_id, component_id, chan, msg, serial_udb_extra_f2_a->sue_time, serial_udb_extra_f2_a->sue_status, serial_udb_extra_f2_a->sue_latitude, serial_udb_extra_f2_a->sue_longitude, serial_udb_extra_f2_a->sue_altitude, serial_udb_extra_f2_a->sue_waypoint_index, serial_udb_extra_f2_a->sue_rmat0, serial_udb_extra_f2_a->sue_rmat1, serial_udb_extra_f2_a->sue_rmat2, serial_udb_extra_f2_a->sue_rmat3, serial_udb_extra_f2_a->sue_rmat4, serial_udb_extra_f2_a->sue_rmat5, serial_udb_extra_f2_a->sue_rmat6, serial_udb_extra_f2_a->sue_rmat7, serial_udb_extra_f2_a->sue_rmat8, serial_udb_extra_f2_a->sue_cog, serial_udb_extra_f2_a->sue_sog, serial_udb_extra_f2_a->sue_cpu_load, serial_udb_extra_f2_a->sue_voltage_milis, serial_udb_extra_f2_a->sue_air_speed_3DIMU, serial_udb_extra_f2_a->sue_estimated_wind_0, serial_udb_extra_f2_a->sue_estimated_wind_1, serial_udb_extra_f2_a->sue_estimated_wind_2, serial_udb_extra_f2_a->sue_magFieldEarth0, serial_udb_extra_f2_a->sue_magFieldEarth1, serial_udb_extra_f2_a->sue_magFieldEarth2, serial_udb_extra_f2_a->sue_svs, serial_udb_extra_f2_a->sue_hdop); +} + /** * @brief Send a serial_udb_extra_f2_a message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f2_b.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f2_b.h index 74da8416d86ea355bfb714b3e0a637f7ce14d1ab..7cb8c87da5beffd02d61fc2b60b61be1a6f01790 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f2_b.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f2_b.h @@ -219,7 +219,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f2_b_pack(uint8_t system_id, * @brief Pack a serial_udb_extra_f2_b message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param sue_time Serial UDB Extra Time * @param sue_pwm_input_1 Serial UDB Extra PWM Input Channel 1 @@ -345,7 +345,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f2_b_pack_chan(uint8_t syste } /** - * @brief Encode a serial_udb_extra_f2_b struct into a message + * @brief Encode a serial_udb_extra_f2_b struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -357,6 +357,20 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f2_b_encode(uint8_t system_i return mavlink_msg_serial_udb_extra_f2_b_pack(system_id, component_id, msg, serial_udb_extra_f2_b->sue_time, serial_udb_extra_f2_b->sue_pwm_input_1, serial_udb_extra_f2_b->sue_pwm_input_2, serial_udb_extra_f2_b->sue_pwm_input_3, serial_udb_extra_f2_b->sue_pwm_input_4, serial_udb_extra_f2_b->sue_pwm_input_5, serial_udb_extra_f2_b->sue_pwm_input_6, serial_udb_extra_f2_b->sue_pwm_input_7, serial_udb_extra_f2_b->sue_pwm_input_8, serial_udb_extra_f2_b->sue_pwm_input_9, serial_udb_extra_f2_b->sue_pwm_input_10, serial_udb_extra_f2_b->sue_pwm_output_1, serial_udb_extra_f2_b->sue_pwm_output_2, serial_udb_extra_f2_b->sue_pwm_output_3, serial_udb_extra_f2_b->sue_pwm_output_4, serial_udb_extra_f2_b->sue_pwm_output_5, serial_udb_extra_f2_b->sue_pwm_output_6, serial_udb_extra_f2_b->sue_pwm_output_7, serial_udb_extra_f2_b->sue_pwm_output_8, serial_udb_extra_f2_b->sue_pwm_output_9, serial_udb_extra_f2_b->sue_pwm_output_10, serial_udb_extra_f2_b->sue_imu_location_x, serial_udb_extra_f2_b->sue_imu_location_y, serial_udb_extra_f2_b->sue_imu_location_z, serial_udb_extra_f2_b->sue_flags, serial_udb_extra_f2_b->sue_osc_fails, serial_udb_extra_f2_b->sue_imu_velocity_x, serial_udb_extra_f2_b->sue_imu_velocity_y, serial_udb_extra_f2_b->sue_imu_velocity_z, serial_udb_extra_f2_b->sue_waypoint_goal_x, serial_udb_extra_f2_b->sue_waypoint_goal_y, serial_udb_extra_f2_b->sue_waypoint_goal_z, serial_udb_extra_f2_b->sue_memory_stack_free); } +/** + * @brief Encode a serial_udb_extra_f2_b struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param serial_udb_extra_f2_b C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_serial_udb_extra_f2_b_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_serial_udb_extra_f2_b_t* serial_udb_extra_f2_b) +{ + return mavlink_msg_serial_udb_extra_f2_b_pack_chan(system_id, component_id, chan, msg, serial_udb_extra_f2_b->sue_time, serial_udb_extra_f2_b->sue_pwm_input_1, serial_udb_extra_f2_b->sue_pwm_input_2, serial_udb_extra_f2_b->sue_pwm_input_3, serial_udb_extra_f2_b->sue_pwm_input_4, serial_udb_extra_f2_b->sue_pwm_input_5, serial_udb_extra_f2_b->sue_pwm_input_6, serial_udb_extra_f2_b->sue_pwm_input_7, serial_udb_extra_f2_b->sue_pwm_input_8, serial_udb_extra_f2_b->sue_pwm_input_9, serial_udb_extra_f2_b->sue_pwm_input_10, serial_udb_extra_f2_b->sue_pwm_output_1, serial_udb_extra_f2_b->sue_pwm_output_2, serial_udb_extra_f2_b->sue_pwm_output_3, serial_udb_extra_f2_b->sue_pwm_output_4, serial_udb_extra_f2_b->sue_pwm_output_5, serial_udb_extra_f2_b->sue_pwm_output_6, serial_udb_extra_f2_b->sue_pwm_output_7, serial_udb_extra_f2_b->sue_pwm_output_8, serial_udb_extra_f2_b->sue_pwm_output_9, serial_udb_extra_f2_b->sue_pwm_output_10, serial_udb_extra_f2_b->sue_imu_location_x, serial_udb_extra_f2_b->sue_imu_location_y, serial_udb_extra_f2_b->sue_imu_location_z, serial_udb_extra_f2_b->sue_flags, serial_udb_extra_f2_b->sue_osc_fails, serial_udb_extra_f2_b->sue_imu_velocity_x, serial_udb_extra_f2_b->sue_imu_velocity_y, serial_udb_extra_f2_b->sue_imu_velocity_z, serial_udb_extra_f2_b->sue_waypoint_goal_x, serial_udb_extra_f2_b->sue_waypoint_goal_y, serial_udb_extra_f2_b->sue_waypoint_goal_z, serial_udb_extra_f2_b->sue_memory_stack_free); +} + /** * @brief Send a serial_udb_extra_f2_b message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f4.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f4.h index 83ccbbedb4857a57f3fa64700cfd3884780c0d26..77c616cc2eba5ccaf4f628ae8842820cb23ff1ab 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f4.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f4.h @@ -104,7 +104,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f4_pack(uint8_t system_id, u * @brief Pack a serial_udb_extra_f4 message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param sue_ROLL_STABILIZATION_AILERONS Serial UDB Extra Roll Stabilization with Ailerons Enabled * @param sue_ROLL_STABILIZATION_RUDDER Serial UDB Extra Roll Stabilization with Rudder Enabled @@ -161,7 +161,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f4_pack_chan(uint8_t system_ } /** - * @brief Encode a serial_udb_extra_f4 struct into a message + * @brief Encode a serial_udb_extra_f4 struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -173,6 +173,20 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f4_encode(uint8_t system_id, return mavlink_msg_serial_udb_extra_f4_pack(system_id, component_id, msg, serial_udb_extra_f4->sue_ROLL_STABILIZATION_AILERONS, serial_udb_extra_f4->sue_ROLL_STABILIZATION_RUDDER, serial_udb_extra_f4->sue_PITCH_STABILIZATION, serial_udb_extra_f4->sue_YAW_STABILIZATION_RUDDER, serial_udb_extra_f4->sue_YAW_STABILIZATION_AILERON, serial_udb_extra_f4->sue_AILERON_NAVIGATION, serial_udb_extra_f4->sue_RUDDER_NAVIGATION, serial_udb_extra_f4->sue_ALTITUDEHOLD_STABILIZED, serial_udb_extra_f4->sue_ALTITUDEHOLD_WAYPOINT, serial_udb_extra_f4->sue_RACING_MODE); } +/** + * @brief Encode a serial_udb_extra_f4 struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param serial_udb_extra_f4 C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_serial_udb_extra_f4_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_serial_udb_extra_f4_t* serial_udb_extra_f4) +{ + return mavlink_msg_serial_udb_extra_f4_pack_chan(system_id, component_id, chan, msg, serial_udb_extra_f4->sue_ROLL_STABILIZATION_AILERONS, serial_udb_extra_f4->sue_ROLL_STABILIZATION_RUDDER, serial_udb_extra_f4->sue_PITCH_STABILIZATION, serial_udb_extra_f4->sue_YAW_STABILIZATION_RUDDER, serial_udb_extra_f4->sue_YAW_STABILIZATION_AILERON, serial_udb_extra_f4->sue_AILERON_NAVIGATION, serial_udb_extra_f4->sue_RUDDER_NAVIGATION, serial_udb_extra_f4->sue_ALTITUDEHOLD_STABILIZED, serial_udb_extra_f4->sue_ALTITUDEHOLD_WAYPOINT, serial_udb_extra_f4->sue_RACING_MODE); +} + /** * @brief Send a serial_udb_extra_f4 message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f5.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f5.h index 2b2451f00d707e773bc7827592a09b041b155fcb..e115a9b445760f41114531a877fd8e0be445f4dc 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f5.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f5.h @@ -84,7 +84,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f5_pack(uint8_t system_id, u * @brief Pack a serial_udb_extra_f5 message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param sue_YAWKP_AILERON Serial UDB YAWKP_AILERON Gain for Proporional control of navigation * @param sue_YAWKD_AILERON Serial UDB YAWKD_AILERON Gain for Rate control of navigation @@ -129,7 +129,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f5_pack_chan(uint8_t system_ } /** - * @brief Encode a serial_udb_extra_f5 struct into a message + * @brief Encode a serial_udb_extra_f5 struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -141,6 +141,20 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f5_encode(uint8_t system_id, return mavlink_msg_serial_udb_extra_f5_pack(system_id, component_id, msg, serial_udb_extra_f5->sue_YAWKP_AILERON, serial_udb_extra_f5->sue_YAWKD_AILERON, serial_udb_extra_f5->sue_ROLLKP, serial_udb_extra_f5->sue_ROLLKD, serial_udb_extra_f5->sue_YAW_STABILIZATION_AILERON, serial_udb_extra_f5->sue_AILERON_BOOST); } +/** + * @brief Encode a serial_udb_extra_f5 struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param serial_udb_extra_f5 C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_serial_udb_extra_f5_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_serial_udb_extra_f5_t* serial_udb_extra_f5) +{ + return mavlink_msg_serial_udb_extra_f5_pack_chan(system_id, component_id, chan, msg, serial_udb_extra_f5->sue_YAWKP_AILERON, serial_udb_extra_f5->sue_YAWKD_AILERON, serial_udb_extra_f5->sue_ROLLKP, serial_udb_extra_f5->sue_ROLLKD, serial_udb_extra_f5->sue_YAW_STABILIZATION_AILERON, serial_udb_extra_f5->sue_AILERON_BOOST); +} + /** * @brief Send a serial_udb_extra_f5 message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f6.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f6.h index 9d58ca9a8e170d8c8831fc1e6727cc505017e342..656103d0905c25c393c845cfcce8f9e5305455a3 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f6.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f6.h @@ -79,7 +79,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f6_pack(uint8_t system_id, u * @brief Pack a serial_udb_extra_f6 message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param sue_PITCHGAIN Serial UDB Extra PITCHGAIN Proportional Control * @param sue_PITCHKD Serial UDB Extra Pitch Rate Control @@ -121,7 +121,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f6_pack_chan(uint8_t system_ } /** - * @brief Encode a serial_udb_extra_f6 struct into a message + * @brief Encode a serial_udb_extra_f6 struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -133,6 +133,20 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f6_encode(uint8_t system_id, return mavlink_msg_serial_udb_extra_f6_pack(system_id, component_id, msg, serial_udb_extra_f6->sue_PITCHGAIN, serial_udb_extra_f6->sue_PITCHKD, serial_udb_extra_f6->sue_RUDDER_ELEV_MIX, serial_udb_extra_f6->sue_ROLL_ELEV_MIX, serial_udb_extra_f6->sue_ELEVATOR_BOOST); } +/** + * @brief Encode a serial_udb_extra_f6 struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param serial_udb_extra_f6 C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_serial_udb_extra_f6_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_serial_udb_extra_f6_t* serial_udb_extra_f6) +{ + return mavlink_msg_serial_udb_extra_f6_pack_chan(system_id, component_id, chan, msg, serial_udb_extra_f6->sue_PITCHGAIN, serial_udb_extra_f6->sue_PITCHKD, serial_udb_extra_f6->sue_RUDDER_ELEV_MIX, serial_udb_extra_f6->sue_ROLL_ELEV_MIX, serial_udb_extra_f6->sue_ELEVATOR_BOOST); +} + /** * @brief Send a serial_udb_extra_f6 message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f7.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f7.h index ab73b967e07c3619d7fa7b3411fa39e5b02e37f3..51c98e6b7ab5acb840ed71f779cb74e3213d245a 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f7.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f7.h @@ -84,7 +84,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f7_pack(uint8_t system_id, u * @brief Pack a serial_udb_extra_f7 message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param sue_YAWKP_RUDDER Serial UDB YAWKP_RUDDER Gain for Proporional control of navigation * @param sue_YAWKD_RUDDER Serial UDB YAWKD_RUDDER Gain for Rate control of navigation @@ -129,7 +129,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f7_pack_chan(uint8_t system_ } /** - * @brief Encode a serial_udb_extra_f7 struct into a message + * @brief Encode a serial_udb_extra_f7 struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -141,6 +141,20 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f7_encode(uint8_t system_id, return mavlink_msg_serial_udb_extra_f7_pack(system_id, component_id, msg, serial_udb_extra_f7->sue_YAWKP_RUDDER, serial_udb_extra_f7->sue_YAWKD_RUDDER, serial_udb_extra_f7->sue_ROLLKP_RUDDER, serial_udb_extra_f7->sue_ROLLKD_RUDDER, serial_udb_extra_f7->sue_RUDDER_BOOST, serial_udb_extra_f7->sue_RTL_PITCH_DOWN); } +/** + * @brief Encode a serial_udb_extra_f7 struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param serial_udb_extra_f7 C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_serial_udb_extra_f7_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_serial_udb_extra_f7_t* serial_udb_extra_f7) +{ + return mavlink_msg_serial_udb_extra_f7_pack_chan(system_id, component_id, chan, msg, serial_udb_extra_f7->sue_YAWKP_RUDDER, serial_udb_extra_f7->sue_YAWKD_RUDDER, serial_udb_extra_f7->sue_ROLLKP_RUDDER, serial_udb_extra_f7->sue_ROLLKD_RUDDER, serial_udb_extra_f7->sue_RUDDER_BOOST, serial_udb_extra_f7->sue_RTL_PITCH_DOWN); +} + /** * @brief Send a serial_udb_extra_f7 message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f8.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f8.h index 310246e8e72777b1934fe0005fbf991cda3bc3c6..8557a95e27eaf225833304073d0258488c89c106 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f8.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/mavlink_msg_serial_udb_extra_f8.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f8_pack(uint8_t system_id, u * @brief Pack a serial_udb_extra_f8 message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param sue_HEIGHT_TARGET_MAX Serial UDB Extra HEIGHT_TARGET_MAX * @param sue_HEIGHT_TARGET_MIN Serial UDB Extra HEIGHT_TARGET_MIN @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f8_pack_chan(uint8_t system_ } /** - * @brief Encode a serial_udb_extra_f8 struct into a message + * @brief Encode a serial_udb_extra_f8 struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_serial_udb_extra_f8_encode(uint8_t system_id, return mavlink_msg_serial_udb_extra_f8_pack(system_id, component_id, msg, serial_udb_extra_f8->sue_HEIGHT_TARGET_MAX, serial_udb_extra_f8->sue_HEIGHT_TARGET_MIN, serial_udb_extra_f8->sue_ALT_HOLD_THROTTLE_MIN, serial_udb_extra_f8->sue_ALT_HOLD_THROTTLE_MAX, serial_udb_extra_f8->sue_ALT_HOLD_PITCH_MIN, serial_udb_extra_f8->sue_ALT_HOLD_PITCH_MAX, serial_udb_extra_f8->sue_ALT_HOLD_PITCH_HIGH); } +/** + * @brief Encode a serial_udb_extra_f8 struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param serial_udb_extra_f8 C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_serial_udb_extra_f8_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_serial_udb_extra_f8_t* serial_udb_extra_f8) +{ + return mavlink_msg_serial_udb_extra_f8_pack_chan(system_id, component_id, chan, msg, serial_udb_extra_f8->sue_HEIGHT_TARGET_MAX, serial_udb_extra_f8->sue_HEIGHT_TARGET_MIN, serial_udb_extra_f8->sue_ALT_HOLD_THROTTLE_MIN, serial_udb_extra_f8->sue_ALT_HOLD_THROTTLE_MAX, serial_udb_extra_f8->sue_ALT_HOLD_PITCH_MIN, serial_udb_extra_f8->sue_ALT_HOLD_PITCH_MAX, serial_udb_extra_f8->sue_ALT_HOLD_PITCH_HIGH); +} + /** * @brief Send a serial_udb_extra_f8 message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/matrixpilot/version.h b/libs/mavlink/include/mavlink/v1.0/matrixpilot/version.h index ea0265298bc9b6a230caae7137b682c1acf327af..59f3d2ded20ec0df94849ad84f916e99b11695e0 100644 --- a/libs/mavlink/include/mavlink/v1.0/matrixpilot/version.h +++ b/libs/mavlink/include/mavlink/v1.0/matrixpilot/version.h @@ -5,7 +5,7 @@ #ifndef MAVLINK_VERSION_H #define MAVLINK_VERSION_H -#define MAVLINK_BUILD_DATE "Thu Jul 4 13:11:50 2013" +#define MAVLINK_BUILD_DATE "Tue Sep 10 23:49:51 2013" #define MAVLINK_WIRE_PROTOCOL_VERSION "1.0" #define MAVLINK_MAX_DIALECT_PAYLOAD_SIZE 254 diff --git a/libs/mavlink/include/mavlink/v1.0/mavlink_helpers.h b/libs/mavlink/include/mavlink/v1.0/mavlink_helpers.h index 72cf91fb9f39d796e31042cbbfba4272f96f98a1..96672f847f43185e52305b25d36575c9880c6404 100644 --- a/libs/mavlink/include/mavlink/v1.0/mavlink_helpers.h +++ b/libs/mavlink/include/mavlink/v1.0/mavlink_helpers.h @@ -16,7 +16,12 @@ #ifndef MAVLINK_GET_CHANNEL_STATUS MAVLINK_HELPER mavlink_status_t* mavlink_get_channel_status(uint8_t chan) { +#if MAVLINK_EXTERNAL_RX_STATUS + // No m_mavlink_status array defined in function, + // has to be defined externally +#else static mavlink_status_t m_mavlink_status[MAVLINK_COMM_NUM_BUFFERS]; +#endif return &m_mavlink_status[chan]; } #endif @@ -29,11 +34,8 @@ MAVLINK_HELPER mavlink_message_t* mavlink_get_channel_buffer(uint8_t chan) { #if MAVLINK_EXTERNAL_RX_BUFFER - // No m_mavlink_message array defined in function, + // No m_mavlink_buffer array defined in function, // has to be defined externally -#ifndef m_mavlink_message -#error ERROR: IF #define MAVLINK_EXTERNAL_RX_BUFFER IS SET, THE BUFFER HAS TO BE ALLOCATED OUTSIDE OF THIS FUNCTION (mavlink_message_t m_mavlink_buffer[MAVLINK_COMM_NUM_BUFFERS];) -#endif #else static mavlink_message_t m_mavlink_buffer[MAVLINK_COMM_NUM_BUFFERS]; #endif diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_attitude_control.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_attitude_control.h index 1aac8395dfad3cd2c006afdd2c2cb6923e8177c3..ef5354d5e15f5539b2d408ab94d3881dafe647b2 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_attitude_control.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_attitude_control.h @@ -99,7 +99,7 @@ static inline uint16_t mavlink_msg_attitude_control_pack(uint8_t system_id, uint * @brief Pack a attitude_control message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target The system to be controlled * @param roll roll @@ -153,7 +153,7 @@ static inline uint16_t mavlink_msg_attitude_control_pack_chan(uint8_t system_id, } /** - * @brief Encode a attitude_control struct into a message + * @brief Encode a attitude_control struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -165,6 +165,20 @@ static inline uint16_t mavlink_msg_attitude_control_encode(uint8_t system_id, ui return mavlink_msg_attitude_control_pack(system_id, component_id, msg, attitude_control->target, attitude_control->roll, attitude_control->pitch, attitude_control->yaw, attitude_control->thrust, attitude_control->roll_manual, attitude_control->pitch_manual, attitude_control->yaw_manual, attitude_control->thrust_manual); } +/** + * @brief Encode a attitude_control struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param attitude_control C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_attitude_control_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_attitude_control_t* attitude_control) +{ + return mavlink_msg_attitude_control_pack_chan(system_id, component_id, chan, msg, attitude_control->target, attitude_control->roll, attitude_control->pitch, attitude_control->yaw, attitude_control->thrust, attitude_control->roll_manual, attitude_control->pitch_manual, attitude_control->yaw_manual, attitude_control->thrust_manual); +} + /** * @brief Send a attitude_control message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_brief_feature.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_brief_feature.h index 353e105814c2e09b7f7102d994809a2b6722b68b..d41093792ef47485ecf942dbf44f2006ce9a7164 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_brief_feature.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_brief_feature.h @@ -92,7 +92,7 @@ static inline uint16_t mavlink_msg_brief_feature_pack(uint8_t system_id, uint8_t * @brief Pack a brief_feature message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param x x position in m * @param y y position in m @@ -141,7 +141,7 @@ static inline uint16_t mavlink_msg_brief_feature_pack_chan(uint8_t system_id, ui } /** - * @brief Encode a brief_feature struct into a message + * @brief Encode a brief_feature struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -153,6 +153,20 @@ static inline uint16_t mavlink_msg_brief_feature_encode(uint8_t system_id, uint8 return mavlink_msg_brief_feature_pack(system_id, component_id, msg, brief_feature->x, brief_feature->y, brief_feature->z, brief_feature->orientation_assignment, brief_feature->size, brief_feature->orientation, brief_feature->descriptor, brief_feature->response); } +/** + * @brief Encode a brief_feature struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param brief_feature C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_brief_feature_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_brief_feature_t* brief_feature) +{ + return mavlink_msg_brief_feature_pack_chan(system_id, component_id, chan, msg, brief_feature->x, brief_feature->y, brief_feature->z, brief_feature->orientation_assignment, brief_feature->size, brief_feature->orientation, brief_feature->descriptor, brief_feature->response); +} + /** * @brief Send a brief_feature message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_data_transmission_handshake.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_data_transmission_handshake.h index 5251c35c326b64650c1ef8649fcf856d2944b6b0..a7af8c8ebb0481c89d62c5dfbf96366187939146 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_data_transmission_handshake.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_data_transmission_handshake.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_data_transmission_handshake_pack(uint8_t syst * @brief Pack a data_transmission_handshake message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param type type of requested/acknowledged data (as defined in ENUM DATA_TYPES in mavlink/include/mavlink_types.h) * @param size total data size in bytes (set on ACK only) @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_data_transmission_handshake_pack_chan(uint8_t } /** - * @brief Encode a data_transmission_handshake struct into a message + * @brief Encode a data_transmission_handshake struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_data_transmission_handshake_encode(uint8_t sy return mavlink_msg_data_transmission_handshake_pack(system_id, component_id, msg, data_transmission_handshake->type, data_transmission_handshake->size, data_transmission_handshake->width, data_transmission_handshake->height, data_transmission_handshake->packets, data_transmission_handshake->payload, data_transmission_handshake->jpg_quality); } +/** + * @brief Encode a data_transmission_handshake struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param data_transmission_handshake C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_data_transmission_handshake_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_data_transmission_handshake_t* data_transmission_handshake) +{ + return mavlink_msg_data_transmission_handshake_pack_chan(system_id, component_id, chan, msg, data_transmission_handshake->type, data_transmission_handshake->size, data_transmission_handshake->width, data_transmission_handshake->height, data_transmission_handshake->packets, data_transmission_handshake->payload, data_transmission_handshake->jpg_quality); +} + /** * @brief Send a data_transmission_handshake message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_encapsulated_data.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_encapsulated_data.h index feeef6f39883873188ed6605faf375de92ad8d24..40001dc3095c34a20598be6ba2ddda6399e67fd3 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_encapsulated_data.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_encapsulated_data.h @@ -62,7 +62,7 @@ static inline uint16_t mavlink_msg_encapsulated_data_pack(uint8_t system_id, uin * @brief Pack a encapsulated_data message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param seqnr sequence number (starting with 0 on every transmission) * @param data image data bytes @@ -93,7 +93,7 @@ static inline uint16_t mavlink_msg_encapsulated_data_pack_chan(uint8_t system_id } /** - * @brief Encode a encapsulated_data struct into a message + * @brief Encode a encapsulated_data struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -105,6 +105,20 @@ static inline uint16_t mavlink_msg_encapsulated_data_encode(uint8_t system_id, u return mavlink_msg_encapsulated_data_pack(system_id, component_id, msg, encapsulated_data->seqnr, encapsulated_data->data); } +/** + * @brief Encode a encapsulated_data struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param encapsulated_data C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_encapsulated_data_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_encapsulated_data_t* encapsulated_data) +{ + return mavlink_msg_encapsulated_data_pack_chan(system_id, component_id, chan, msg, encapsulated_data->seqnr, encapsulated_data->data); +} + /** * @brief Send a encapsulated_data message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_image_available.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_image_available.h index 6d1d9cca7621b1f02380ec7dad503f53f5cbf74a..ae4db825df152b1d66d2ce535873bed33bafb6e3 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_image_available.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_image_available.h @@ -169,7 +169,7 @@ static inline uint16_t mavlink_msg_image_available_pack(uint8_t system_id, uint8 * @brief Pack a image_available message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param cam_id Camera id * @param cam_no Camera # (starts with 0) @@ -265,7 +265,7 @@ static inline uint16_t mavlink_msg_image_available_pack_chan(uint8_t system_id, } /** - * @brief Encode a image_available struct into a message + * @brief Encode a image_available struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -277,6 +277,20 @@ static inline uint16_t mavlink_msg_image_available_encode(uint8_t system_id, uin return mavlink_msg_image_available_pack(system_id, component_id, msg, image_available->cam_id, image_available->cam_no, image_available->timestamp, image_available->valid_until, image_available->img_seq, image_available->img_buf_index, image_available->width, image_available->height, image_available->depth, image_available->channels, image_available->key, image_available->exposure, image_available->gain, image_available->roll, image_available->pitch, image_available->yaw, image_available->local_z, image_available->lat, image_available->lon, image_available->alt, image_available->ground_x, image_available->ground_y, image_available->ground_z); } +/** + * @brief Encode a image_available struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param image_available C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_image_available_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_image_available_t* image_available) +{ + return mavlink_msg_image_available_pack_chan(system_id, component_id, chan, msg, image_available->cam_id, image_available->cam_no, image_available->timestamp, image_available->valid_until, image_available->img_seq, image_available->img_buf_index, image_available->width, image_available->height, image_available->depth, image_available->channels, image_available->key, image_available->exposure, image_available->gain, image_available->roll, image_available->pitch, image_available->yaw, image_available->local_z, image_available->lat, image_available->lon, image_available->alt, image_available->ground_x, image_available->ground_y, image_available->ground_z); +} + /** * @brief Send a image_available message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_image_trigger_control.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_image_trigger_control.h index 784cedf8b5e61d4ac47fae4c42da6a3e99cf76ee..664574be94763643d3e392543cae4bfabe211e3c 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_image_trigger_control.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_image_trigger_control.h @@ -59,7 +59,7 @@ static inline uint16_t mavlink_msg_image_trigger_control_pack(uint8_t system_id, * @brief Pack a image_trigger_control message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param enable 0 to disable, 1 to enable * @return length of the message in bytes (excluding serial stream start sign) @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_image_trigger_control_pack_chan(uint8_t syste } /** - * @brief Encode a image_trigger_control struct into a message + * @brief Encode a image_trigger_control struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -101,6 +101,20 @@ static inline uint16_t mavlink_msg_image_trigger_control_encode(uint8_t system_i return mavlink_msg_image_trigger_control_pack(system_id, component_id, msg, image_trigger_control->enable); } +/** + * @brief Encode a image_trigger_control struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param image_trigger_control C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_image_trigger_control_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_image_trigger_control_t* image_trigger_control) +{ + return mavlink_msg_image_trigger_control_pack_chan(system_id, component_id, chan, msg, image_trigger_control->enable); +} + /** * @brief Send a image_trigger_control message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_image_triggered.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_image_triggered.h index 05b0d775fd56e586d290f087be3ac1e1bf79fb99..f3a2243afcbb012e9fd58981be7613f80f2dd4d3 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_image_triggered.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_image_triggered.h @@ -114,7 +114,7 @@ static inline uint16_t mavlink_msg_image_triggered_pack(uint8_t system_id, uint8 * @brief Pack a image_triggered message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param timestamp Timestamp * @param seq IMU seq @@ -177,7 +177,7 @@ static inline uint16_t mavlink_msg_image_triggered_pack_chan(uint8_t system_id, } /** - * @brief Encode a image_triggered struct into a message + * @brief Encode a image_triggered struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -189,6 +189,20 @@ static inline uint16_t mavlink_msg_image_triggered_encode(uint8_t system_id, uin return mavlink_msg_image_triggered_pack(system_id, component_id, msg, image_triggered->timestamp, image_triggered->seq, image_triggered->roll, image_triggered->pitch, image_triggered->yaw, image_triggered->local_z, image_triggered->lat, image_triggered->lon, image_triggered->alt, image_triggered->ground_x, image_triggered->ground_y, image_triggered->ground_z); } +/** + * @brief Encode a image_triggered struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param image_triggered C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_image_triggered_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_image_triggered_t* image_triggered) +{ + return mavlink_msg_image_triggered_pack_chan(system_id, component_id, chan, msg, image_triggered->timestamp, image_triggered->seq, image_triggered->roll, image_triggered->pitch, image_triggered->yaw, image_triggered->local_z, image_triggered->lat, image_triggered->lon, image_triggered->alt, image_triggered->ground_x, image_triggered->ground_y, image_triggered->ground_z); +} + /** * @brief Send a image_triggered message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_marker.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_marker.h index 817ec60a2043abc63f8d81e8f9f3b1241d5d9cd9..6bdcceaf9a7c0eaef8c9add576bfda820a68ccba 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_marker.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_marker.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_marker_pack(uint8_t system_id, uint8_t compon * @brief Pack a marker message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param id ID * @param x x position @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_marker_pack_chan(uint8_t system_id, uint8_t c } /** - * @brief Encode a marker struct into a message + * @brief Encode a marker struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_marker_encode(uint8_t system_id, uint8_t comp return mavlink_msg_marker_pack(system_id, component_id, msg, marker->id, marker->x, marker->y, marker->z, marker->roll, marker->pitch, marker->yaw); } +/** + * @brief Encode a marker struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param marker C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_marker_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_marker_t* marker) +{ + return mavlink_msg_marker_pack_chan(system_id, component_id, chan, msg, marker->id, marker->x, marker->y, marker->z, marker->roll, marker->pitch, marker->yaw); +} + /** * @brief Send a marker message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_pattern_detected.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_pattern_detected.h index 7e29d7152584be0639f1dcac06f2885392751b42..aa7b827a362b9269a0c56e787e440d6c03f09add 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_pattern_detected.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_pattern_detected.h @@ -72,7 +72,7 @@ static inline uint16_t mavlink_msg_pattern_detected_pack(uint8_t system_id, uint * @brief Pack a pattern_detected message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param type 0: Pattern, 1: Letter * @param confidence Confidence of detection @@ -109,7 +109,7 @@ static inline uint16_t mavlink_msg_pattern_detected_pack_chan(uint8_t system_id, } /** - * @brief Encode a pattern_detected struct into a message + * @brief Encode a pattern_detected struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -121,6 +121,20 @@ static inline uint16_t mavlink_msg_pattern_detected_encode(uint8_t system_id, ui return mavlink_msg_pattern_detected_pack(system_id, component_id, msg, pattern_detected->type, pattern_detected->confidence, pattern_detected->file, pattern_detected->detected); } +/** + * @brief Encode a pattern_detected struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param pattern_detected C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_pattern_detected_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_pattern_detected_t* pattern_detected) +{ + return mavlink_msg_pattern_detected_pack_chan(system_id, component_id, chan, msg, pattern_detected->type, pattern_detected->confidence, pattern_detected->file, pattern_detected->detected); +} + /** * @brief Send a pattern_detected message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_point_of_interest.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_point_of_interest.h index a6faebbb5ac1cc73914ba46157ffb09b151b39b6..913a52897ed9ca3ea99451a264ebec4d5005112c 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_point_of_interest.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_point_of_interest.h @@ -92,7 +92,7 @@ static inline uint16_t mavlink_msg_point_of_interest_pack(uint8_t system_id, uin * @brief Pack a point_of_interest message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param type 0: Notice, 1: Warning, 2: Critical, 3: Emergency, 4: Debug * @param color 0: blue, 1: yellow, 2: red, 3: orange, 4: green, 5: magenta @@ -141,7 +141,7 @@ static inline uint16_t mavlink_msg_point_of_interest_pack_chan(uint8_t system_id } /** - * @brief Encode a point_of_interest struct into a message + * @brief Encode a point_of_interest struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -153,6 +153,20 @@ static inline uint16_t mavlink_msg_point_of_interest_encode(uint8_t system_id, u return mavlink_msg_point_of_interest_pack(system_id, component_id, msg, point_of_interest->type, point_of_interest->color, point_of_interest->coordinate_system, point_of_interest->timeout, point_of_interest->x, point_of_interest->y, point_of_interest->z, point_of_interest->name); } +/** + * @brief Encode a point_of_interest struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param point_of_interest C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_point_of_interest_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_point_of_interest_t* point_of_interest) +{ + return mavlink_msg_point_of_interest_pack_chan(system_id, component_id, chan, msg, point_of_interest->type, point_of_interest->color, point_of_interest->coordinate_system, point_of_interest->timeout, point_of_interest->x, point_of_interest->y, point_of_interest->z, point_of_interest->name); +} + /** * @brief Send a point_of_interest message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_point_of_interest_connection.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_point_of_interest_connection.h index 8d02f9e5c45614b542b3d8a39b17063064ae791a..e2443643186f9cd8e79f1f8c930f9c5f14a18b66 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_point_of_interest_connection.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_point_of_interest_connection.h @@ -107,7 +107,7 @@ static inline uint16_t mavlink_msg_point_of_interest_connection_pack(uint8_t sys * @brief Pack a point_of_interest_connection message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param type 0: Notice, 1: Warning, 2: Critical, 3: Emergency, 4: Debug * @param color 0: blue, 1: yellow, 2: red, 3: orange, 4: green, 5: magenta @@ -165,7 +165,7 @@ static inline uint16_t mavlink_msg_point_of_interest_connection_pack_chan(uint8_ } /** - * @brief Encode a point_of_interest_connection struct into a message + * @brief Encode a point_of_interest_connection struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -177,6 +177,20 @@ static inline uint16_t mavlink_msg_point_of_interest_connection_encode(uint8_t s return mavlink_msg_point_of_interest_connection_pack(system_id, component_id, msg, point_of_interest_connection->type, point_of_interest_connection->color, point_of_interest_connection->coordinate_system, point_of_interest_connection->timeout, point_of_interest_connection->xp1, point_of_interest_connection->yp1, point_of_interest_connection->zp1, point_of_interest_connection->xp2, point_of_interest_connection->yp2, point_of_interest_connection->zp2, point_of_interest_connection->name); } +/** + * @brief Encode a point_of_interest_connection struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param point_of_interest_connection C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_point_of_interest_connection_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_point_of_interest_connection_t* point_of_interest_connection) +{ + return mavlink_msg_point_of_interest_connection_pack_chan(system_id, component_id, chan, msg, point_of_interest_connection->type, point_of_interest_connection->color, point_of_interest_connection->coordinate_system, point_of_interest_connection->timeout, point_of_interest_connection->xp1, point_of_interest_connection->yp1, point_of_interest_connection->zp1, point_of_interest_connection->xp2, point_of_interest_connection->yp2, point_of_interest_connection->zp2, point_of_interest_connection->name); +} + /** * @brief Send a point_of_interest_connection message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_position_control_setpoint.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_position_control_setpoint.h index 6c86be3ab5688052f00809564b64fc0fc7e7fb8b..6f4ca510ae038fe424377168e4cce243ba8d1948 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_position_control_setpoint.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_position_control_setpoint.h @@ -79,7 +79,7 @@ static inline uint16_t mavlink_msg_position_control_setpoint_pack(uint8_t system * @brief Pack a position_control_setpoint message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param id ID of waypoint, 0 for plain position * @param x x position @@ -121,7 +121,7 @@ static inline uint16_t mavlink_msg_position_control_setpoint_pack_chan(uint8_t s } /** - * @brief Encode a position_control_setpoint struct into a message + * @brief Encode a position_control_setpoint struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -133,6 +133,20 @@ static inline uint16_t mavlink_msg_position_control_setpoint_encode(uint8_t syst return mavlink_msg_position_control_setpoint_pack(system_id, component_id, msg, position_control_setpoint->id, position_control_setpoint->x, position_control_setpoint->y, position_control_setpoint->z, position_control_setpoint->yaw); } +/** + * @brief Encode a position_control_setpoint struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param position_control_setpoint C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_position_control_setpoint_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_position_control_setpoint_t* position_control_setpoint) +{ + return mavlink_msg_position_control_setpoint_pack_chan(system_id, component_id, chan, msg, position_control_setpoint->id, position_control_setpoint->x, position_control_setpoint->y, position_control_setpoint->z, position_control_setpoint->yaw); +} + /** * @brief Send a position_control_setpoint message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_raw_aux.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_raw_aux.h index 0a0dbdb37891e685a30c8e683f888b700a87ab12..08cedbb4b230e106ff17c13d650aa21a92766981 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_raw_aux.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_raw_aux.h @@ -89,7 +89,7 @@ static inline uint16_t mavlink_msg_raw_aux_pack(uint8_t system_id, uint8_t compo * @brief Pack a raw_aux message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param adc1 ADC1 (J405 ADC3, LPC2148 AD0.6) * @param adc2 ADC2 (J405 ADC5, LPC2148 AD0.2) @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_raw_aux_pack_chan(uint8_t system_id, uint8_t } /** - * @brief Encode a raw_aux struct into a message + * @brief Encode a raw_aux struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_raw_aux_encode(uint8_t system_id, uint8_t com return mavlink_msg_raw_aux_pack(system_id, component_id, msg, raw_aux->adc1, raw_aux->adc2, raw_aux->adc3, raw_aux->adc4, raw_aux->vbat, raw_aux->temp, raw_aux->baro); } +/** + * @brief Encode a raw_aux struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param raw_aux C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_raw_aux_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_raw_aux_t* raw_aux) +{ + return mavlink_msg_raw_aux_pack_chan(system_id, component_id, chan, msg, raw_aux->adc1, raw_aux->adc2, raw_aux->adc3, raw_aux->adc4, raw_aux->vbat, raw_aux->temp, raw_aux->baro); +} + /** * @brief Send a raw_aux message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_set_cam_shutter.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_set_cam_shutter.h index 7be6409119089fbc6d14d6e673f5ae42242ac3cb..b26d748c254585873fc794d4c709f57af168d353 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_set_cam_shutter.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_set_cam_shutter.h @@ -84,7 +84,7 @@ static inline uint16_t mavlink_msg_set_cam_shutter_pack(uint8_t system_id, uint8 * @brief Pack a set_cam_shutter message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param cam_no Camera id * @param cam_mode Camera mode: 0 = auto, 1 = manual @@ -129,7 +129,7 @@ static inline uint16_t mavlink_msg_set_cam_shutter_pack_chan(uint8_t system_id, } /** - * @brief Encode a set_cam_shutter struct into a message + * @brief Encode a set_cam_shutter struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -141,6 +141,20 @@ static inline uint16_t mavlink_msg_set_cam_shutter_encode(uint8_t system_id, uin return mavlink_msg_set_cam_shutter_pack(system_id, component_id, msg, set_cam_shutter->cam_no, set_cam_shutter->cam_mode, set_cam_shutter->trigger_pin, set_cam_shutter->interval, set_cam_shutter->exposure, set_cam_shutter->gain); } +/** + * @brief Encode a set_cam_shutter struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param set_cam_shutter C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_set_cam_shutter_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_cam_shutter_t* set_cam_shutter) +{ + return mavlink_msg_set_cam_shutter_pack_chan(system_id, component_id, chan, msg, set_cam_shutter->cam_no, set_cam_shutter->cam_mode, set_cam_shutter->trigger_pin, set_cam_shutter->interval, set_cam_shutter->exposure, set_cam_shutter->gain); +} + /** * @brief Send a set_cam_shutter message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_set_position_control_offset.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_set_position_control_offset.h index 25bff659edd0d31c7e7f464f88242cd23e85871c..f1f9e698f8797d15725170fe05c123b68a403e4a 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_set_position_control_offset.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_set_position_control_offset.h @@ -84,7 +84,7 @@ static inline uint16_t mavlink_msg_set_position_control_offset_pack(uint8_t syst * @brief Pack a set_position_control_offset message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID @@ -129,7 +129,7 @@ static inline uint16_t mavlink_msg_set_position_control_offset_pack_chan(uint8_t } /** - * @brief Encode a set_position_control_offset struct into a message + * @brief Encode a set_position_control_offset struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -141,6 +141,20 @@ static inline uint16_t mavlink_msg_set_position_control_offset_encode(uint8_t sy return mavlink_msg_set_position_control_offset_pack(system_id, component_id, msg, set_position_control_offset->target_system, set_position_control_offset->target_component, set_position_control_offset->x, set_position_control_offset->y, set_position_control_offset->z, set_position_control_offset->yaw); } +/** + * @brief Encode a set_position_control_offset struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param set_position_control_offset C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_set_position_control_offset_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_position_control_offset_t* set_position_control_offset) +{ + return mavlink_msg_set_position_control_offset_pack_chan(system_id, component_id, chan, msg, set_position_control_offset->target_system, set_position_control_offset->target_component, set_position_control_offset->x, set_position_control_offset->y, set_position_control_offset->z, set_position_control_offset->yaw); +} + /** * @brief Send a set_position_control_offset message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_watchdog_command.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_watchdog_command.h index 42678801869a730ad96bc990ae165f698fc68b52..9458087da98b84f23b7a67b1efcd897b09e370cd 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_watchdog_command.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_watchdog_command.h @@ -74,7 +74,7 @@ static inline uint16_t mavlink_msg_watchdog_command_pack(uint8_t system_id, uint * @brief Pack a watchdog_command message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target_system_id Target system ID * @param watchdog_id Watchdog ID @@ -113,7 +113,7 @@ static inline uint16_t mavlink_msg_watchdog_command_pack_chan(uint8_t system_id, } /** - * @brief Encode a watchdog_command struct into a message + * @brief Encode a watchdog_command struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -125,6 +125,20 @@ static inline uint16_t mavlink_msg_watchdog_command_encode(uint8_t system_id, ui return mavlink_msg_watchdog_command_pack(system_id, component_id, msg, watchdog_command->target_system_id, watchdog_command->watchdog_id, watchdog_command->process_id, watchdog_command->command_id); } +/** + * @brief Encode a watchdog_command struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param watchdog_command C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_watchdog_command_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_watchdog_command_t* watchdog_command) +{ + return mavlink_msg_watchdog_command_pack_chan(system_id, component_id, chan, msg, watchdog_command->target_system_id, watchdog_command->watchdog_id, watchdog_command->process_id, watchdog_command->command_id); +} + /** * @brief Send a watchdog_command message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_watchdog_heartbeat.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_watchdog_heartbeat.h index 49478999cecc0c6a5b8a460d5f05a3fdef4cbf76..3f4295ee5d84c14322b399620de1887d1eddbe6a 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_watchdog_heartbeat.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_watchdog_heartbeat.h @@ -64,7 +64,7 @@ static inline uint16_t mavlink_msg_watchdog_heartbeat_pack(uint8_t system_id, ui * @brief Pack a watchdog_heartbeat message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param watchdog_id Watchdog ID * @param process_count Number of processes @@ -97,7 +97,7 @@ static inline uint16_t mavlink_msg_watchdog_heartbeat_pack_chan(uint8_t system_i } /** - * @brief Encode a watchdog_heartbeat struct into a message + * @brief Encode a watchdog_heartbeat struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -109,6 +109,20 @@ static inline uint16_t mavlink_msg_watchdog_heartbeat_encode(uint8_t system_id, return mavlink_msg_watchdog_heartbeat_pack(system_id, component_id, msg, watchdog_heartbeat->watchdog_id, watchdog_heartbeat->process_count); } +/** + * @brief Encode a watchdog_heartbeat struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param watchdog_heartbeat C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_watchdog_heartbeat_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_watchdog_heartbeat_t* watchdog_heartbeat) +{ + return mavlink_msg_watchdog_heartbeat_pack_chan(system_id, component_id, chan, msg, watchdog_heartbeat->watchdog_id, watchdog_heartbeat->process_count); +} + /** * @brief Send a watchdog_heartbeat message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_watchdog_process_info.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_watchdog_process_info.h index d706ef85e1daf285bf7fddc8283e7d0f6be43d9a..55853cdde4494070724f83da43cf43fb4a4e54db 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_watchdog_process_info.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_watchdog_process_info.h @@ -78,7 +78,7 @@ static inline uint16_t mavlink_msg_watchdog_process_info_pack(uint8_t system_id, * @brief Pack a watchdog_process_info message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param watchdog_id Watchdog ID * @param process_id Process ID @@ -118,7 +118,7 @@ static inline uint16_t mavlink_msg_watchdog_process_info_pack_chan(uint8_t syste } /** - * @brief Encode a watchdog_process_info struct into a message + * @brief Encode a watchdog_process_info struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -130,6 +130,20 @@ static inline uint16_t mavlink_msg_watchdog_process_info_encode(uint8_t system_i return mavlink_msg_watchdog_process_info_pack(system_id, component_id, msg, watchdog_process_info->watchdog_id, watchdog_process_info->process_id, watchdog_process_info->name, watchdog_process_info->arguments, watchdog_process_info->timeout); } +/** + * @brief Encode a watchdog_process_info struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param watchdog_process_info C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_watchdog_process_info_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_watchdog_process_info_t* watchdog_process_info) +{ + return mavlink_msg_watchdog_process_info_pack_chan(system_id, component_id, chan, msg, watchdog_process_info->watchdog_id, watchdog_process_info->process_id, watchdog_process_info->name, watchdog_process_info->arguments, watchdog_process_info->timeout); +} + /** * @brief Send a watchdog_process_info message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_watchdog_process_status.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_watchdog_process_status.h index b1bbaaae7b181b05b0819d05bca2563092dd2ba9..a0410d803e55973386e46aaf6639c76529c4dc53 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_watchdog_process_status.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/mavlink_msg_watchdog_process_status.h @@ -84,7 +84,7 @@ static inline uint16_t mavlink_msg_watchdog_process_status_pack(uint8_t system_i * @brief Pack a watchdog_process_status message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param watchdog_id Watchdog ID * @param process_id Process ID @@ -129,7 +129,7 @@ static inline uint16_t mavlink_msg_watchdog_process_status_pack_chan(uint8_t sys } /** - * @brief Encode a watchdog_process_status struct into a message + * @brief Encode a watchdog_process_status struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -141,6 +141,20 @@ static inline uint16_t mavlink_msg_watchdog_process_status_encode(uint8_t system return mavlink_msg_watchdog_process_status_pack(system_id, component_id, msg, watchdog_process_status->watchdog_id, watchdog_process_status->process_id, watchdog_process_status->state, watchdog_process_status->muted, watchdog_process_status->pid, watchdog_process_status->crashes); } +/** + * @brief Encode a watchdog_process_status struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param watchdog_process_status C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_watchdog_process_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_watchdog_process_status_t* watchdog_process_status) +{ + return mavlink_msg_watchdog_process_status_pack_chan(system_id, component_id, chan, msg, watchdog_process_status->watchdog_id, watchdog_process_status->process_id, watchdog_process_status->state, watchdog_process_status->muted, watchdog_process_status->pid, watchdog_process_status->crashes); +} + /** * @brief Send a watchdog_process_status message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/pixhawk.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/pixhawk.h index a2d0d0e14e77cd4337287f4c3387b073fbfccd78..3fc9e6477383ea6571be29b457edb717e44a6d83 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/pixhawk.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/pixhawk.h @@ -72,6 +72,7 @@ enum MAV_CMD MAV_CMD_DO_SET_SERVO=183, /* Set a servo to a desired PWM value. |Servo number| PWM (microseconds, 1000 to 2000 typical)| Empty| Empty| Empty| Empty| Empty| */ MAV_CMD_DO_REPEAT_SERVO=184, /* Cycle a between its nominal setting and a desired PWM for a desired number of cycles with a desired period. |Servo number| PWM (microseconds, 1000 to 2000 typical)| Cycle count| Cycle time (seconds)| Empty| Empty| Empty| */ MAV_CMD_DO_CONTROL_VIDEO=200, /* Control onboard camera system. |Camera ID (-1 for all)| Transmission: 0: disabled, 1: enabled compressed, 2: enabled raw| Transmission mode: 0: video stream, >0: single images every n seconds (decimal)| Recording: 0: disabled, 1: enabled compressed, 2: enabled raw| Empty| Empty| Empty| */ + MAV_CMD_DO_SET_ROI=201, /* Sets the region of interest (ROI) for a sensor set or the vehicle itself. This can then be used by the vehicles control system to control the vehicle attitude and the attitude of various sensors such as cameras. |Region of intereset mode. (see MAV_ROI enum)| MISSION index/ target ID. (see MAV_ROI enum)| ROI index (allows a vehicle to manage multiple ROI's)| Empty| x the location of the fixed ROI (see MAV_FRAME)| y| z| */ MAV_CMD_DO_LAST=240, /* NOP - This command is only used to mark the upper limit of the DO commands in the enumeration |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ MAV_CMD_PREFLIGHT_CALIBRATION=241, /* Trigger calibration. This command will be only accepted if in pre-flight mode. |Gyro calibration: 0: no, 1: yes| Magnetometer calibration: 0: no, 1: yes| Ground pressure: 0: no, 1: yes| Radio calibration: 0: no, 1: yes| Accelerometer calibration: 0: no, 1: yes| Empty| Empty| */ MAV_CMD_PREFLIGHT_SET_SENSOR_OFFSETS=242, /* Set sensor offsets. This command will be only accepted if in pre-flight mode. |Sensor to adjust the offsets for: 0: gyros, 1: accelerometer, 2: magnetometer, 3: barometer, 4: optical flow| X axis offset (or generic dimension 1), in the sensor's raw units| Y axis offset (or generic dimension 2), in the sensor's raw units| Z axis offset (or generic dimension 3), in the sensor's raw units| Generic dimension 4, in the sensor's raw units| Generic dimension 5, in the sensor's raw units| Generic dimension 6, in the sensor's raw units| */ @@ -80,7 +81,8 @@ enum MAV_CMD MAV_CMD_OVERRIDE_GOTO=252, /* Hold / continue the current action |MAV_GOTO_DO_HOLD: hold MAV_GOTO_DO_CONTINUE: continue with next item in mission plan| MAV_GOTO_HOLD_AT_CURRENT_POSITION: Hold at current position MAV_GOTO_HOLD_AT_SPECIFIED_POSITION: hold at specified position| MAV_FRAME coordinate frame of hold point| Desired yaw angle in degrees| Latitude / X position| Longitude / Y position| Altitude / Z position| */ MAV_CMD_MISSION_START=300, /* start running a mission |first_item: the first mission item to run| last_item: the last mission item to run (after this item is run, the mission ends)| */ MAV_CMD_COMPONENT_ARM_DISARM=400, /* Arms / Disarms a component |1 to arm, 0 to disarm| */ - MAV_CMD_ENUM_END=401, /* | */ + MAV_CMD_START_RX_PAIR=500, /* Starts receiver pairing |0:Spektrum| 0:Spektrum DSM2, 1:Spektrum DSMX| */ + MAV_CMD_ENUM_END=501, /* | */ MAV_CMD_DO_START_SEARCH=10001, /* Starts a search |1 to arm, 0 to disarm| */ MAV_CMD_DO_FINISH_SEARCH=10002, /* Starts a search |1 to arm, 0 to disarm| */ MAV_CMD_NAV_SWEEP=10003, /* Starts a search |1 to arm, 0 to disarm| */ diff --git a/libs/mavlink/include/mavlink/v1.0/pixhawk/version.h b/libs/mavlink/include/mavlink/v1.0/pixhawk/version.h index 61fe6e930d1de6a87734188ee2a22797904d4171..07831a42562384d4a4e93e1446dc10b97c463f0d 100644 --- a/libs/mavlink/include/mavlink/v1.0/pixhawk/version.h +++ b/libs/mavlink/include/mavlink/v1.0/pixhawk/version.h @@ -5,7 +5,7 @@ #ifndef MAVLINK_VERSION_H #define MAVLINK_VERSION_H -#define MAVLINK_BUILD_DATE "Thu Jul 4 13:12:05 2013" +#define MAVLINK_BUILD_DATE "Tue Sep 10 23:49:13 2013" #define MAVLINK_WIRE_PROTOCOL_VERSION "1.0" #define MAVLINK_MAX_DIALECT_PAYLOAD_SIZE 255 diff --git a/libs/mavlink/include/mavlink/v1.0/protocol.h b/libs/mavlink/include/mavlink/v1.0/protocol.h index ddacae59c4cbefe6381440942e161ff532a37133..86e7ff588b519cf2ff88ffed9d97f342e19213cc 100644 --- a/libs/mavlink/include/mavlink/v1.0/protocol.h +++ b/libs/mavlink/include/mavlink/v1.0/protocol.h @@ -162,7 +162,7 @@ static inline void byte_copy_8(char *dst, const char *src) /* like memcpy(), but if src is NULL, do a memset to zero */ -static void mav_array_memcpy(void *dest, const void *src, size_t n) +static inline void mav_array_memcpy(void *dest, const void *src, size_t n) { if (src == NULL) { memset(dest, 0, n); diff --git a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_cmd_airspeed_ack.h b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_cmd_airspeed_ack.h index 5cdd584561f87a0f77e3e012a1b603164ec8cda4..73e9d75dbc8cf4da2cb669bcf1bb546241b89d03 100644 --- a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_cmd_airspeed_ack.h +++ b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_cmd_airspeed_ack.h @@ -72,7 +72,7 @@ static inline uint16_t mavlink_msg_cmd_airspeed_ack_pack(uint8_t system_id, uint * @brief Pack a cmd_airspeed_ack message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param spCmd @@ -109,7 +109,7 @@ static inline uint16_t mavlink_msg_cmd_airspeed_ack_pack_chan(uint8_t system_id, } /** - * @brief Encode a cmd_airspeed_ack struct into a message + * @brief Encode a cmd_airspeed_ack struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -121,6 +121,20 @@ static inline uint16_t mavlink_msg_cmd_airspeed_ack_encode(uint8_t system_id, ui return mavlink_msg_cmd_airspeed_ack_pack(system_id, component_id, msg, cmd_airspeed_ack->spCmd, cmd_airspeed_ack->ack); } +/** + * @brief Encode a cmd_airspeed_ack struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param cmd_airspeed_ack C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_cmd_airspeed_ack_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_cmd_airspeed_ack_t* cmd_airspeed_ack) +{ + return mavlink_msg_cmd_airspeed_ack_pack_chan(system_id, component_id, chan, msg, cmd_airspeed_ack->spCmd, cmd_airspeed_ack->ack); +} + /** * @brief Send a cmd_airspeed_ack message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_cmd_airspeed_chng.h b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_cmd_airspeed_chng.h index 2a4894fe72a5b88ba421ee49a918778c9499ea72..b6b567f993292a6e657e1ff6d96bb6305823cdf9 100644 --- a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_cmd_airspeed_chng.h +++ b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_cmd_airspeed_chng.h @@ -72,7 +72,7 @@ static inline uint16_t mavlink_msg_cmd_airspeed_chng_pack(uint8_t system_id, uin * @brief Pack a cmd_airspeed_chng message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param target @@ -109,7 +109,7 @@ static inline uint16_t mavlink_msg_cmd_airspeed_chng_pack_chan(uint8_t system_id } /** - * @brief Encode a cmd_airspeed_chng struct into a message + * @brief Encode a cmd_airspeed_chng struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -121,6 +121,20 @@ static inline uint16_t mavlink_msg_cmd_airspeed_chng_encode(uint8_t system_id, u return mavlink_msg_cmd_airspeed_chng_pack(system_id, component_id, msg, cmd_airspeed_chng->target, cmd_airspeed_chng->spCmd); } +/** + * @brief Encode a cmd_airspeed_chng struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param cmd_airspeed_chng C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_cmd_airspeed_chng_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_cmd_airspeed_chng_t* cmd_airspeed_chng) +{ + return mavlink_msg_cmd_airspeed_chng_pack_chan(system_id, component_id, chan, msg, cmd_airspeed_chng->target, cmd_airspeed_chng->spCmd); +} + /** * @brief Send a cmd_airspeed_chng message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_filt_rot_vel.h b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_filt_rot_vel.h index d600e917495852473f2fb197e1493af1dfd3d923..642f7aab931bdf0b8bac6a568a0ca38339359b65 100644 --- a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_filt_rot_vel.h +++ b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_filt_rot_vel.h @@ -63,7 +63,7 @@ static inline uint16_t mavlink_msg_filt_rot_vel_pack(uint8_t system_id, uint8_t * @brief Pack a filt_rot_vel message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param rotVel @@ -95,7 +95,7 @@ static inline uint16_t mavlink_msg_filt_rot_vel_pack_chan(uint8_t system_id, uin } /** - * @brief Encode a filt_rot_vel struct into a message + * @brief Encode a filt_rot_vel struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -107,6 +107,20 @@ static inline uint16_t mavlink_msg_filt_rot_vel_encode(uint8_t system_id, uint8_ return mavlink_msg_filt_rot_vel_pack(system_id, component_id, msg, filt_rot_vel->rotVel); } +/** + * @brief Encode a filt_rot_vel struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param filt_rot_vel C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_filt_rot_vel_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_filt_rot_vel_t* filt_rot_vel) +{ + return mavlink_msg_filt_rot_vel_pack_chan(system_id, component_id, chan, msg, filt_rot_vel->rotVel); +} + /** * @brief Send a filt_rot_vel message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_llc_out.h b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_llc_out.h index cb1c86f436e9d5ba000383b6f266a8f7e4e9a82d..0f8369881a9bdbf86f7db7cee94e7bd3a151b168 100644 --- a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_llc_out.h +++ b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_llc_out.h @@ -73,7 +73,7 @@ static inline uint16_t mavlink_msg_llc_out_pack(uint8_t system_id, uint8_t compo * @brief Pack a llc_out message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param servoOut @@ -110,7 +110,7 @@ static inline uint16_t mavlink_msg_llc_out_pack_chan(uint8_t system_id, uint8_t } /** - * @brief Encode a llc_out struct into a message + * @brief Encode a llc_out struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -122,6 +122,20 @@ static inline uint16_t mavlink_msg_llc_out_encode(uint8_t system_id, uint8_t com return mavlink_msg_llc_out_pack(system_id, component_id, msg, llc_out->servoOut, llc_out->MotorOut); } +/** + * @brief Encode a llc_out struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param llc_out C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_llc_out_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_llc_out_t* llc_out) +{ + return mavlink_msg_llc_out_pack_chan(system_id, component_id, chan, msg, llc_out->servoOut, llc_out->MotorOut); +} + /** * @brief Send a llc_out message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_air_temp.h b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_air_temp.h index b6bd0d9e52ac0a55a9c748b65175df7f380e6aef..5d9382326293c35246b3cdd87710aa41b5921ea5 100644 --- a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_air_temp.h +++ b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_air_temp.h @@ -63,7 +63,7 @@ static inline uint16_t mavlink_msg_obs_air_temp_pack(uint8_t system_id, uint8_t * @brief Pack a obs_air_temp message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param airT @@ -95,7 +95,7 @@ static inline uint16_t mavlink_msg_obs_air_temp_pack_chan(uint8_t system_id, uin } /** - * @brief Encode a obs_air_temp struct into a message + * @brief Encode a obs_air_temp struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -107,6 +107,20 @@ static inline uint16_t mavlink_msg_obs_air_temp_encode(uint8_t system_id, uint8_ return mavlink_msg_obs_air_temp_pack(system_id, component_id, msg, obs_air_temp->airT); } +/** + * @brief Encode a obs_air_temp struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param obs_air_temp C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_obs_air_temp_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_obs_air_temp_t* obs_air_temp) +{ + return mavlink_msg_obs_air_temp_pack_chan(system_id, component_id, chan, msg, obs_air_temp->airT); +} + /** * @brief Send a obs_air_temp message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_air_velocity.h b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_air_velocity.h index 87a65cfa0624a40ffc41996caa626f484d53ca91..35d813ca150acf01d2ad1cd33464f1243a9e60e2 100644 --- a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_air_velocity.h +++ b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_air_velocity.h @@ -81,7 +81,7 @@ static inline uint16_t mavlink_msg_obs_air_velocity_pack(uint8_t system_id, uint * @brief Pack a obs_air_velocity message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param magnitude @@ -123,7 +123,7 @@ static inline uint16_t mavlink_msg_obs_air_velocity_pack_chan(uint8_t system_id, } /** - * @brief Encode a obs_air_velocity struct into a message + * @brief Encode a obs_air_velocity struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -135,6 +135,20 @@ static inline uint16_t mavlink_msg_obs_air_velocity_encode(uint8_t system_id, ui return mavlink_msg_obs_air_velocity_pack(system_id, component_id, msg, obs_air_velocity->magnitude, obs_air_velocity->aoa, obs_air_velocity->slip); } +/** + * @brief Encode a obs_air_velocity struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param obs_air_velocity C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_obs_air_velocity_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_obs_air_velocity_t* obs_air_velocity) +{ + return mavlink_msg_obs_air_velocity_pack_chan(system_id, component_id, chan, msg, obs_air_velocity->magnitude, obs_air_velocity->aoa, obs_air_velocity->slip); +} + /** * @brief Send a obs_air_velocity message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_attitude.h b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_attitude.h index 602eafc80b0f5d94920076d13f734570f7633a11..9c80cd66eb926ee8364877da46f1916aa3014ab3 100644 --- a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_attitude.h +++ b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_attitude.h @@ -63,7 +63,7 @@ static inline uint16_t mavlink_msg_obs_attitude_pack(uint8_t system_id, uint8_t * @brief Pack a obs_attitude message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param quat @@ -95,7 +95,7 @@ static inline uint16_t mavlink_msg_obs_attitude_pack_chan(uint8_t system_id, uin } /** - * @brief Encode a obs_attitude struct into a message + * @brief Encode a obs_attitude struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -107,6 +107,20 @@ static inline uint16_t mavlink_msg_obs_attitude_encode(uint8_t system_id, uint8_ return mavlink_msg_obs_attitude_pack(system_id, component_id, msg, obs_attitude->quat); } +/** + * @brief Encode a obs_attitude struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param obs_attitude C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_obs_attitude_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_obs_attitude_t* obs_attitude) +{ + return mavlink_msg_obs_attitude_pack_chan(system_id, component_id, chan, msg, obs_attitude->quat); +} + /** * @brief Send a obs_attitude message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_bias.h b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_bias.h index 3ab855ba817c46ca4872094b0baff24058dd6c92..24dd43b5799b165b0b9fbf7ace8f40263ede27f1 100644 --- a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_bias.h +++ b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_bias.h @@ -73,7 +73,7 @@ static inline uint16_t mavlink_msg_obs_bias_pack(uint8_t system_id, uint8_t comp * @brief Pack a obs_bias message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param accBias @@ -110,7 +110,7 @@ static inline uint16_t mavlink_msg_obs_bias_pack_chan(uint8_t system_id, uint8_t } /** - * @brief Encode a obs_bias struct into a message + * @brief Encode a obs_bias struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -122,6 +122,20 @@ static inline uint16_t mavlink_msg_obs_bias_encode(uint8_t system_id, uint8_t co return mavlink_msg_obs_bias_pack(system_id, component_id, msg, obs_bias->accBias, obs_bias->gyroBias); } +/** + * @brief Encode a obs_bias struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param obs_bias C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_obs_bias_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_obs_bias_t* obs_bias) +{ + return mavlink_msg_obs_bias_pack_chan(system_id, component_id, chan, msg, obs_bias->accBias, obs_bias->gyroBias); +} + /** * @brief Send a obs_bias message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_position.h b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_position.h index ec494d51a2dff9fd81a2848c99dcac0e83060775..cfc2fe7e1047233b0083007752e7fab6e4805f7a 100644 --- a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_position.h +++ b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_position.h @@ -81,7 +81,7 @@ static inline uint16_t mavlink_msg_obs_position_pack(uint8_t system_id, uint8_t * @brief Pack a obs_position message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param lon @@ -123,7 +123,7 @@ static inline uint16_t mavlink_msg_obs_position_pack_chan(uint8_t system_id, uin } /** - * @brief Encode a obs_position struct into a message + * @brief Encode a obs_position struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -135,6 +135,20 @@ static inline uint16_t mavlink_msg_obs_position_encode(uint8_t system_id, uint8_ return mavlink_msg_obs_position_pack(system_id, component_id, msg, obs_position->lon, obs_position->lat, obs_position->alt); } +/** + * @brief Encode a obs_position struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param obs_position C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_obs_position_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_obs_position_t* obs_position) +{ + return mavlink_msg_obs_position_pack_chan(system_id, component_id, chan, msg, obs_position->lon, obs_position->lat, obs_position->alt); +} + /** * @brief Send a obs_position message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_qff.h b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_qff.h index e42b0261fa91d3af2387e30c8fb95fdc787e2169..24e272bf7a7df3157ed90d489d816978f089fda7 100644 --- a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_qff.h +++ b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_qff.h @@ -63,7 +63,7 @@ static inline uint16_t mavlink_msg_obs_qff_pack(uint8_t system_id, uint8_t compo * @brief Pack a obs_qff message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param qff @@ -95,7 +95,7 @@ static inline uint16_t mavlink_msg_obs_qff_pack_chan(uint8_t system_id, uint8_t } /** - * @brief Encode a obs_qff struct into a message + * @brief Encode a obs_qff struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -107,6 +107,20 @@ static inline uint16_t mavlink_msg_obs_qff_encode(uint8_t system_id, uint8_t com return mavlink_msg_obs_qff_pack(system_id, component_id, msg, obs_qff->qff); } +/** + * @brief Encode a obs_qff struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param obs_qff C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_obs_qff_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_obs_qff_t* obs_qff) +{ + return mavlink_msg_obs_qff_pack_chan(system_id, component_id, chan, msg, obs_qff->qff); +} + /** * @brief Send a obs_qff message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_velocity.h b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_velocity.h index 2fa6e9111f50c00e0cf0c3ddb454df63deb6b3fc..6e3776632bb7451ca34ff08f97b95092d8fe5222 100644 --- a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_velocity.h +++ b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_velocity.h @@ -63,7 +63,7 @@ static inline uint16_t mavlink_msg_obs_velocity_pack(uint8_t system_id, uint8_t * @brief Pack a obs_velocity message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param vel @@ -95,7 +95,7 @@ static inline uint16_t mavlink_msg_obs_velocity_pack_chan(uint8_t system_id, uin } /** - * @brief Encode a obs_velocity struct into a message + * @brief Encode a obs_velocity struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -107,6 +107,20 @@ static inline uint16_t mavlink_msg_obs_velocity_encode(uint8_t system_id, uint8_ return mavlink_msg_obs_velocity_pack(system_id, component_id, msg, obs_velocity->vel); } +/** + * @brief Encode a obs_velocity struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param obs_velocity C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_obs_velocity_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_obs_velocity_t* obs_velocity) +{ + return mavlink_msg_obs_velocity_pack_chan(system_id, component_id, chan, msg, obs_velocity->vel); +} + /** * @brief Send a obs_velocity message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_wind.h b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_wind.h index bc9f6e4eff8074d16e349dee1b83210f0974ec02..55f7cb2ae1fe7a783c068ff377ac1434815b11be 100644 --- a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_wind.h +++ b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_obs_wind.h @@ -63,7 +63,7 @@ static inline uint16_t mavlink_msg_obs_wind_pack(uint8_t system_id, uint8_t comp * @brief Pack a obs_wind message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param wind @@ -95,7 +95,7 @@ static inline uint16_t mavlink_msg_obs_wind_pack_chan(uint8_t system_id, uint8_t } /** - * @brief Encode a obs_wind struct into a message + * @brief Encode a obs_wind struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -107,6 +107,20 @@ static inline uint16_t mavlink_msg_obs_wind_encode(uint8_t system_id, uint8_t co return mavlink_msg_obs_wind_pack(system_id, component_id, msg, obs_wind->wind); } +/** + * @brief Encode a obs_wind struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param obs_wind C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_obs_wind_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_obs_wind_t* obs_wind) +{ + return mavlink_msg_obs_wind_pack_chan(system_id, component_id, chan, msg, obs_wind->wind); +} + /** * @brief Send a obs_wind message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_pm_elec.h b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_pm_elec.h index 0799af07f833a37afb69ad1785ac578765ab9e68..e0963ece79953a8b487b6f5af09e200405348065 100644 --- a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_pm_elec.h +++ b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_pm_elec.h @@ -79,7 +79,7 @@ static inline uint16_t mavlink_msg_pm_elec_pack(uint8_t system_id, uint8_t compo * @brief Pack a pm_elec message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param PwCons @@ -119,7 +119,7 @@ static inline uint16_t mavlink_msg_pm_elec_pack_chan(uint8_t system_id, uint8_t } /** - * @brief Encode a pm_elec struct into a message + * @brief Encode a pm_elec struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -131,6 +131,20 @@ static inline uint16_t mavlink_msg_pm_elec_encode(uint8_t system_id, uint8_t com return mavlink_msg_pm_elec_pack(system_id, component_id, msg, pm_elec->PwCons, pm_elec->BatStat, pm_elec->PwGen); } +/** + * @brief Encode a pm_elec struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param pm_elec C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_pm_elec_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_pm_elec_t* pm_elec) +{ + return mavlink_msg_pm_elec_pack_chan(system_id, component_id, chan, msg, pm_elec->PwCons, pm_elec->BatStat, pm_elec->PwGen); +} + /** * @brief Send a pm_elec message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_sys_stat.h b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_sys_stat.h index e5e483a73afd4dec1810a677cb75d811dfaaac7e..94f3e58bb9300a29119b2930e1d32b6f19acdf53 100644 --- a/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_sys_stat.h +++ b/libs/mavlink/include/mavlink/v1.0/sensesoar/mavlink_msg_sys_stat.h @@ -90,7 +90,7 @@ static inline uint16_t mavlink_msg_sys_stat_pack(uint8_t system_id, uint8_t comp * @brief Pack a sys_stat message on a channel * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) - * @param chan The MAVLink channel this message was sent over + * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param gps @@ -137,7 +137,7 @@ static inline uint16_t mavlink_msg_sys_stat_pack_chan(uint8_t system_id, uint8_t } /** - * @brief Encode a sys_stat struct into a message + * @brief Encode a sys_stat struct * * @param system_id ID of this system * @param component_id ID of this component (e.g. 200 for IMU) @@ -149,6 +149,20 @@ static inline uint16_t mavlink_msg_sys_stat_encode(uint8_t system_id, uint8_t co return mavlink_msg_sys_stat_pack(system_id, component_id, msg, sys_stat->gps, sys_stat->act, sys_stat->mod, sys_stat->commRssi); } +/** + * @brief Encode a sys_stat struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param sys_stat C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_sys_stat_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_sys_stat_t* sys_stat) +{ + return mavlink_msg_sys_stat_pack_chan(system_id, component_id, chan, msg, sys_stat->gps, sys_stat->act, sys_stat->mod, sys_stat->commRssi); +} + /** * @brief Send a sys_stat message * @param chan MAVLink channel to send the message diff --git a/libs/mavlink/include/mavlink/v1.0/sensesoar/version.h b/libs/mavlink/include/mavlink/v1.0/sensesoar/version.h index 4633e6eb5c848faf869970b2320f1ac9e953c068..ab3f47b9df0c3204df345f7d97f1d231423d32dc 100644 --- a/libs/mavlink/include/mavlink/v1.0/sensesoar/version.h +++ b/libs/mavlink/include/mavlink/v1.0/sensesoar/version.h @@ -5,7 +5,7 @@ #ifndef MAVLINK_VERSION_H #define MAVLINK_VERSION_H -#define MAVLINK_BUILD_DATE "Thu Jul 4 13:12:22 2013" +#define MAVLINK_BUILD_DATE "Tue Sep 10 23:50:02 2013" #define MAVLINK_WIRE_PROTOCOL_VERSION "1.0" #define MAVLINK_MAX_DIALECT_PAYLOAD_SIZE 254 diff --git a/libs/opmapcontrol/src/internals/copyrightstrings.h b/libs/opmapcontrol/src/internals/copyrightstrings.h index 42cebdd3d3906a9f54ebb83774662e710e5fe426..1334d27bebce172f7594279416a6d2855264ca65 100644 --- a/libs/opmapcontrol/src/internals/copyrightstrings.h +++ b/libs/opmapcontrol/src/internals/copyrightstrings.h @@ -31,11 +31,11 @@ #include namespace internals { -static const QString googleCopyright = QString("©%1 Google - Map data ©%1 Tele Atlas, Imagery ©%1 TerraMetrics").arg(QDate::currentDate().year()); -static const QString openStreetMapCopyright = QString("© OpenStreetMap - Map data ©%1 OpenStreetMap").arg(QDate::currentDate().year()); -static const QString yahooMapCopyright = QString("© Yahoo! Inc. - Map data & Imagery ©%1 NAVTEQ").arg(QDate::currentDate().year()); -static const QString virtualEarthCopyright = QString("©%1 Microsoft Corporation, ©%1 NAVTEQ, ©%1 Image courtesy of NASA").arg(QDate::currentDate().year()); -static const QString arcGisCopyright = QString("©%1 ESRI - Map data ©%1 ArcGIS").arg(QDate::currentDate().year()); +static const QString googleCopyright = QString("(c)%1 Google - Map data (c)%1 Tele Atlas, Imagery (c)%1 TerraMetrics").arg(QDate::currentDate().year()); +static const QString openStreetMapCopyright = QString("(c) OpenStreetMap - Map data (c)%1 OpenStreetMap").arg(QDate::currentDate().year()); +static const QString yahooMapCopyright = QString("(c) Yahoo! Inc. - Map data & Imagery (c)%1 NAVTEQ").arg(QDate::currentDate().year()); +static const QString virtualEarthCopyright = QString("(c)%1 Microsoft Corporation, (c)%1 NAVTEQ, (c)%1 Image courtesy of NASA").arg(QDate::currentDate().year()); +static const QString arcGisCopyright = QString("(c)%1 ESRI - Map data (c)%1 ArcGIS").arg(QDate::currentDate().year()); } #endif // COPYRIGHTSTRINGS_H diff --git a/libs/serialport/doc/images/blockingmaster-example.png b/libs/serialport/doc/images/blockingmaster-example.png new file mode 100644 index 0000000000000000000000000000000000000000..44aa5ecfa894a78074ce7e89a331d0006be6d834 Binary files /dev/null and b/libs/serialport/doc/images/blockingmaster-example.png differ diff --git a/libs/serialport/doc/images/blockingslave-example.png b/libs/serialport/doc/images/blockingslave-example.png new file mode 100644 index 0000000000000000000000000000000000000000..44aa39394d3dbfbf8a5d519a428d60230b188805 Binary files /dev/null and b/libs/serialport/doc/images/blockingslave-example.png differ diff --git a/libs/serialport/doc/images/cenumerator-example.png b/libs/serialport/doc/images/cenumerator-example.png new file mode 100644 index 0000000000000000000000000000000000000000..03792e71dbe3c6f291c4c6c0533f7e30286dccb6 Binary files /dev/null and b/libs/serialport/doc/images/cenumerator-example.png differ diff --git a/libs/serialport/doc/images/enumerator-example.png b/libs/serialport/doc/images/enumerator-example.png new file mode 100644 index 0000000000000000000000000000000000000000..c4add83896d3b144c99945384060b0f22bd962e8 Binary files /dev/null and b/libs/serialport/doc/images/enumerator-example.png differ diff --git a/libs/serialport/doc/images/terminal-example.png b/libs/serialport/doc/images/terminal-example.png new file mode 100644 index 0000000000000000000000000000000000000000..28aa366709c8e54968f54a75d4c3569e98c0cdc5 Binary files /dev/null and b/libs/serialport/doc/images/terminal-example.png differ diff --git a/libs/serialport/doc/qtserialport.qdocconf b/libs/serialport/doc/qtserialport.qdocconf new file mode 100644 index 0000000000000000000000000000000000000000..f095c2f18b0456edc4461bb19110a69964d3e03b --- /dev/null +++ b/libs/serialport/doc/qtserialport.qdocconf @@ -0,0 +1,37 @@ +include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) + +project = QtSerialPort +description = Qt Serial Port Reference Documentation +url = http://qt-project.org/doc/qt-$QT_VER/qtserialport +version = $QT_VERSION + +qhp.projects = QtSerialPort + +qhp.QtSerialPort.file = qtserialport.qhp +qhp.QtSerialPort.namespace = org.qt-project.qtserialport.$QT_VERSION_TAG +qhp.QtSerialPort.virtualFolder = qtserialport +qhp.QtSerialPort.indexTitle = Qt Serial Port +qhp.QtSerialPort.indexRoot = + +qhp.QtSerialPort.filterAttributes = qtserialport $QT_VERSION qtrefdoc +qhp.QtSerialPort.customFilters.Qt.name = QtSerialPort $QT_VERSION +qhp.QtSerialPort.customFilters.Qt.filterAttributes = qtserialport $QT_VERSION + +qhp.QtSerialPort.subprojects = classes examples + +qhp.QtSerialPort.subprojects.classes.title = C++ Classes +qhp.QtSerialPort.subprojects.classes.indexTitle = Qt Serial Port C++ Classes +qhp.QtSerialPort.subprojects.classes.selectors = class fake:headerfile +qhp.QtSerialPort.subprojects.classes.sortPages = true + +qhp.QtSerialPort.subprojects.examples.title = Examples +qhp.QtSerialPort.subprojects.examples.indexTitle = Qt Serial Port Examples +qhp.QtSerialPort.subprojects.examples.selectors = fake:example +qhp.QtSerialPort.subprojects.examples.sortPages = true + +headerdirs += .. +sourcedirs += .. +exampledirs += ../../../examples/serialport +imagedirs += images + +depends += qtcore qtdoc diff --git a/libs/serialport/doc/src/index.qdoc b/libs/serialport/doc/src/index.qdoc new file mode 100644 index 0000000000000000000000000000000000000000..ae5faebc964a4f025729be4039ed3e8de440797c --- /dev/null +++ b/libs/serialport/doc/src/index.qdoc @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2011 - 2012 Denis Shienkov +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page qtserialport-index.html + \title Qt Serial Port + \brief Provides API to make the serial programming simple and portable. + + Qt Serial Port provides the basic functionality, which includes + configuring, I/O operations, get and set control signals of the + RS-232 pinouts. + + The following are not supported by this module: + \list + \li Terminal features such as echo, control CR/LF, and so on. + \li Text mode. + \li Configuring timeouts and delays while reading. + \li Tracking and notification when the state of RS-232 pinout signals change. + \endlist + + To use these classes in your application, use the following include + statement: + + \code + #include + \endcode + + To link against the module, add this line to your \l qmake \c + .pro file: + + \code + QT += serialport + \endcode + + \section1 Related information + \list + \li \l{Qt Serial Port C++ Classes}{C++ Classes} + \li \l{Qt Serial Port Examples}{Examples} + \endlist + +*/ diff --git a/libs/serialport/doc/src/qtserialport-module.qdoc b/libs/serialport/doc/src/qtserialport-module.qdoc new file mode 100644 index 0000000000000000000000000000000000000000..b0fc506e52d3988695eb65b19f8bfcde4abe5200 --- /dev/null +++ b/libs/serialport/doc/src/qtserialport-module.qdoc @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2011 - 2012 Denis Shienkov +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \module QtSerialPort + \title Qt Serial Port C++ Classes + \brief List of C++ classes that enable access to a serial port. + + To use these classes in your application, use the following include + statement: + + \code + #include + \endcode + + To link against the module, add this line to your \l qmake \c + .pro file: + + \code + QT += serialport + \endcode +*/ diff --git a/libs/serialport/doc/style/style.css b/libs/serialport/doc/style/style.css new file mode 100644 index 0000000000000000000000000000000000000000..df84049f12a08d68086728ae454e72ba6ecd75da --- /dev/null +++ b/libs/serialport/doc/style/style.css @@ -0,0 +1,137 @@ +a:link, a:visited { + color: #00732F; + text-decoration: none; + font-weight: bold; +} + +body { + font: normal 400 14px/1.2 Arial; + margin-top: 85px; +} + +h1 { + margin: 0; +} + +h2 { + font: 500 20px/1.2 Arial; +} + +h3.fn, span.fn { + -moz-border-radius: 7px 7px 7px 7px; + -webkit-border-radius: 7px 7px 7px 7px; + border-radius: 7px 7px 7px 7px; + background-color: #F6F6F6; + border-width: 1px; + border-style: solid; + border-color: #E6E6E6; + word-spacing: 3px; + padding: 3px 5px; +} + +table, pre { + -moz-border-radius: 7px 7px 7px 7px; + -webkit-border-radius: 7px 7px 7px 7px; + border-radius: 7px 7px 7px 7px; + background-color: #F6F6F6; + border: 1px solid #E6E6E6; + border-collapse: separate; + font-size: 12px; + line-height: 1.2; + margin-bottom: 25px; + margin-left: 15px; +} + +table td { + padding: 3px 15px 3px 20px; +} + +table tr.even { + background-color: white; + color: #66666E; +} + +table tr.odd { + background-color: #F6F6F6; + color: #66666E; +} + +li { + margin-bottom: 10px; + padding-left: 12px; +} + +.cpp { + display: block; + margin: 10; + overflow: hidden; + overflow-x: hidden; + overflow-y: hidden; + padding: 20px 0 20px 0; +} + +.footer { + margin-top: 50px; +} + +.memItemLeft { + padding-right: 3px; +} + +.memItemRight { + padding: 3px 15px 3px 0; +} + +.qml { + display: block; + margin: 10; + overflow: hidden; + overflow-x: hidden; + overflow-y: hidden; + padding: 20px 0 20px 0; +} + +.qmldefault { + padding-left: 5px; + float: right; + color: red; +} + +.qmlreadonly { + padding-left: 5px; + float: right; + color: #254117; +} + +.rightAlign { + padding: 3px 5px 3px 10px; + text-align: right; +} + +.title { + background-color: white; + color: #44A51C; + font-family: Verdana; + font-size: 35px; + font-weight: normal; + left: 0; + padding-bottom: 5px; + padding-left: 16px; + padding-top: 20px; + position: absolute; + right: 0; + top: 0; +} + +.toc { + float: right; + -moz-border-radius: 7px 7px 7px 7px; + -webkit-border-radius: 7px 7px 7px 7px; + border-radius: 7px 7px 7px 7px; + background-color: #F6F6F6; + border: 1px solid #DDD; + margin: 0 20px 10px 10px; + padding: 20px 15px 20px 20px; + height: auto; + width: 200px; +} diff --git a/libs/serialport/qserialport.cpp b/libs/serialport/qserialport.cpp new file mode 100644 index 0000000000000000000000000000000000000000..96f06d4bd9d3f17d644bcca0b8cf4b15035ae523 --- /dev/null +++ b/libs/serialport/qserialport.cpp @@ -0,0 +1,1167 @@ +/**************************************************************************** +** +** Copyright (C) 2011-2012 Denis Shienkov +** Copyright (C) 2011 Sergey Belyashov +** Copyright (C) 2012 Laszlo Papp +** Copyright (C) 2012 Andre Hartmann +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialport.h" +#include "qserialportinfo.h" + +#ifdef Q_OS_WIN +#include "qserialport_win_p.h" +#elif defined (Q_OS_SYMBIAN) +#include "qserialport_symbian_p.h" +#elif defined (Q_OS_UNIX) +#include "qserialport_unix_p.h" +#else +#error Unsupported OS +#endif + +#ifndef SERIALPORT_BUFFERSIZE +# define SERIALPORT_BUFFERSIZE 16384 +#endif + +QT_BEGIN_NAMESPACE + +QSerialPortPrivateData::QSerialPortPrivateData(QSerialPort *q) + : readBufferMaxSize(0) + , readBuffer(SERIALPORT_BUFFERSIZE) + , writeBuffer(SERIALPORT_BUFFERSIZE) + , error(QSerialPort::NoError) + , inputBaudRate(0) + , outputBaudRate(0) + , dataBits(QSerialPort::UnknownDataBits) + , parity(QSerialPort::UnknownParity) + , stopBits(QSerialPort::UnknownStopBits) + , flow(QSerialPort::UnknownFlowControl) + , policy(QSerialPort::IgnorePolicy) + , settingsRestoredOnClose(true) + , q_ptr(q) +{ +} + +int QSerialPortPrivateData::timeoutValue(int msecs, int elapsed) +{ + if (msecs == -1) + return msecs; + msecs -= elapsed; + return qMax(msecs, 0); +} + +/*! + \class QSerialPort + + \brief Provides functions to access serial ports. + + \reentrant + \ingroup serialport-main + \inmodule QtSerialPort + \since 5.1 + + You can get information about the available serial ports using the + QSerialPortInfo helper class, which allows an enumeration of all the serial + ports in the system. This is useful to obtain the correct name of the + serial port you want to use. You can pass an object + of the helper class as an argument to the setPort() or setPortName() + methods to assign the desired serial device. + + After setting the port, you can open it in read-only (r/o), write-only + (w/o), or read-write (r/w) mode using the open() method. + + \note The serial port is always opened with exclusive access + (that is, no other process or thread can access an already opened serial port). + + Having successfully opened, QSerialPort tries to determine the current + configuration of the port and initializes itself. You can reconfigure the + port to the desired setting using the setBaudRate(), setDataBits(), + setParity(), setStopBits(), and setFlowControl() methods. + + The status of the control pinout signals is determined with the + isDataTerminalReady(), isRequestToSend, and pinoutSignals() methods. To + change the control line status, use the setDataTerminalReady(), and + setRequestToSend() methods. + + Once you know that the ports are ready to read or write, you can + use the read() or write() methods. Alternatively the + readLine() and readAll() convenience methods can also be invoked. + If not all the data is read at once, the remaining data will + be available for later as new incoming data is appended to the + QSerialPort's internal read buffer. You can limit the size of the read + buffer using setReadBufferSize(). + + Use the close() method to close the port and cancel the I/O operations. + + See the following example: + + \code + int numRead = 0, numReadTotal = 0; + char buffer[50]; + + forever { + numRead = serial.read(buffer, 50); + + // Do whatever with the array + + numReadTotal += numRead; + if (numRead == 0 && !serial.waitForReadyRead()) + break; + } + \endcode + + If \l{QIODevice::}{waitForReadyRead()} returns false, the + connection has been closed or an error has occurred. + + Programming with a blocking serial port is radically different from + programming with a non-blocking serial port. A blocking serial port + does not require an event loop and typically leads to simpler code. + However, in a GUI application, blocking serial port should only be + used in non-GUI threads, to avoid freezing the user interface. + + For more details about these approaches, refer to the + \l {Examples}{example} applications. + + The QSerialPort class can also be used with QTextStream and QDataStream's + stream operators (operator<<() and operator>>()). There is one issue to be + aware of, though: make sure that enough data is available before attempting + to read by using the operator>>() overloaded operator. + + \sa QSerialPortInfo +*/ + +/*! + \enum QSerialPort::Direction + + This enum describes the possible directions of the data transmission. + + \note This enumeration is used for setting the baud rate of the device + separately for each direction on some operating systems (for example, + POSIX-like). + + \value Input Input direction. + \value Output Output direction. + \value AllDirections Simultaneously in two directions. +*/ + +/*! + \enum QSerialPort::BaudRate + + This enum describes the baud rate which the communication device operates + with. Note: only the most common standard baud rates are listed in this + enum. + + \value Baud1200 1200 baud. + \value Baud2400 2400 baud. + \value Baud4800 4800 baud. + \value Baud9600 9600 baud. + \value Baud19200 19200 baud. + \value Baud38400 38400 baud. + \value Baud57600 57600 baud. + \value Baud115200 115200 baud. + \value UnknownBaud Unknown baud. + + \sa QSerialPort::baudRate +*/ + +/*! + \enum QSerialPort::DataBits + + This enum describes the number of data bits used. + + \value Data5 Five bits. + \value Data6 Six bits. + \value Data7 Seven bits + \value Data8 Eight bits. + \value UnknownDataBits Unknown number of bits. + + \sa QSerialPort::dataBits +*/ + +/*! + \enum QSerialPort::Parity + + This enum describes the parity scheme used. + + \value NoParity No parity. + \value EvenParity Even parity. + \value OddParity Odd parity. + \value SpaceParity Space parity. + \value MarkParity Mark parity. + \value UnknownParity Unknown parity. + + \sa QSerialPort::parity +*/ + +/*! + \enum QSerialPort::StopBits + + This enum describes the number of stop bits used. + + \value OneStop 1 stop bit. + \value OneAndHalfStop 1.5 stop bits. + \value TwoStop 2 stop bits. + \value UnknownStopBits Unknown number of stop bit. + + \sa QSerialPort::stopBits +*/ + +/*! + \enum QSerialPort::FlowControl + + This enum describes the flow control used. + + \value NoFlowControl No flow control. + \value HardwareControl Hardware flow control (RTS/CTS). + \value SoftwareControl Software flow control (XON/XOFF). + \value UnknownFlowControl Unknown flow control. + + \sa QSerialPort::flowControl +*/ + +/*! + \enum QSerialPort::PinoutSignal + + This enum describes the possible RS-232 pinout signals. + + \value NoSignal No line active + \value TransmittedDataSignal TxD (Transmitted Data). + \value ReceivedDataSignal RxD (Received Data). + \value DataTerminalReadySignal DTR (Data Terminal Ready). + \value DataCarrierDetectSignal DCD (Data Carrier Detect). + \value DataSetReadySignal DSR (Data Set Ready). + \value RingIndicatorSignal RNG (Ring Indicator). + \value RequestToSendSignal RTS (Request To Send). + \value ClearToSendSignal CTS (Clear To Send). + \value SecondaryTransmittedDataSignal STD (Secondary Transmitted Data). + \value SecondaryReceivedDataSignal SRD (Secondary Received Data). + + \sa pinoutSignals(), QSerialPort::dataTerminalReady, + QSerialPort::requestToSend +*/ + +/*! + \enum QSerialPort::DataErrorPolicy + + This enum describes the policies for the received symbols + while parity errors were detected. + + \value SkipPolicy Skips the bad character. + \value PassZeroPolicy Replaces bad character to zero. + \value IgnorePolicy Ignores the error for a bad character. + \value StopReceivingPolicy Stops data reception on error. + \value UnknownPolicy Unknown policy. + + \sa QSerialPort::dataErrorPolicy +*/ + +/*! + \enum QSerialPort::SerialPortError + + This enum describes the errors that may be contained by the + QSerialPort::error property. + + \value NoError No error occurred. + \value DeviceNotFoundError An error occurred while attempting to + open an non-existing device. + \value PermissionError An error occurred while attempting to + open an already opened device by another process or a user not + having enough permission and credentials to open. + \value OpenError An error occurred while attempting to + open an already opened device in this object. + \value ParityError Parity error detected by the hardware while reading data. + \value FramingError Framing error detected by the hardware while reading data. + \value BreakConditionError Break condition detected by the hardware on + the input line. + \value WriteError An I/O error occurred while writing the data. + \value ReadError An I/O error occurred while reading the data. + \value ResourceError An I/O error occurred when a resource becomes unavailable, + e.g. when the device is unexpectedly removed from the system. + \value UnsupportedOperationError The requested device operation is + not supported or prohibited by the running operating system. + \value UnknownError An unidentified error occurred. + + \sa QSerialPort::error +*/ + + + +/*! + Constructs a new serial port object with the given \a parent. +*/ +QSerialPort::QSerialPort(QObject *parent) + : QIODevice(parent) + , d_ptr(new QSerialPortPrivate(this)) +{} + +/*! + Constructs a new serial port object with the given \a parent + to represent the serial port with the specified \a name. + + The name should have a specific format; see the setPort() method. +*/ +QSerialPort::QSerialPort(const QString &name, QObject *parent) + : QIODevice(parent) + , d_ptr(new QSerialPortPrivate(this)) +{ + setPortName(name); +} + +/*! + Constructs a new serial port object with the given \a parent + to represent the serial port with the specified helper class + \a serialPortInfo. +*/ +QSerialPort::QSerialPort(const QSerialPortInfo &serialPortInfo, QObject *parent) + : QIODevice(parent) + , d_ptr(new QSerialPortPrivate(this)) +{ + setPort(serialPortInfo); +} + +/*! + Closes the serial port, if necessary, and then destroys object. +*/ +QSerialPort::~QSerialPort() +{ + /**/ + close(); + delete d_ptr; +} + +/*! + Sets the \a name of the serial port. + + The name of the serial port can be passed on as either a short name or + the long system location if necessary. + + \sa portName(), QSerialPortInfo +*/ +void QSerialPort::setPortName(const QString &name) +{ + Q_D(QSerialPort); + d->systemLocation = QSerialPortPrivate::portNameToSystemLocation(name); +} + +/*! + Sets the port stored in the serial port info instance \a serialPortInfo. + + \sa portName(), QSerialPortInfo +*/ +void QSerialPort::setPort(const QSerialPortInfo &serialPortInfo) +{ + Q_D(QSerialPort); + d->systemLocation = QSerialPortPrivate::portNameToSystemLocation(serialPortInfo.systemLocation()); +} + +/*! + Returns the name set by setPort() or to the QSerialPort constructors. + This name is short, i.e. it extract and convert out from the internal + variable system location of the device. Conversion algorithm is + platform specific: + \table + \header + \li Platform + \li Brief Description + \row + \li Windows + \li Removes the prefix "\\\\.\\" from the system location + and returns the remainder of the string. + \row + \li Windows CE + \li Removes the postfix ":" from the system location + and returns the remainder of the string. + \row + \li Symbian + \li Returns the system location as it is, + as it is equivalent to the port name. + \row + \li GNU/Linux + \li Removes the prefix "/dev/" from the system location + and returns the remainder of the string. + \row + \li Mac OSX + \li Removes the prefix "/dev/cu." and "/dev/tty." from the + system location and returns the remainder of the string. + \row + \li Other *nix + \li The same as for GNU/Linux. + \endtable + + \sa setPort(), QSerialPortInfo::portName() +*/ +QString QSerialPort::portName() const +{ + Q_D(const QSerialPort); + return QSerialPortPrivate::portNameFromSystemLocation(d->systemLocation); +} + +/*! + \reimp + + Opens the serial port using OpenMode \a mode, and then returns true if + successful; otherwise returns false with and sets an error code which can be + obtained by calling the error() method. + + \warning The \a mode has to be QIODevice::ReadOnly, QIODevice::WriteOnly, + or QIODevice::ReadWrite. Other modes are unsupported. + + \sa QIODevice::OpenMode, setPort() +*/ +bool QSerialPort::open(OpenMode mode) +{ + Q_D(QSerialPort); + + if (isOpen()) { + setError(QSerialPort::OpenError); + return false; + } + + // Define while not supported modes. + static const OpenMode unsupportedModes = Append | Truncate | Text | Unbuffered; + if ((mode & unsupportedModes) || mode == NotOpen) { + setError(QSerialPort::UnsupportedOperationError); + return false; + } + + clearError(); + if (d->open(mode)) { + QIODevice::open(mode); + + d->dataTerminalReady = isDataTerminalReady(); + d->requestToSend = isRequestToSend(); + + return true; + } + return false; +} + +/*! + \reimp + + \sa QIODevice::close() +*/ +void QSerialPort::close() +{ + Q_D(QSerialPort); + if (!isOpen()) { + return; + } + + QIODevice::close(); + d->close(); +} + +/*! + \property QSerialPort::settingsRestoredOnClose + \brief the flag which allows to restore the previous settings while closing + the serial port. + + If this flag is true, the settings will be restored; otherwise not. + The default state of the QSerialPort class is configured to restore the + settings. +*/ +void QSerialPort::setSettingsRestoredOnClose(bool restore) +{ + Q_D(QSerialPort); + + if (d->settingsRestoredOnClose != restore) { + d->settingsRestoredOnClose = restore; + emit settingsRestoredOnCloseChanged(d->settingsRestoredOnClose); + } +} + +bool QSerialPort::settingsRestoredOnClose() const +{ + Q_D(const QSerialPort); + return d->settingsRestoredOnClose; +} + +/*! + \fn void QSerialPort::settingsRestoredOnCloseChanged(bool restore) + + This signal is emitted after the flag which allows to restore the + previous settings while closing the serial port has been changed. The new + flag which allows to restore the previous settings while closing the serial + port is passed as \a restore. + + \sa QSerialPort::settingsRestoredOnClose +*/ + +/*! + \property QSerialPort::baudRate + \brief the data baud rate for the desired direction + + If the setting is successful, returns true; otherwise returns false and sets + an error code which can be obtained by accessing the value of the + QSerialPort::error property. To set the baud rate, use the enumeration + QSerialPort::BaudRate or any positive qint32 value. + + \warning Only the AllDirections flag is support for setting this property on + Windows, Windows CE, and Symbian. + + \warning Returns equal baud rate in any direction on Windows, Windows CE, and + Symbian. +*/ +bool QSerialPort::setBaudRate(qint32 baudRate, Directions dir) +{ + Q_D(QSerialPort); + + if (d->setBaudRate(baudRate, dir)) { + if (dir & QSerialPort::Input) { + if (d->inputBaudRate != baudRate) + d->inputBaudRate = baudRate; + else + dir &= ~QSerialPort::Input; + } + + if (dir & QSerialPort::Output) { + if (d->outputBaudRate != baudRate) + d->outputBaudRate = baudRate; + else + dir &= ~QSerialPort::Output; + } + + if (dir) + emit baudRateChanged(baudRate, dir); + + return true; + } + + return false; +} + +qint32 QSerialPort::baudRate(Directions dir) const +{ + Q_D(const QSerialPort); + if (dir == QSerialPort::AllDirections) + return d->inputBaudRate == d->outputBaudRate ? + d->inputBaudRate : QSerialPort::UnknownBaud; + return dir & QSerialPort::Input ? d->inputBaudRate : d->outputBaudRate; +} + +/*! + \fn void QSerialPort::baudRateChanged(qint32 baudRate, Directions dir) + + This signal is emitted after the baud rate has been changed. The new baud + rate is passed as \a baudRate and directions as \a dir. + + \sa QSerialPort::baudRate +*/ + +/*! + \property QSerialPort::dataBits + \brief the data bits in a frame + + If the setting is successful, returns true; otherwise returns false and sets + an error code which can be obtained by accessing the value of the + QSerialPort::error property. +*/ +bool QSerialPort::setDataBits(DataBits dataBits) +{ + Q_D(QSerialPort); + + if (d->setDataBits(dataBits)) { + if (d->dataBits != dataBits) { + d->dataBits = dataBits; + emit dataBitsChanged(d->dataBits); + } + return true; + } + + return false; +} + +QSerialPort::DataBits QSerialPort::dataBits() const +{ + Q_D(const QSerialPort); + return d->dataBits; +} + +/*! + \fn void QSerialPort::dataBitsChanged(DataBits dataBits) + + This signal is emitted after the data bits in a frame has been changed. The + new data bits in a frame is passed as \a dataBits. + + \sa QSerialPort::dataBits +*/ + + +/*! + \property QSerialPort::parity + \brief the parity checking mode + + If the setting is successful, returns true; otherwise returns false and sets + an error code which can be obtained by accessing the value of the + QSerialPort::error property. +*/ +bool QSerialPort::setParity(Parity parity) +{ + Q_D(QSerialPort); + + if (d->setParity(parity)) { + if (d->parity != parity) { + d->parity = parity; + emit parityChanged(d->parity); + } + return true; + } + + return false; +} + +QSerialPort::Parity QSerialPort::parity() const +{ + Q_D(const QSerialPort); + return d->parity; +} + +/*! + \fn void QSerialPort::parityChanged(Parity parity) + + This signal is emitted after the parity checking mode has been changed. The + new parity checking mode is passed as \a parity. + + \sa QSerialPort::parity +*/ + +/*! + \property QSerialPort::stopBits + \brief the number of stop bits in a frame + + If the setting is successful, returns true; otherwise returns false and + sets an error code which can be obtained by accessing the value of the + QSerialPort::error property. +*/ +bool QSerialPort::setStopBits(StopBits stopBits) +{ + Q_D(QSerialPort); + + if (d->setStopBits(stopBits)) { + if (d->stopBits != stopBits) { + d->stopBits = stopBits; + emit stopBitsChanged(d->stopBits); + } + return true; + } + + return false; +} + +QSerialPort::StopBits QSerialPort::stopBits() const +{ + Q_D(const QSerialPort); + return d->stopBits; +} + +/*! + \fn void QSerialPort::stopBitsChanged(StopBits stopBits) + + This signal is emitted after the number of stop bits in a frame has been + changed. The new number of stop bits in a frame is passed as \a stopBits. + + \sa QSerialPort::stopBits +*/ + +/*! + \property QSerialPort::flowControl + \brief the desired flow control mode + + If the setting is successful, returns true; otherwise returns false and sets + an error code which can be obtained by accessing the value of the + QSerialPort::error property. +*/ +bool QSerialPort::setFlowControl(FlowControl flow) +{ + Q_D(QSerialPort); + + if (d->setFlowControl(flow)) { + if (d->flow != flow) { + d->flow = flow; + emit flowControlChanged(d->flow); + } + return true; + } + + return false; +} + +QSerialPort::FlowControl QSerialPort::flowControl() const +{ + Q_D(const QSerialPort); + return d->flow; +} + +/*! + \fn void QSerialPort::flowControlChanged(FlowControl flow) + + This signal is emitted after the flow control mode has been changed. The + new flow control mode is passed as \a flow. + + \sa QSerialPort::flowControl +*/ + +/*! + \property QSerialPort::dataTerminalReady + \brief the state (high or low) of the line signal DTR + + If the setting is successful, returns true; otherwise returns false. + If the flag is true then the DTR signal is set to high; otherwise low. + + \sa pinoutSignals() +*/ +bool QSerialPort::setDataTerminalReady(bool set) +{ + Q_D(QSerialPort); + + bool retval = d->setDataTerminalReady(set); + if (retval && (d->dataTerminalReady != set)) { + d->dataTerminalReady = set; + emit dataTerminalReadyChanged(set); + } + + return retval; +} + +bool QSerialPort::isDataTerminalReady() +{ + Q_D(const QSerialPort); + return d->pinoutSignals() & QSerialPort::DataTerminalReadySignal; +} + +/*! + \fn void QSerialPort::dataTerminalReadyChanged(bool set) + + This signal is emitted after the state (high or low) of the line signal DTR + has been changed. The new the state (high or low) of the line signal DTR is + passed as \a set. + + \sa QSerialPort::dataTerminalReady +*/ + +/*! + \property QSerialPort::requestToSend + \brief the state (high or low) of the line signal RTS + + If the setting is successful, returns true; otherwise returns false. + If the flag is true then the RTS signal is set to high; otherwise low. + + \sa pinoutSignals() +*/ +bool QSerialPort::setRequestToSend(bool set) +{ + Q_D(QSerialPort); + + bool retval = d->setRequestToSend(set); + if (retval && (d->requestToSend != set)) { + d->requestToSend = set; + emit requestToSendChanged(set); + } + + return retval; +} + +bool QSerialPort::isRequestToSend() +{ + Q_D(const QSerialPort); + return d->pinoutSignals() & QSerialPort::RequestToSendSignal; +} + +/*! + \fn void QSerialPort::requestToSendChanged(bool set) + + This signal is emitted after the state (high or low) of the line signal RTS + has been changed. The new the state (high or low) of the line signal RTS is + passed as \a set. + + \sa QSerialPort::requestToSend +*/ + +/*! + Returns the state of the line signals in a bitmap format. + + From this result, it is possible to allocate the state of the + desired signal by applying a mask "AND", where the mask is + the desired enumeration value from QSerialPort::PinoutSignals. + + Note that, this method performs a system call, thus ensuring that the line + signal states are returned properly. This is necessary when the underlying + operating systems cannot provide proper notifications about the changes. + + \sa isDataTerminalReady(), isRequestToSend, setDataTerminalReady(), + setRequestToSend() +*/ +QSerialPort::PinoutSignals QSerialPort::pinoutSignals() +{ + Q_D(const QSerialPort); + return d->pinoutSignals(); +} + +/*! + This function writes as much as possible from the internal write + buffer to the underlying serial port without blocking. If any data + was written, this function returns true; otherwise returns false. + + Call this function for sending the buffered data immediately to the serial + port. The number of bytes successfully written depends on the operating + system. In most cases, this function does not need to be called, because the + QSerialPort class will start sending data automatically once control is + returned to the event loop. In the absence of an event loop, call + waitForBytesWritten() instead. + + \sa write(), waitForBytesWritten() +*/ +bool QSerialPort::flush() +{ + Q_D(QSerialPort); + return d->flush(); +} + +/*! + Discards all characters from the output or input buffer, depending on + a given direction \a dir. Including clear an internal class buffers and + the UART (driver) buffers. Also terminate pending read or write operations. + If successful, returns true; otherwise returns false. +*/ +bool QSerialPort::clear(Directions dir) +{ + Q_D(QSerialPort); + if (dir & Input) + d->readBuffer.clear(); + if (dir & Output) + d->writeBuffer.clear(); + return d->clear(dir); +} + +/*! + \reimp + + Returns true if no more data is currently available for reading; otherwise + returns false. + + This function is most commonly used when reading data from the + serial port in a loop. For example: + + \code + // This slot is connected to QSerialPort::readyRead() + void QSerialPortClass::readyReadSlot() + { + while (!port.atEnd()) { + QByteArray data = port.read(100); + .... + } + } + \endcode + + \sa bytesAvailable(), readyRead() + */ +bool QSerialPort::atEnd() const +{ + Q_D(const QSerialPort); + return QIODevice::atEnd() && (!isOpen() || (d->bytesAvailable() == 0)); +} + +/*! + \property QSerialPort::dataErrorPolicy + \brief the error policy how the process receives the character in case of + parity error detection. + + If the setting is successful, returns true; otherwise returns false. The + default policy set is IgnorePolicy. +*/ +bool QSerialPort::setDataErrorPolicy(DataErrorPolicy policy) +{ + Q_D(QSerialPort); + + const bool ret = d->policy == policy || d->setDataErrorPolicy(policy); + if (ret && (d->policy != policy)) { + d->policy = policy; + emit dataErrorPolicyChanged(d->policy); + } + + return ret; +} + +QSerialPort::DataErrorPolicy QSerialPort::dataErrorPolicy() const +{ + Q_D(const QSerialPort); + return d->policy; +} + +/*! + \fn void QSerialPort::dataErrorPolicyChanged(DataErrorPolicy policy) + + This signal is emitted after the error policy how the process receives the + character in case of parity error detection has been changed. The new error + policy how the process receives the character in case of parity error + detection is passed as \a policy. + + \sa QSerialPort::dataErrorPolicy +*/ + +/*! + \property QSerialPort::error + \brief the error status of the serial port + + The I/O device status returns an error code. For example, if open() + returns false, or a read/write operation returns -1, this property can + be used to figure out the reason why the operation failed. + + The error code is set to the default QSerialPort::NoError after a call to + clearError() +*/ +QSerialPort::SerialPortError QSerialPort::error() const +{ + Q_D(const QSerialPort); + return d->error; +} + +void QSerialPort::clearError() +{ + setError(QSerialPort::NoError); +} + +/*! + \fn void QSerialPort::error(SerialPortError error) + + This signal is emitted after the error has been changed. The new erroris + passed as \a error. + + \sa QSerialPort::error +*/ + +/*! + Returns the size of the internal read buffer. This limits the + amount of data that the client can receive before calling the read() + or readAll() methods. + + A read buffer size of 0 (the default) means that the buffer has + no size limit, ensuring that no data is lost. + + \sa setReadBufferSize(), read() +*/ +qint64 QSerialPort::readBufferSize() const +{ + Q_D(const QSerialPort); + return d->readBufferMaxSize; +} + +/*! + Sets the size of QSerialPort's internal read buffer to be \a + size bytes. + + If the buffer size is limited to a certain size, QSerialPort + will not buffer more than this size of data. Exceptionally, a buffer + size of 0 means that the read buffer is unlimited and all + incoming data is buffered. This is the default. + + This option is useful if the data is only read at certain points + in time (for instance in a real-time streaming application) or if the serial + port should be protected against receiving too much data, which may + eventually causes that the application runs out of memory. + + \sa readBufferSize(), read() +*/ +void QSerialPort::setReadBufferSize(qint64 size) +{ + Q_D(QSerialPort); + + if (d->readBufferMaxSize == size) + return; + d->readBufferMaxSize = size; +} + +/*! + \reimp + + Always returns true. The serial port is a sequential device. +*/ +bool QSerialPort::isSequential() const +{ + return true; +} + +/*! + \reimp + + Returns the number of incoming bytes that are waiting to be read. + + \sa bytesToWrite(), read() +*/ +qint64 QSerialPort::bytesAvailable() const +{ + Q_D(const QSerialPort); + return d->bytesAvailable() + QIODevice::bytesAvailable(); +} + +/*! + \reimp + + Returns the number of bytes that are waiting to be written. The + bytes are written when control goes back to the event loop or + when flush() is called. + + \sa bytesAvailable(), flush() +*/ +qint64 QSerialPort::bytesToWrite() const +{ + Q_D(const QSerialPort); + return d->writeBuffer.size() + QIODevice::bytesToWrite(); +} + +/*! + \reimp + + Returns true if a line of data can be read from the serial port; + otherwise returns false. + + \sa readLine() +*/ +bool QSerialPort::canReadLine() const +{ + Q_D(const QSerialPort); + const bool hasLine = (d->bytesAvailable() > 0) && d->readBuffer.canReadLine(); + return hasLine || QIODevice::canReadLine(); +} + +/*! + \reimp + + This function blocks until new data is available for reading and the + \l{QIODevice::}{readyRead()} signal has been emitted. The function + will timeout after \a msecs milliseconds. + + The function returns true if the readyRead() signal is emitted and + there is new data available for reading; otherwise it returns false + (if an error occurred or the operation timed out). + + \sa waitForBytesWritten() +*/ +bool QSerialPort::waitForReadyRead(int msecs) +{ + Q_D(QSerialPort); + return d->waitForReadyRead(msecs); +} + +/*! + \reimp +*/ +bool QSerialPort::waitForBytesWritten(int msecs) +{ + Q_D(QSerialPort); + return d->waitForBytesWritten(msecs); +} + +/*! + Sends a continuous stream of zero bits during a specified period + of time \a duration in msec if the terminal is using asynchronous + serial data. If successful, returns true; otherwise returns false. + + If the duration is zero then zero bits are transmitted by at least + 0.25 seconds, but no more than 0.5 seconds. + + If the duration is non zero then zero bits are transmitted within a certain + period of time depending on the implementation. + + \sa setBreakEnabled() +*/ +bool QSerialPort::sendBreak(int duration) +{ + Q_D(QSerialPort); + return d->sendBreak(duration); +} + +/*! + Controls the signal break, depending on the flag \a set. + If successful, returns true; otherwise returns false. + + If \a set is true then enables the break transmission; otherwise disables. + + \sa sendBreak() +*/ +bool QSerialPort::setBreakEnabled(bool set) +{ + Q_D(QSerialPort); + return d->setBreakEnabled(set); +} + +/*! + \reimp +*/ +qint64 QSerialPort::readData(char *data, qint64 maxSize) +{ + Q_D(QSerialPort); + return d->readFromBuffer(data, maxSize); +} + +/*! + \reimp +*/ +qint64 QSerialPort::readLineData(char *data, qint64 maxSize) +{ + return QIODevice::readLineData(data, maxSize); +} + +/*! + \reimp +*/ +qint64 QSerialPort::writeData(const char *data, qint64 maxSize) +{ + Q_D(QSerialPort); + return d->writeToBuffer(data, maxSize); +} + +void QSerialPort::setError(QSerialPort::SerialPortError serialPortError, const QString &errorString) +{ + Q_D(QSerialPort); + + d->error = serialPortError; + + if (errorString.isNull()) + setErrorString(qt_error_string(-1)); + else + setErrorString(errorString); + + emit error(serialPortError); +} + +#include "moc_qserialport.cpp" + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialport.h b/libs/serialport/qserialport.h new file mode 100644 index 0000000000000000000000000000000000000000..8a2842fe0dd7630970237eebd1d6dba3131b6b95 --- /dev/null +++ b/libs/serialport/qserialport.h @@ -0,0 +1,257 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2013 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSERIALPORT_H +#define QSERIALPORT_H + +#include + +#include +//#include +QT_BEGIN_NAMESPACE + +class QSerialPortInfo; +class QSerialPortPrivate; + +class Q_SERIALPORT_EXPORT QSerialPort : public QIODevice +{ + Q_OBJECT + + Q_PROPERTY(qint32 baudRate READ baudRate WRITE setBaudRate NOTIFY baudRateChanged) + Q_PROPERTY(DataBits dataBits READ dataBits WRITE setDataBits NOTIFY dataBitsChanged) + Q_PROPERTY(Parity parity READ parity WRITE setParity NOTIFY parityChanged) + Q_PROPERTY(StopBits stopBits READ stopBits WRITE setStopBits NOTIFY stopBitsChanged) + Q_PROPERTY(FlowControl flowControl READ flowControl WRITE setFlowControl NOTIFY flowControlChanged) + Q_PROPERTY(DataErrorPolicy dataErrorPolicy READ dataErrorPolicy WRITE setDataErrorPolicy NOTIFY dataErrorPolicyChanged) + Q_PROPERTY(bool dataTerminalReady READ isDataTerminalReady WRITE setDataTerminalReady NOTIFY dataTerminalReadyChanged) + Q_PROPERTY(bool requestToSend READ isRequestToSend WRITE setRequestToSend NOTIFY requestToSendChanged) + Q_PROPERTY(SerialPortError error READ error RESET clearError NOTIFY error) + Q_PROPERTY(bool settingsRestoredOnClose READ settingsRestoredOnClose WRITE setSettingsRestoredOnClose NOTIFY settingsRestoredOnCloseChanged) + + Q_ENUMS( Directions Rate DataBits Parity StopBits FlowControl PinoutSignals DataErrorPolicy SerialPortError ) + +public: + + enum Direction { + Input = 1, + Output = 2, + AllDirections = Input | Output + }; + Q_DECLARE_FLAGS(Directions, Direction) + + enum BaudRate { + Baud1200 = 1200, + Baud2400 = 2400, + Baud4800 = 4800, + Baud9600 = 9600, + Baud19200 = 19200, + Baud38400 = 38400, + Baud57600 = 57600, + Baud115200 = 115200, + UnknownBaud = -1 + }; + + enum DataBits { + Data5 = 5, + Data6 = 6, + Data7 = 7, + Data8 = 8, + UnknownDataBits = -1 + }; + + enum Parity { + NoParity = 0, + EvenParity = 2, + OddParity = 3, + SpaceParity = 4, + MarkParity = 5, + UnknownParity = -1 + }; + + enum StopBits { + OneStop = 1, + OneAndHalfStop = 3, + TwoStop = 2, + UnknownStopBits = -1 + }; + + enum FlowControl { + NoFlowControl, + HardwareControl, + SoftwareControl, + UnknownFlowControl = -1 + }; + + enum PinoutSignal { + NoSignal = 0x00, + TransmittedDataSignal = 0x01, + ReceivedDataSignal = 0x02, + DataTerminalReadySignal = 0x04, + DataCarrierDetectSignal = 0x08, + DataSetReadySignal = 0x10, + RingIndicatorSignal = 0x20, + RequestToSendSignal = 0x40, + ClearToSendSignal = 0x80, + SecondaryTransmittedDataSignal = 0x100, + SecondaryReceivedDataSignal = 0x200 + }; + Q_DECLARE_FLAGS(PinoutSignals, PinoutSignal) + + enum DataErrorPolicy { + SkipPolicy, + PassZeroPolicy, + IgnorePolicy, + StopReceivingPolicy, + UnknownPolicy = -1 + }; + + enum SerialPortError { + NoError, + DeviceNotFoundError, + PermissionError, + OpenError, + ParityError, + FramingError, + BreakConditionError, + WriteError, + ReadError, + ResourceError, + UnsupportedOperationError, + UnknownError + }; + + explicit QSerialPort(QObject *parent = 0); + explicit QSerialPort(const QString &name, QObject *parent = 0); + explicit QSerialPort(const QSerialPortInfo &info, QObject *parent = 0); + virtual ~QSerialPort(); + + void setPortName(const QString &name); + QString portName() const; + + void setPort(const QSerialPortInfo &info); + + bool open(OpenMode mode) Q_DECL_OVERRIDE; + void close() Q_DECL_OVERRIDE; + + void setSettingsRestoredOnClose(bool restore); + bool settingsRestoredOnClose() const; + + bool setBaudRate(qint32 baudRate, Directions dir = AllDirections); + qint32 baudRate(Directions dir = AllDirections) const; + + bool setDataBits(DataBits dataBits); + DataBits dataBits() const; + + bool setParity(Parity parity); + Parity parity() const; + + bool setStopBits(StopBits stopBits); + StopBits stopBits() const; + + bool setFlowControl(FlowControl flow); + FlowControl flowControl() const; + + bool setDataTerminalReady(bool set); + bool isDataTerminalReady(); + + bool setRequestToSend(bool set); + bool isRequestToSend(); + + PinoutSignals pinoutSignals(); + + bool flush(); + bool clear(Directions dir = AllDirections); + bool atEnd() const Q_DECL_OVERRIDE; + + bool setDataErrorPolicy(DataErrorPolicy policy = IgnorePolicy); + DataErrorPolicy dataErrorPolicy() const; + + SerialPortError error() const; + void clearError(); + + qint64 readBufferSize() const; + void setReadBufferSize(qint64 size); + + bool isSequential() const Q_DECL_OVERRIDE; + + qint64 bytesAvailable() const Q_DECL_OVERRIDE; + qint64 bytesToWrite() const Q_DECL_OVERRIDE; + bool canReadLine() const Q_DECL_OVERRIDE; + + bool waitForReadyRead(int msecs) Q_DECL_OVERRIDE; + bool waitForBytesWritten(int msecs) Q_DECL_OVERRIDE; + + bool sendBreak(int duration = 0); + bool setBreakEnabled(bool set = true); + +Q_SIGNALS: + void baudRateChanged(qint32 baudRate, QSerialPort::Directions dir); + void dataBitsChanged(QSerialPort::DataBits dataBits); + void parityChanged(QSerialPort::Parity parity); + void stopBitsChanged(QSerialPort::StopBits stopBits); + void flowControlChanged(QSerialPort::FlowControl flow); + void dataErrorPolicyChanged(QSerialPort::DataErrorPolicy policy); + void dataTerminalReadyChanged(bool set); + void requestToSendChanged(bool set); + void error(QSerialPort::SerialPortError serialPortError); + void settingsRestoredOnCloseChanged(bool restore); + +protected: + qint64 readData(char *data, qint64 maxSize) Q_DECL_OVERRIDE; + qint64 readLineData(char *data, qint64 maxSize) Q_DECL_OVERRIDE; + qint64 writeData(const char *data, qint64 maxSize) Q_DECL_OVERRIDE; + +private: + void setError(QSerialPort::SerialPortError error, const QString &errorString = QString()); + + QSerialPortPrivate * const d_ptr; + + Q_DECLARE_PRIVATE(QSerialPort) + Q_DISABLE_COPY(QSerialPort) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QSerialPort::Directions) +Q_DECLARE_OPERATORS_FOR_FLAGS(QSerialPort::PinoutSignals) + +QT_END_NAMESPACE + +#endif // QSERIALPORT_H diff --git a/libs/serialport/qserialport.pri b/libs/serialport/qserialport.pri new file mode 100644 index 0000000000000000000000000000000000000000..9de6a7ab05f6d50072774e49bc7adb53c0609e04 --- /dev/null +++ b/libs/serialport/qserialport.pri @@ -0,0 +1,58 @@ +INCLUDEPATH += $$PWD + +unix { + CONFIG += link_pkgconfig + + packagesExist(libudev) { + DEFINES += HAVE_LIBUDEV + PKGCONFIG += libudev + } +} + +PUBLIC_HEADERS += \ + $$PWD/qserialportglobal.h \ + $$PWD/qserialport.h \ + $$PWD/qserialportinfo.h + +PRIVATE_HEADERS += \ + $$PWD/qserialport_p.h \ + $$PWD/qserialportinfo_p.h + +SOURCES += \ + $$PWD/qserialport.cpp \ + $$PWD/qserialportinfo.cpp + +win32 { + PRIVATE_HEADERS += \ + $$PWD/qserialport_win_p.h + + SOURCES += \ + $$PWD/qserialport_win.cpp \ + $$PWD/qserialportinfo_win.cpp + + LIBS += -lsetupapi -ladvapi32 + +} + +unix:!symbian { + PRIVATE_HEADERS += \ + $$PWD/qttylocker_unix_p.h \ + $$PWD/qserialport_unix_p.h + + SOURCES += \ + $$PWD/qttylocker_unix.cpp \ + $$PWD/qserialport_unix.cpp \ + $$PWD/qserialportinfo_unix.cpp + + macx { + SOURCES += $$PWD/qserialportinfo_mac.cpp + + LIBS += -framework IOKit -framework CoreFoundation + } else { + linux*:contains( DEFINES, HAVE_LIBUDEV ) { + LIBS += -ludev + } + } +} + +HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS diff --git a/libs/serialport/qserialport_p.h b/libs/serialport/qserialport_p.h new file mode 100644 index 0000000000000000000000000000000000000000..abd9cb633d5d4fec21196286fa4158695cfbb52a --- /dev/null +++ b/libs/serialport/qserialport_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2011-2012 Denis Shienkov +** Copyright (C) 2011 Sergey Belyashov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSERIALPORT_P_H +#define QSERIALPORT_P_H + +#include "qserialport.h" + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#else +#include "qt4support/qringbuffer_p.h" +#endif + +QT_BEGIN_NAMESPACE + +class QSerialPortPrivateData +{ + Q_DECLARE_PUBLIC(QSerialPort) +public: + enum IoConstants { + ReadChunkSize = 512, + WriteChunkSize = 512 + }; + + QSerialPortPrivateData(QSerialPort *q); + int timeoutValue(int msecs, int elapsed); + + qint64 readBufferMaxSize; + QRingBuffer readBuffer; + QRingBuffer writeBuffer; + QSerialPort::SerialPortError error; + QString systemLocation; + qint32 inputBaudRate; + qint32 outputBaudRate; + QSerialPort::DataBits dataBits; + QSerialPort::Parity parity; + QSerialPort::StopBits stopBits; + QSerialPort::FlowControl flow; + QSerialPort::DataErrorPolicy policy; + bool dataTerminalReady; + bool requestToSend; + bool settingsRestoredOnClose; + QSerialPort * const q_ptr; +}; + +QT_END_NAMESPACE + +#endif // QSERIALPORT_P_H diff --git a/libs/serialport/qserialport_symbian.cpp b/libs/serialport/qserialport_symbian.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2bba5a4d86c4ef90e52266cbf35a7ded003a82ae --- /dev/null +++ b/libs/serialport/qserialport_symbian.cpp @@ -0,0 +1,645 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialport_symbian_p.h" + +#include + +#include +//#include +#include + +QT_BEGIN_NAMESPACE + +// Physical device driver. +#ifdef __WINS__ +_LIT(KPddName, "ECDRV"); +#else // defined (__EPOC32__) +_LIT(KPddName, "EUART"); +#endif + +// Logical device driver. +_LIT(KLddName,"ECOMM"); + +// Modules names. +_LIT(KRS232ModuleName, "ECUART"); +_LIT(KBluetoothModuleName, "BTCOMM"); +_LIT(KInfraRedModuleName, "IRCOMM"); +_LIT(KACMModuleName, "ECACM"); + +// Return false on error load. +static bool loadDevices() +{ + TInt r = KErrNone; +#ifdef __WINS__ + RFs fileServer; + r = User::LeaveIfError(fileServer.Connect()); + if (r != KErrNone) + return false; + fileServer.Close (); +#endif + + r = User::LoadPhysicalDevice(KPddName); + if (r != KErrNone && r != KErrAlreadyExists) + return false; //User::Leave(r); + + r = User::LoadLogicalDevice(KLddName); + if (r != KErrNone && r != KErrAlreadyExists) + return false; //User::Leave(r); + +#ifndef __WINS__ + r = StartC32(); + if (r != KErrNone && r != KErrAlreadyExists) + return false; //User::Leave(r); +#endif + + return true; +} + +QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q) + : QSerialPortPrivateData(q) + , errnum(KErrNone) +{ +} + +bool QSerialPortPrivate::open(QIODevice::OpenMode mode) +{ + // FIXME: Maybe need added check an ReadWrite open mode? + Q_UNUSED(mode) + + if (!loadDevices()) { + q_ptr->setError(QSerialPort::UnknownError); + return false; + } + + RCommServ server; + errnum = server.Connect(); + if (errnum != KErrNone) { + q_ptr->setError(decodeSystemError()); + return false; + } + + if (systemLocation.contains("BTCOMM")) + errnum = server.LoadCommModule(KBluetoothModuleName); + else if (systemLocation.contains("IRCOMM")) + errnum = server.LoadCommModule(KInfraRedModuleName); + else if (systemLocation.contains("ACM")) + errnum = server.LoadCommModule(KACMModuleName); + else + errnum = server.LoadCommModule(KRS232ModuleName); + + if (errnum != KErrNone) { + q_ptr->setError(decodeSystemError()); + return false; + } + + // In Symbian OS port opening only in R/W mode? + TPtrC portName(static_cast(systemLocation.utf16()), systemLocation.length()); + errnum = descriptor.Open(server, portName, ECommExclusive); + + if (errnum != KErrNone) { + q_ptr->setError(decodeSystemError()); + return false; + } + + // Save current port settings. + errnum = descriptor.Config(restoredSettings); + if (errnum != KErrNone) { + q_ptr->setError(decodeSystemError()); + return false; + } + + detectDefaultSettings(); + return true; +} + +void QSerialPortPrivate::close() +{ + if (settingsRestoredOnClose) + descriptor.SetConfig(restoredSettings); + descriptor.Close(); +} + +QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() const +{ + QSerialPort::PinoutSignals ret = QSerialPort::NoSignal; + + TUint signalMask = 0; + descriptor.Signals(signalMask); + + if (signalMask & KSignalCTS) + ret |= QSerialPort::ClearToSendSignal; + if (signalMask & KSignalDSR) + ret |= QSerialPort::DataSetReadySignal; + if (signalMask & KSignalDCD) + ret |= QSerialPort::DataCarrierDetectSignal; + if (signalMask & KSignalRNG) + ret |= QSerialPort::RingIndicatorSignal; + if (signalMask & KSignalRTS) + ret |= QSerialPort::RequestToSendSignal; + if (signalMask & KSignalDTR) + ret |= QSerialPort::DataTerminalReadySignal; + + //if (signalMask & KSignalBreak) + // ret |= + return ret; +} + +bool QSerialPortPrivate::setDataTerminalReady(bool set) +{ + TInt r; + if (set) + r = descriptor.SetSignalsToMark(KSignalDTR); + else + r = descriptor.SetSignalsToSpace(KSignalDTR); + + return r == KErrNone; +} + +bool QSerialPortPrivate::setRequestToSend(bool set) +{ + TInt r; + if (set) + r = descriptor.SetSignalsToMark(KSignalRTS); + else + r = descriptor.SetSignalsToSpace(KSignalRTS); + + return r == KErrNone; +} + +bool QSerialPortPrivate::flush() +{ + // TODO: Implement me + return false; +} + +bool QSerialPortPrivate::clear(QSerialPort::Directions dir) +{ + TUint flags = 0; + if (dir & QSerialPort::Input) + flags |= KCommResetRx; + if (dir & QSerialPort::Output) + flags |= KCommResetTx; + TInt r = descriptor.ResetBuffers(flags); + return r == KErrNone; +} + +bool QSerialPortPrivate::sendBreak(int duration) +{ + TRequestStatus status; + descriptor.Break(status, TTimeIntervalMicroSeconds32(duration * 1000)); + return false; +} + +bool QSerialPortPrivate::setBreakEnabled(bool set) +{ + // TODO: Implement me + return false; +} + +qint64 QSerialPortPrivate::systemInputQueueSize () const +{ + return descriptor.QueryReceiveBuffer(); +} + +qint64 QSerialPortPrivate::systemOutputQueueSize () const +{ + // TODO: Implement me + return 0; +} + +qint64 QSerialPortPrivate::bytesAvailable() const +{ + return readBuffer.size(); +} + +qint64 QSerialPortPrivate::readFromBuffer(char *data, qint64 maxSize) +{ + // TODO: Implement me + return -1; +} + +qint64 QSerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize) +{ + // TODO: Implement me + return -1; +} + +bool QSerialPortPrivate::waitForReadyRead(int msec) +{ + // TODO: Implement me + return false; +} + +bool QSerialPortPrivate::waitForBytesWritten(int msec) +{ + // TODO: Implement me + return false; +} + +bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions dir) +{ + if (dir != QSerialPort::AllDirections) { + q_ptr->setError(QSerialPort::UnsupportedOperationError); + return false; + } + + baudRate = settingFromBaudRate(baudRate); + if (baudRate) + currentSettings().iRate = static_cast(baudRate); + else { + q_ptr->setError(QSerialPort::UnsupportedOperationError); + return false; + } + + return updateCommConfig(); +} + +bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits) +{ + switch (dataBits) { + case QSerialPort::Data5: + currentSettings().iDataBits = EData5; + break; + case QSerialPort::Data6: + currentSettings().iDataBits = EData6; + break; + case QSerialPort::Data7: + currentSettings().iDataBits = EData7; + break; + case QSerialPort::Data8: + currentSettings().iDataBits = EData8; + break; + default: + currentSettings().iDataBits = EData8; + break; + } + + return updateCommConfig(); +} + +bool QSerialPortPrivate::setParity(QSerialPort::Parity parity) +{ + switch (parity) { + case QSerialPort::NoParity: + currentSettings().iParity = EParityNone; + break; + case QSerialPort::EvenParity: + currentSettings().iParity = EParityEven; + break; + case QSerialPort::OddParity: + currentSettings().iParity = EParityOdd; + break; + case QSerialPort::MarkParity: + currentSettings().iParity = EParityMark; + break; + case QSerialPort::SpaceParity: + currentSettings().iParity = EParitySpace; + break; + default: + currentSettings().iParity = EParityNone; + break; + } + + return updateCommConfig(); +} + +bool QSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits) +{ + switch (stopBits) { + case QSerialPort::OneStop: + currentSettings().iStopBits = EStop1; + break; + case QSerialPort::TwoStop: + currentSettings().iStopBits = EStop2; + break; + default: + currentSettings().iStopBits = EStop1; + break; + } + + return updateCommConfig(); +} + +bool QSerialPortPrivate::setFlowControl(QSerialPort::FlowControl flow) +{ + switch (flow) { + case QSerialPort::NoFlowControl: + currentSettings().iHandshake = KConfigFailDSR; + break; + case QSerialPort::HardwareControl: + currentSettings().iHandshake = KConfigObeyCTS | KConfigFreeRTS; + break; + case QSerialPort::SoftwareControl: + currentSettings().iHandshake = KConfigObeyXoff | KConfigSendXoff; + break; + default: + currentSettings().iHandshake = KConfigFailDSR; + break; + } + + return updateCommConfig(); +} + +bool QSerialPortPrivate::setDataErrorPolicy(QSerialPort::DataErrorPolicy policy) +{ + // TODO: Implement me + return false; +} + +bool QSerialPortPrivate::notifyRead() +{ + // TODO: Implement me + return false; +} + +bool QSerialPortPrivate::notifyWrite() +{ + // TODO: Implement me + return false; +} + +bool QSerialPortPrivate::updateCommConfig() +{ + if (descriptor.SetConfig(currentSettings) != KErrNone) { + q_ptr->setError(QSerialPort::UnsupportedOperationError); + return false; + } + return true; +} + +void QSerialPortPrivate::detectDefaultSettings() +{ + // Detect baud rate. + inputBaudRate = baudRateFromSetting(currentSettings().iRate); + outputBaudRate = inputBaudRate; + + // Detect databits. + switch (currentSettings().iDataBits) { + case EData5: + dataBits = QSerialPort::Data5; + break; + case EData6: + dataBits = QSerialPort::Data6; + break; + case EData7: + dataBits = QSerialPort::Data7; + break; + case EData8: + dataBits = QSerialPort::Data8; + break; + default: + dataBits = QSerialPort::UnknownDataBits; + break; + } + + // Detect parity. + switch (currentSettings().iParity) { + case EParityNone: + parity = QSerialPort::NoParity; + break; + case EParityEven: + parity = QSerialPort::EvenParity; + break; + case EParityOdd: + parity = QSerialPort::OddParity; + break; + case EParityMark: + parity = QSerialPort::MarkParity; + break; + case EParitySpace: + parity = QSerialPort::SpaceParity; + break; + default: + parity = QSerialPort::UnknownParity; + break; + } + + // Detect stopbits. + switch (currentSettings().iStopBits) { + case EStop1: + stopBits = QSerialPort::OneStop; + break; + case EStop2: + stopBits = QSerialPort::TwoStop; + break; + default: + stopBits = QSerialPort::UnknownStopBits; + break; + } + + // Detect flow control. + if ((currentSettings().iHandshake & (KConfigObeyXoff | KConfigSendXoff)) + == (KConfigObeyXoff | KConfigSendXoff)) + flow = QSerialPort::SoftwareControl; + else if ((currentSettings().iHandshake & (KConfigObeyCTS | KConfigFreeRTS)) + == (KConfigObeyCTS | KConfigFreeRTS)) + flow = QSerialPort::HardwareControl; + else if (currentSettings().iHandshake & KConfigFailDSR) + flow = QSerialPort::NoFlowControl; + else + flow = QSerialPort::UnknownFlowControl; +} + +QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const +{ + QSerialPort::SerialPortError error; + switch (errnum) { + case KErrPermissionDenied: + error = QSerialPort::DeviceNotFoundError; + break; + case KErrLocked: + error = QSerialPort::PermissionError; + break; + case KErrAccessDenied: + error = QSerialPort::PermissionError; + break; + default: + error = QSerialPort::UnknownError; + break; + } + return error; +} + +bool QSerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectForWrite, + bool checkRead, bool checkWrite, + int msecs, bool *timedOut) +{ + + // FIXME: I'm not sure in implementation this method. + // Someone needs to check and correct. + + TRequestStatus timerStatus; + TRequestStatus readStatus; + TRequestStatus writeStatus; + + if (msecs > 0) { + if (!selectTimer.Handle()) { + if (selectTimer.CreateLocal() != KErrNone) + return false; + } + selectTimer.HighRes(timerStatus, msecs * 1000); + } + + if (checkRead) + descriptor.NotifyDataAvailable(readStatus); + + if (checkWrite) + descriptor.NotifyOutputEmpty(writeStatus); + + enum { STATUSES_COUNT = 3 }; + TRequestStatus *statuses[STATUSES_COUNT]; + TInt num = 0; + statuses[num++] = &timerStatus; + statuses[num++] = &readStatus; + statuses[num++] = &writeStatus; + + User::WaitForNRequest(statuses, num); + + bool result = false; + + // By timeout? + if (timerStatus != KRequestPending) { + Q_ASSERT(selectForRead); + *selectForRead = false; + Q_ASSERT(selectForWrite); + *selectForWrite = false; + } else { + selectTimer.Cancel(); + User::WaitForRequest(timerStatus); + + // By read? + if (readStatus != KRequestPending) { + Q_ASSERT(selectForRead); + *selectForRead = true; + } + + // By write? + if (writeStatus != KRequestPending) { + Q_ASSERT(selectForWrite); + *selectForWrite = true; + } + + if (checkRead) + descriptor.NotifyDataAvailableCancel(); + if (checkWrite) + descriptor.NotifyOutputEmptyCancel(); + + result = true; + } + return result; +} + +QString QSerialPortPrivate::portNameToSystemLocation(const QString &port) +{ + // Port name is equval to port systemLocation. + return port; +} + +QString QSerialPortPrivate::portNameFromSystemLocation(const QString &location) +{ + // Port name is equval to port systemLocation. + return location; +} + +typedef QMap BaudRateMap; + +// This table contains correspondences standard pairs values of +// baud rates that are defined in files +// - d32comm.h for Symbian^3 +// - d32public.h for Symbian SR1 + +static const BaudRateMap createStandardBaudRateMap() +{ + BaudRateMap baudRateMap; + + baudRateMap.insert(50, EBps50) + baudRateMap.insert(75, EBps75) + baudRateMap.insert(110, EBps110) + baudRateMap.insert(134, EBps134) + baudRateMap.insert(150, EBps150) + baudRateMap.insert(300, EBps300) + baudRateMap.insert(600, EBps600) + baudRateMap.insert(1200, EBps1200) + baudRateMap.insert(1800, EBps1800) + baudRateMap.insert(2000, EBps2000) + baudRateMap.insert(2400, EBps2400) + baudRateMap.insert(3600, EBps3600) + baudRateMap.insert(4800, EBps4800) + baudRateMap.insert(7200, EBps7200) + baudRateMap.insert(9600, EBps9600) + baudRateMap.insert(19200, EBps19200) + baudRateMap.insert(38400, EBps38400) + baudRateMap.insert(57600, EBps57600) + baudRateMap.insert(115200, EBps115200) + baudRateMap.insert(230400, EBps230400) + baudRateMap.insert(460800, EBps460800) + baudRateMap.insert(576000, EBps576000) + baudRateMap.insert(921600, EBps921600) + baudRateMap.insert(1152000, EBps1152000) + // << baudRateMap.insert(1843200, EBps1843200) only for Symbian SR1 + baudRateMap.insert(4000000, EBps4000000); + + return baudRateMap; +} + +static const BaudRateMap& standardBaudRateMap() +{ + static const BaudRateMap baudRateMap = createStandardBaudRateMap(); + return baudRateMap; +} + +qint32 QSerialPortPrivate::baudRateFromSetting(qint32 setting) +{ + return standardBaudRateMap().key(setting); +} + +qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate) +{ + return standardBaudRateMap().value(baudRate); +} + +QList QSerialPortPrivate::standardBaudRates() +{ + return standardBaudRateMap().keys(); +} + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialport_symbian_p.h b/libs/serialport/qserialport_symbian_p.h new file mode 100644 index 0000000000000000000000000000000000000000..7f9eaddd3eff92081ec11aef4815498623f76c89 --- /dev/null +++ b/libs/serialport/qserialport_symbian_p.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSERIALPORT_SYMBIAN_P_H +#define QSERIALPORT_SYMBIAN_P_H + +#include "qserialport_p.h" + +#include + +QT_BEGIN_NAMESPACE + +class QSerialPortPrivate : public QSerialPortPrivateData +{ +public: + QSerialPortPrivate(QSerialPort *q); + + bool open(QIODevice::OpenMode mode); + void close(); + + QSerialPort::PinoutSignals pinoutSignals() const; + + bool setDataTerminalReady(bool set); + bool setRequestToSend(bool set); + + bool flush(); + bool clear(QSerialPort::Directions dir); + + bool sendBreak(int duration); + bool setBreakEnabled(bool set); + + qint64 systemInputQueueSize () const; + qint64 systemOutputQueueSize () const; + + qint64 bytesAvailable() const; + + qint64 readFromBuffer(char *data, qint64 maxSize); + qint64 writeToBuffer(const char *data, qint64 maxSize); + + bool waitForReadyRead(int msec); + bool waitForBytesWritten(int msec); + + bool setBaudRate(qint32 baudRate, QSerialPort::Directions dir); + bool setDataBits(QSerialPort::DataBits dataBits); + bool setParity(QSerialPort::Parity parity); + bool setStopBits(QSerialPort::StopBits stopBits); + bool setFlowControl(QSerialPort::FlowControl flowControl); + bool setDataErrorPolicy(QSerialPort::DataErrorPolicy policy); + + bool notifyRead(); + bool notifyWrite(); + + static QString portNameToSystemLocation(const QString &port); + static QString portNameFromSystemLocation(const QString &location); + + static qint32 baudRateFromSetting(qint32 setting); + static qint32 settingFromBaudRate(qint32 baudRate); + + static QList standardBaudRates(); + + TCommConfig currentSettings; + TCommConfig restoredSettings; + RComm descriptor; + mutable RTimer selectTimer; + TInt errnum; + +private: + bool updateCommConfig(); + + void detectDefaultSettings(); + QSerialPort::SerialPortError decodeSystemError() const; + + bool waitForReadOrWrite(bool *selectForRead, bool *selectForWrite, + bool checkRead, bool checkWrite, + int msecs, bool *timedOut); +}; + +QT_END_NAMESPACE + +#endif // QSERIALPORT_SYMBIAN_P_H diff --git a/libs/serialport/qserialport_unix.cpp b/libs/serialport/qserialport_unix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2f6c8ccbafa734f578db1aca5a6abfeedfbbb9a8 --- /dev/null +++ b/libs/serialport/qserialport_unix.cpp @@ -0,0 +1,1343 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Copyright (C) 2012 Andre Hartmann +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialport_unix_p.h" +#include "qttylocker_unix_p.h" + +#include +#include +#include +#include +#include + +#ifdef Q_OS_MAC +#if defined (MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4) +#include +#endif +#endif + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class ReadNotifier : public QSocketNotifier +{ +public: + ReadNotifier(QSerialPortPrivate *d, QObject *parent) + : QSocketNotifier(d->descriptor, QSocketNotifier::Read, parent) + , dptr(d) + {} + +protected: + bool event(QEvent *e) Q_DECL_OVERRIDE { + bool ret = QSocketNotifier::event(e); + if (ret) + dptr->readNotification(); + return ret; + } + +private: + QSerialPortPrivate *dptr; +}; + +class WriteNotifier : public QSocketNotifier +{ +public: + WriteNotifier(QSerialPortPrivate *d, QObject *parent) + : QSocketNotifier(d->descriptor, QSocketNotifier::Write, parent) + , dptr(d) + {} + +protected: + bool event(QEvent *e) Q_DECL_OVERRIDE { + bool ret = QSocketNotifier::event(e); + if (ret) + dptr->writeNotification(QSerialPortPrivateData::WriteChunkSize); + return ret; + } + +private: + QSerialPortPrivate *dptr; +}; + +class ExceptionNotifier : public QSocketNotifier +{ +public: + ExceptionNotifier(QSerialPortPrivate *d, QObject *parent) + : QSocketNotifier(d->descriptor, QSocketNotifier::Exception, parent) + , dptr(d) + {} + +protected: + bool event(QEvent *e) Q_DECL_OVERRIDE { + bool ret = QSocketNotifier::event(e); + if (ret) + dptr->exceptionNotification(); + return ret; + } + +private: + QSerialPortPrivate *dptr; +}; + +QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q) + : QSerialPortPrivateData(q) + , descriptor(-1) + , isCustomBaudRateSupported(false) + , readNotifier(0) + , writeNotifier(0) + , exceptionNotifier(0) + , readPortNotifierCalled(false) + , readPortNotifierState(false) + , readPortNotifierStateSet(false) + , emittedReadyRead(false) + , emittedBytesWritten(false) +{ +} + +bool QSerialPortPrivate::open(QIODevice::OpenMode mode) +{ + QByteArray portName = portNameFromSystemLocation(systemLocation).toLocal8Bit(); + const char *ptr = portName.constData(); + + bool byCurrPid = false; + if (QTtyLocker::isLocked(ptr, &byCurrPid)) { + q_ptr->setError(QSerialPort::PermissionError); + return false; + } + + int flags = O_NOCTTY | O_NONBLOCK; + + switch (mode & QIODevice::ReadWrite) { + case QIODevice::WriteOnly: + flags |= O_WRONLY; + break; + case QIODevice::ReadWrite: + flags |= O_RDWR; + break; + default: + flags |= O_RDONLY; + break; + } + + descriptor = ::open(systemLocation.toLocal8Bit().constData(), flags); + + if (descriptor == -1) { + q_ptr->setError(decodeSystemError()); + return false; + } + + ::fcntl(descriptor, F_SETFL, FNDELAY); + + QTtyLocker::lock(ptr); + if (!QTtyLocker::isLocked(ptr, &byCurrPid)) { + q_ptr->setError(QSerialPort::PermissionError); + return false; + } + +#ifdef TIOCEXCL + ::ioctl(descriptor, TIOCEXCL); +#endif + + if (::tcgetattr(descriptor, &restoredTermios) == -1) { + q_ptr->setError(decodeSystemError()); + return false; + } + + currentTermios = restoredTermios; + ::cfmakeraw(¤tTermios); + currentTermios.c_cflag |= CLOCAL; + currentTermios.c_cc[VTIME] = 0; + currentTermios.c_cc[VMIN] = 0; + + if (mode & QIODevice::ReadOnly) + currentTermios.c_cflag |= CREAD; + + if (!updateTermios()) + return false; + + setExceptionNotificationEnabled(true); + + if ((flags & O_WRONLY) == 0) + setReadNotificationEnabled(true); + + detectDefaultSettings(); + return true; +} + +void QSerialPortPrivate::close() +{ + if (settingsRestoredOnClose) { + ::tcsetattr(descriptor, TCSANOW, &restoredTermios); +#ifdef Q_OS_LINUX + if (isCustomBaudRateSupported) + ::ioctl(descriptor, TIOCSSERIAL, &restoredSerialInfo); +#endif + } + +#ifdef TIOCNXCL + ::ioctl(descriptor, TIOCNXCL); +#endif + + if (readNotifier) { + readNotifier->setEnabled(false); + readNotifier->deleteLater(); + readNotifier = 0; + } + + if (writeNotifier) { + writeNotifier->setEnabled(false); + writeNotifier->deleteLater(); + writeNotifier = 0; + } + + if (exceptionNotifier) { + exceptionNotifier->setEnabled(false); + exceptionNotifier->deleteLater(); + exceptionNotifier = 0; + } + + ::close(descriptor); + + QByteArray portName = portNameFromSystemLocation(systemLocation).toLocal8Bit(); + const char *ptr = portName.constData(); + + bool byCurrPid = false; + if (QTtyLocker::isLocked(ptr, &byCurrPid) && byCurrPid) + QTtyLocker::unlock(ptr); + + descriptor = -1; + isCustomBaudRateSupported = false; +} + +QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() const +{ + int arg = 0; + QSerialPort::PinoutSignals ret = QSerialPort::NoSignal; + + if (::ioctl(descriptor, TIOCMGET, &arg) == -1) { + q_ptr->setError(decodeSystemError()); + return ret; + } + +#ifdef TIOCM_LE + if (arg & TIOCM_LE) + ret |= QSerialPort::DataSetReadySignal; +#endif +#ifdef TIOCM_DTR + if (arg & TIOCM_DTR) + ret |= QSerialPort::DataTerminalReadySignal; +#endif +#ifdef TIOCM_RTS + if (arg & TIOCM_RTS) + ret |= QSerialPort::RequestToSendSignal; +#endif +#ifdef TIOCM_ST + if (arg & TIOCM_ST) + ret |= QSerialPort::SecondaryTransmittedDataSignal; +#endif +#ifdef TIOCM_SR + if (arg & TIOCM_SR) + ret |= QSerialPort::SecondaryReceivedDataSignal; +#endif +#ifdef TIOCM_CTS + if (arg & TIOCM_CTS) + ret |= QSerialPort::ClearToSendSignal; +#endif +#ifdef TIOCM_CAR + if (arg & TIOCM_CAR) + ret |= QSerialPort::DataCarrierDetectSignal; +#elif defined TIOCM_CD + if (arg & TIOCM_CD) + ret |= QSerialPort::DataCarrierDetectSignal; +#endif +#ifdef TIOCM_RNG + if (arg & TIOCM_RNG) + ret |= QSerialPort::RingIndicatorSignal; +#elif defined TIOCM_RI + if (arg & TIOCM_RI) + ret |= QSerialPort::RingIndicatorSignal; +#endif +#ifdef TIOCM_DSR + if (arg & TIOCM_DSR) + ret |= QSerialPort::DataSetReadySignal; +#endif + + return ret; +} + +bool QSerialPortPrivate::setDataTerminalReady(bool set) +{ + int status = TIOCM_DTR; + return ::ioctl(descriptor, set ? TIOCMBIS : TIOCMBIC, &status) != -1; +} + +bool QSerialPortPrivate::setRequestToSend(bool set) +{ + int status = TIOCM_RTS; + return ::ioctl(descriptor, set ? TIOCMBIS : TIOCMBIC, &status) != -1; +} + +bool QSerialPortPrivate::flush() +{ + return writeNotification() && (::tcdrain(descriptor) != -1); +} + +bool QSerialPortPrivate::clear(QSerialPort::Directions dir) +{ + return ::tcflush(descriptor, (dir == QSerialPort::AllDirections) + ? TCIOFLUSH : (dir & QSerialPort::Input) ? TCIFLUSH : TCOFLUSH) != -1; +} + +bool QSerialPortPrivate::sendBreak(int duration) +{ + return ::tcsendbreak(descriptor, duration) != -1; +} + +bool QSerialPortPrivate::setBreakEnabled(bool set) +{ + return ::ioctl(descriptor, set ? TIOCSBRK : TIOCCBRK) != -1; +} + +qint64 QSerialPortPrivate::systemInputQueueSize () const +{ + int nbytes = 0; +#ifdef TIOCINQ + if (::ioctl(descriptor, TIOCINQ, &nbytes) == -1) + return -1; +#endif + return nbytes; +} + +qint64 QSerialPortPrivate::systemOutputQueueSize () const +{ + int nbytes = 0; +#ifdef TIOCOUTQ + if (::ioctl(descriptor, TIOCOUTQ, &nbytes) == -1) + return -1; +#endif + return nbytes; +} + +qint64 QSerialPortPrivate::bytesAvailable() const +{ + return readBuffer.size(); +} + +qint64 QSerialPortPrivate::readFromBuffer(char *data, qint64 maxSize) +{ + if (readBuffer.isEmpty()) + return 0; + + if (maxSize == 1) { + *data = readBuffer.getChar(); + if (readBuffer.isEmpty()) + setReadNotificationEnabled(true); + return 1; + } + + const qint64 bytesToRead = qMin(qint64(readBuffer.size()), maxSize); + qint64 readSoFar = 0; + while (readSoFar < bytesToRead) { + const char *ptr = readBuffer.readPointer(); + const int bytesToReadFromThisBlock = qMin(int(bytesToRead - readSoFar), + readBuffer.nextDataBlockSize()); + ::memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock); + readSoFar += bytesToReadFromThisBlock; + readBuffer.free(bytesToReadFromThisBlock); + } + + if (!isReadNotificationEnabled()) + setReadNotificationEnabled(true); + + if (readSoFar > 0) { + if (readBuffer.isEmpty()) + setReadNotificationEnabled(true); + return readSoFar; + } + + return readSoFar; +} + +qint64 QSerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize) +{ + char *ptr = writeBuffer.reserve(maxSize); + if (maxSize == 1) + *ptr = *data; + else + ::memcpy(ptr, data, maxSize); + + const qint64 written = maxSize; + + if (!writeBuffer.isEmpty() && !isWriteNotificationEnabled()) + setWriteNotificationEnabled(true); + + return written; +} + +bool QSerialPortPrivate::waitForReadyRead(int msecs) +{ + QElapsedTimer stopWatch; + + stopWatch.start(); + + do { + bool readyToRead = false; + bool readyToWrite = false; + bool timedOut = false; + if (!waitForReadOrWrite(&readyToRead, &readyToWrite, true, !writeBuffer.isEmpty(), + timeoutValue(msecs, stopWatch.elapsed()), &timedOut)) { + q_ptr->setError(decodeSystemError()); + return false; + } + + if (readyToRead) { + if (readNotification()) + return true; + } + + if (readyToWrite) + writeNotification(WriteChunkSize); + + } while (msecs == -1 || timeoutValue(msecs, stopWatch.elapsed()) > 0); + return false; +} + +bool QSerialPortPrivate::waitForBytesWritten(int msecs) +{ + if (writeBuffer.isEmpty()) + return false; + + QElapsedTimer stopWatch; + + stopWatch.start(); + + forever { + bool readyToRead = false; + bool readyToWrite = false; + bool timedOut = false; + if (!waitForReadOrWrite(&readyToRead, &readyToWrite, true, !writeBuffer.isEmpty(), + timeoutValue(msecs, stopWatch.elapsed()), &timedOut)) { + q_ptr->setError(decodeSystemError()); + return false; + } + + if (readyToRead && !readNotification()) + return false; + + if (readyToWrite) + return writeNotification(WriteChunkSize); + } + return false; +} + +bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions dir) +{ + bool ret = baudRate > 0; + + // prepare section + + if (ret) { + const qint32 unixBaudRate = QSerialPortPrivate::settingFromBaudRate(baudRate); + if (unixBaudRate > 0) { + // try prepate to set standard baud rate +#ifdef Q_OS_LINUX + // prepare to forcefully reset the custom mode + if (isCustomBaudRateSupported) { + //currentSerialInfo.flags |= ASYNC_SPD_MASK; + currentSerialInfo.flags &= ~(ASYNC_SPD_CUST /* | ASYNC_LOW_LATENCY*/); + currentSerialInfo.custom_divisor = 0; + } +#endif + // prepare to set standard baud rate + ret = !(((dir & QSerialPort::Input) && ::cfsetispeed(¤tTermios, unixBaudRate) < 0) + || ((dir & QSerialPort::Output) && ::cfsetospeed(¤tTermios, unixBaudRate) < 0)); + } else { + // try prepate to set custom baud rate +#ifdef Q_OS_LINUX + // prepare to forcefully set the custom mode + if (isCustomBaudRateSupported) { + currentSerialInfo.flags &= ~ASYNC_SPD_MASK; + currentSerialInfo.flags |= (ASYNC_SPD_CUST /* | ASYNC_LOW_LATENCY*/); + currentSerialInfo.custom_divisor = currentSerialInfo.baud_base / baudRate; + if (currentSerialInfo.custom_divisor == 0) + currentSerialInfo.custom_divisor = 1; + // for custom mode needed prepare to set B38400 baud rate + ret = (::cfsetspeed(¤tTermios, B38400) != -1); + } else { + ret = false; + } +#elif defined(Q_OS_MAC) + +# if defined (MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4) + // Starting with Tiger, the IOSSIOSPEED ioctl can be used to set arbitrary baud rates + // other than those specified by POSIX. The driver for the underlying serial hardware + // ultimately determines which baud rates can be used. This ioctl sets both the input + // and output speed. + ret = ::ioctl(descriptor, IOSSIOSPEED, &baudRate) != -1; +# else + // others MacOSX version, can't prepare to set custom baud rate + ret = false; +# endif + +#else + // others *nix OS, can't prepare to set custom baud rate + ret = false; +#endif + } + } + + // finally section + +#ifdef Q_OS_LINUX + if (ret && isCustomBaudRateSupported) // finally, set or reset the custom mode + ret = ::ioctl(descriptor, TIOCSSERIAL, ¤tSerialInfo) != -1; +#endif + + if (ret) // finally, set baud rate + ret = updateTermios(); + else + q_ptr->setError(decodeSystemError()); + return ret; +} + +bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits) +{ + currentTermios.c_cflag &= ~CSIZE; + switch (dataBits) { + case QSerialPort::Data5: + currentTermios.c_cflag |= CS5; + break; + case QSerialPort::Data6: + currentTermios.c_cflag |= CS6; + break; + case QSerialPort::Data7: + currentTermios.c_cflag |= CS7; + break; + case QSerialPort::Data8: + currentTermios.c_cflag |= CS8; + break; + default: + currentTermios.c_cflag |= CS8; + break; + } + return updateTermios(); +} + +bool QSerialPortPrivate::setParity(QSerialPort::Parity parity) +{ + currentTermios.c_iflag &= ~(PARMRK | INPCK); + currentTermios.c_iflag |= IGNPAR; + + switch (parity) { + +#ifdef CMSPAR + // Here Installation parity only for GNU/Linux where the macro CMSPAR. + case QSerialPort::SpaceParity: + currentTermios.c_cflag &= ~PARODD; + currentTermios.c_cflag |= PARENB | CMSPAR; + break; + case QSerialPort::MarkParity: + currentTermios.c_cflag |= PARENB | CMSPAR | PARODD; + break; +#endif + case QSerialPort::NoParity: + currentTermios.c_cflag &= ~PARENB; + break; + case QSerialPort::EvenParity: + currentTermios.c_cflag &= ~PARODD; + currentTermios.c_cflag |= PARENB; + break; + case QSerialPort::OddParity: + currentTermios.c_cflag |= PARENB | PARODD; + break; + default: + currentTermios.c_cflag |= PARENB; + currentTermios.c_iflag |= PARMRK | INPCK; + currentTermios.c_iflag &= ~IGNPAR; + break; + } + + return updateTermios(); +} + +bool QSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits) +{ + switch (stopBits) { + case QSerialPort::OneStop: + currentTermios.c_cflag &= ~CSTOPB; + break; + case QSerialPort::TwoStop: + currentTermios.c_cflag |= CSTOPB; + break; + default: + currentTermios.c_cflag &= ~CSTOPB; + break; + } + return updateTermios(); +} + +bool QSerialPortPrivate::setFlowControl(QSerialPort::FlowControl flow) +{ + switch (flow) { + case QSerialPort::NoFlowControl: + currentTermios.c_cflag &= ~CRTSCTS; + currentTermios.c_iflag &= ~(IXON | IXOFF | IXANY); + break; + case QSerialPort::HardwareControl: + currentTermios.c_cflag |= CRTSCTS; + currentTermios.c_iflag &= ~(IXON | IXOFF | IXANY); + break; + case QSerialPort::SoftwareControl: + currentTermios.c_cflag &= ~CRTSCTS; + currentTermios.c_iflag |= IXON | IXOFF | IXANY; + break; + default: + currentTermios.c_cflag &= ~CRTSCTS; + currentTermios.c_iflag &= ~(IXON | IXOFF | IXANY); + break; + } + return updateTermios(); +} + +bool QSerialPortPrivate::setDataErrorPolicy(QSerialPort::DataErrorPolicy policy) +{ + tcflag_t parmrkMask = PARMRK; +#ifndef CMSPAR + // in space/mark parity emulation also used PARMRK flag + if (parity == QSerialPort::SpaceParity + || parity == QSerialPort::MarkParity) { + parmrkMask = 0; + } +#endif //CMSPAR + switch (policy) { + case QSerialPort::SkipPolicy: + currentTermios.c_iflag &= ~parmrkMask; + currentTermios.c_iflag |= IGNPAR | INPCK; + break; + case QSerialPort::PassZeroPolicy: + currentTermios.c_iflag &= ~(IGNPAR | parmrkMask); + currentTermios.c_iflag |= INPCK; + break; + case QSerialPort::IgnorePolicy: + currentTermios.c_iflag &= ~INPCK; + break; + case QSerialPort::StopReceivingPolicy: + currentTermios.c_iflag &= ~IGNPAR; + currentTermios.c_iflag |= parmrkMask | INPCK; + break; + default: + currentTermios.c_iflag &= ~INPCK; + break; + } + return updateTermios(); +} + +bool QSerialPortPrivate::readNotification() +{ + // Prevent recursive calls + if (readPortNotifierCalled) { + if (!readPortNotifierStateSet) { + readPortNotifierStateSet = true; + readPortNotifierState = isReadNotificationEnabled(); + setReadNotificationEnabled(false); + } + } + + readPortNotifierCalled = true; + + // Always buffered, read data from the port into the read buffer + qint64 newBytes = readBuffer.size(); + qint64 bytesToRead = policy == QSerialPort::IgnorePolicy ? ReadChunkSize : 1; + + if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) { + bytesToRead = readBufferMaxSize - readBuffer.size(); + if (bytesToRead == 0) { + // Buffer is full. User must read data from the buffer + // before we can read more from the port. + return false; + } + } + + char *ptr = readBuffer.reserve(bytesToRead); + const qint64 readBytes = readFromPort(ptr, bytesToRead); + + if (readBytes <= 0) { + readBuffer.chop(bytesToRead); + return false; + } + + readBuffer.chop(bytesToRead - qMax(readBytes, qint64(0))); + + newBytes = readBuffer.size() - newBytes; + + // If read buffer is full, disable the read port notifier. + if (readBufferMaxSize && readBuffer.size() == readBufferMaxSize) + setReadNotificationEnabled(false); + + // only emit readyRead() when not recursing, and only if there is data available + const bool hasData = newBytes > 0; + + if (!emittedReadyRead && hasData) { + emittedReadyRead = true; + emit q_ptr->readyRead(); + emittedReadyRead = false; + } + + if (!hasData) + setReadNotificationEnabled(true); + + // reset the read port notifier state if we reentered inside the + // readyRead() connected slot. + if (readPortNotifierStateSet + && readPortNotifierState != isReadNotificationEnabled()) { + setReadNotificationEnabled(readPortNotifierState); + readPortNotifierStateSet = false; + } + return true; +} + +bool QSerialPortPrivate::writeNotification(int maxSize) +{ + const int tmp = writeBuffer.size(); + + if (writeBuffer.isEmpty()) { + setWriteNotificationEnabled(false); + return false; + } + + int nextSize = qMin(writeBuffer.nextDataBlockSize(), maxSize); + + const char *ptr = writeBuffer.readPointer(); + + // Attempt to write it chunk. + qint64 written = writeToPort(ptr, nextSize); + if (written < 0) + return false; + + // Remove what we wrote so far. + writeBuffer.free(written); + if (written > 0) { + // Don't emit bytesWritten() recursively. + if (!emittedBytesWritten) { + emittedBytesWritten = true; + emit q_ptr->bytesWritten(written); + emittedBytesWritten = false; + } + } + + if (writeBuffer.isEmpty()) + setWriteNotificationEnabled(false); + + return (writeBuffer.size() < tmp); +} + +bool QSerialPortPrivate::exceptionNotification() +{ + QSerialPort::SerialPortError error = decodeSystemError(); + q_ptr->setError(error); + + return true; +} + +bool QSerialPortPrivate::updateTermios() +{ + if (::tcsetattr(descriptor, TCSANOW, ¤tTermios) == -1) { + q_ptr->setError(decodeSystemError()); + return false; + } + return true; +} + +void QSerialPortPrivate::detectDefaultSettings() +{ + // Detect baud rate. + const speed_t inputUnixBaudRate = ::cfgetispeed(¤tTermios); + const speed_t outputUnixBaudRate = ::cfgetospeed(¤tTermios); + bool isCustomBaudRateCurrentSet = false; + +#ifdef Q_OS_LINUX + // try detect the ability to support custom baud rate + isCustomBaudRateSupported = ::ioctl(descriptor, TIOCGSERIAL, ¤tSerialInfo) != -1 + && ::ioctl(descriptor, TIOCSSERIAL, ¤tSerialInfo) != -1; + + if (isCustomBaudRateSupported) { + restoredSerialInfo = currentSerialInfo; + + // assume that the baud rate is a custom + isCustomBaudRateCurrentSet = inputUnixBaudRate == B38400 && outputUnixBaudRate == B38400; + + if (isCustomBaudRateCurrentSet) { + if ((currentSerialInfo.flags & ASYNC_SPD_CUST) + && currentSerialInfo.custom_divisor > 0) { + + // yes, speed is really custom + inputBaudRate = currentSerialInfo.baud_base / currentSerialInfo.custom_divisor; + outputBaudRate = inputBaudRate; + } else { + // no, we were wrong and the speed is a standard 38400 baud + isCustomBaudRateCurrentSet = false; + } + } + } +#else + // other *nix +#endif + if (!isCustomBaudRateSupported || !isCustomBaudRateCurrentSet) { + inputBaudRate = QSerialPortPrivate::baudRateFromSetting(inputUnixBaudRate); + outputBaudRate = QSerialPortPrivate::baudRateFromSetting(outputUnixBaudRate); + } + + // Detect databits. + switch (currentTermios.c_cflag & CSIZE) { + case CS5: + dataBits = QSerialPort::Data5; + break; + case CS6: + dataBits = QSerialPort::Data6; + break; + case CS7: + dataBits = QSerialPort::Data7; + break; + case CS8: + dataBits = QSerialPort::Data8; + break; + default: + dataBits = QSerialPort::UnknownDataBits; + break; + } + + // Detect parity. +#ifdef CMSPAR + if (currentTermios.c_cflag & CMSPAR) { + parity = currentTermios.c_cflag & PARODD ? + QSerialPort::MarkParity : QSerialPort::SpaceParity; + } else { +#endif + if (currentTermios.c_cflag & PARENB) { + parity = currentTermios.c_cflag & PARODD ? + QSerialPort::OddParity : QSerialPort::EvenParity; + } else { + parity = QSerialPort::NoParity; + } +#ifdef CMSPAR + } +#endif + + // Detect stopbits. + stopBits = currentTermios.c_cflag & CSTOPB ? + QSerialPort::TwoStop : QSerialPort::OneStop; + + // Detect flow control. + if ((!(currentTermios.c_cflag & CRTSCTS)) && (!(currentTermios.c_iflag & (IXON | IXOFF | IXANY)))) + flow = QSerialPort::NoFlowControl; + else if ((!(currentTermios.c_cflag & CRTSCTS)) && (currentTermios.c_iflag & (IXON | IXOFF | IXANY))) + flow = QSerialPort::SoftwareControl; + else if ((currentTermios.c_cflag & CRTSCTS) && (!(currentTermios.c_iflag & (IXON | IXOFF | IXANY)))) + flow = QSerialPort::HardwareControl; + else + flow = QSerialPort::UnknownFlowControl; +} + +QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const +{ + QSerialPort::SerialPortError error; + switch (errno) { + case ENODEV: + error = QSerialPort::DeviceNotFoundError; + break; + case EACCES: + error = QSerialPort::PermissionError; + break; + case EBUSY: + error = QSerialPort::PermissionError; + break; + case EAGAIN: + error = QSerialPort::ResourceError; + break; + case EIO: + error = QSerialPort::ResourceError; + break; + case EBADF: + error = QSerialPort::ResourceError; + break; +#ifdef Q_OS_MAC + case ENXIO: + error = QSerialPort::ResourceError; + break; +#endif + default: + error = QSerialPort::UnknownError; + break; + } + return error; +} + +bool QSerialPortPrivate::isReadNotificationEnabled() const +{ + return readNotifier && readNotifier->isEnabled(); +} + +void QSerialPortPrivate::setReadNotificationEnabled(bool enable) +{ + if (readNotifier) { + readNotifier->setEnabled(enable); + } else if (enable) { + readNotifier = new ReadNotifier(this, q_ptr); + readNotifier->setEnabled(true); + } +} + +bool QSerialPortPrivate::isWriteNotificationEnabled() const +{ + return writeNotifier && writeNotifier->isEnabled(); +} + +void QSerialPortPrivate::setWriteNotificationEnabled(bool enable) +{ + if (writeNotifier) { + writeNotifier->setEnabled(enable); + } else if (enable) { + writeNotifier = new WriteNotifier(this, q_ptr); + writeNotifier->setEnabled(true); + } +} + +bool QSerialPortPrivate::isExceptionNotificationEnabled() const +{ + return exceptionNotifier && exceptionNotifier->isEnabled(); +} + +void QSerialPortPrivate::setExceptionNotificationEnabled(bool enable) +{ + if (exceptionNotifier) { + exceptionNotifier->setEnabled(enable); + } else if (enable) { + exceptionNotifier = new ExceptionNotifier(this, q_ptr); + exceptionNotifier->setEnabled(true); + } +} + +bool QSerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectForWrite, + bool checkRead, bool checkWrite, + int msecs, bool *timedOut) +{ + Q_ASSERT(selectForRead); + Q_ASSERT(selectForWrite); + Q_ASSERT(timedOut); + + fd_set fdread; + FD_ZERO(&fdread); + if (checkRead) + FD_SET(descriptor, &fdread); + + fd_set fdwrite; + FD_ZERO(&fdwrite); + if (checkWrite) + FD_SET(descriptor, &fdwrite); + + struct timeval tv; + tv.tv_sec = msecs / 1000; + tv.tv_usec = (msecs % 1000) * 1000; + + int ret = ::select(descriptor + 1, &fdread, &fdwrite, 0, msecs < 0 ? 0 : &tv); + if (ret < 0) + return false; + if (ret == 0) { + *timedOut = true; + return false; + } + + *selectForRead = FD_ISSET(descriptor, &fdread); + *selectForWrite = FD_ISSET(descriptor, &fdwrite); + + return ret; +} + +qint64 QSerialPortPrivate::readFromPort(char *data, qint64 maxSize) +{ + qint64 bytesRead = 0; +#if defined (CMSPAR) + if (parity == QSerialPort::NoParity + || policy != QSerialPort::StopReceivingPolicy) { +#else + if (parity != QSerialPort::MarkParity + && parity != QSerialPort::SpaceParity) { +#endif + bytesRead = ::read(descriptor, data, maxSize); + } else {// Perform parity emulation. + bytesRead = readPerChar(data, maxSize); + } + + if (bytesRead <= 0) { + QSerialPort::SerialPortError error = decodeSystemError(); + if (error != QSerialPort::ResourceError) + error = QSerialPort::ReadError; + q_ptr->setError(error); + } + + return bytesRead; +} + +qint64 QSerialPortPrivate::writeToPort(const char *data, qint64 maxSize) +{ + qint64 bytesWritten = 0; +#if defined (CMSPAR) + bytesWritten = ::write(descriptor, data, maxSize); +#else + if (parity != QSerialPort::MarkParity + && parity != QSerialPort::SpaceParity) { + bytesWritten = ::write(descriptor, data, maxSize); + } else {// Perform parity emulation. + bytesWritten = writePerChar(data, maxSize); + } +#endif + + if (bytesWritten < 0) { + QSerialPort::SerialPortError error = decodeSystemError(); + if (error != QSerialPort::ResourceError) + error = QSerialPort::WriteError; + q_ptr->setError(error); + } + + return bytesWritten; +} + +static inline bool evenParity(quint8 c) +{ + c ^= c >> 4; //(c7 ^ c3)(c6 ^ c2)(c5 ^ c1)(c4 ^ c0) + c ^= c >> 2; //[(c7 ^ c3)(c5 ^ c1)][(c6 ^ c2)(c4 ^ c0)] + c ^= c >> 1; + return c & 1; //(c7 ^ c3)(c5 ^ c1)(c6 ^ c2)(c4 ^ c0) +} + +#ifndef CMSPAR + +qint64 QSerialPortPrivate::writePerChar(const char *data, qint64 maxSize) +{ + qint64 ret = 0; + quint8 const charMask = (0xFF >> (8 - dataBits)); + + while (ret < maxSize) { + + bool par = evenParity(*data & charMask); + // False if need EVEN, true if need ODD. + par ^= parity == QSerialPort::MarkParity; + if (par ^ (currentTermios.c_cflag & PARODD)) { // Need switch parity mode? + currentTermios.c_cflag ^= PARODD; + flush(); //force sending already buffered data, because updateTermios() cleares buffers + //todo: add receiving buffered data!!! + if (!updateTermios()) + break; + } + + int r = ::write(descriptor, data, 1); + if (r < 0) + return -1; + if (r > 0) { + data += r; + ret += r; + } + } + return ret; +} + +#endif //CMSPAR + +qint64 QSerialPortPrivate::readPerChar(char *data, qint64 maxSize) +{ + qint64 ret = 0; + quint8 const charMask = (0xFF >> (8 - dataBits)); + + // 0 - prefix not started, + // 1 - received 0xFF, + // 2 - received 0xFF and 0x00 + int prefix = 0; + while (ret < maxSize) { + + qint64 r = ::read(descriptor, data, 1); + if (r < 0) { + if (errno == EAGAIN) // It is ok for nonblocking mode. + break; + return -1; + } + if (r == 0) + break; + + bool par = true; + switch (prefix) { + case 2: // Previously received both 0377 and 0. + par = false; + prefix = 0; + break; + case 1: // Previously received 0377. + if (*data == '\0') { + ++prefix; + continue; + } + prefix = 0; + break; + default: + if (*data == '\377') { + prefix = 1; + continue; + } + break; + } + // Now: par contains parity ok or error, *data contains received character + par ^= evenParity(*data & charMask); //par contains parity bit value for EVEN mode + par ^= (currentTermios.c_cflag & PARODD); //par contains parity bit value for current mode + if (par ^ (parity == QSerialPort::SpaceParity)) { //if parity error + switch (policy) { + case QSerialPort::SkipPolicy: + continue; //ignore received character + case QSerialPort::StopReceivingPolicy: + if (parity != QSerialPort::NoParity) + q_ptr->setError(QSerialPort::ParityError); + else + q_ptr->setError(*data == '\0' ? + QSerialPort::BreakConditionError : QSerialPort::FramingError); + return ++ret; //abort receiving + break; + case QSerialPort::UnknownPolicy: + // Unknown error policy is used! Falling back to PassZeroPolicy + case QSerialPort::PassZeroPolicy: + *data = '\0'; //replace received character by zero + break; + case QSerialPort::IgnorePolicy: + break; //ignore error and pass received character + } + } + ++data; + ++ret; + } + return ret; +} + +#ifdef Q_OS_MAC +static const QLatin1String defaultFilePathPrefix("/dev/cu."); +static const QLatin1String unusedFilePathPrefix("/dev/tty."); +#else +static const QLatin1String defaultFilePathPrefix("/dev/"); +#endif + +QString QSerialPortPrivate::portNameToSystemLocation(const QString &port) +{ + QString ret = port; + +#ifdef Q_OS_MAC + ret.remove(unusedFilePathPrefix); +#endif + + if (!ret.contains(defaultFilePathPrefix)) + ret.prepend(defaultFilePathPrefix); + return ret; +} + +QString QSerialPortPrivate::portNameFromSystemLocation(const QString &location) +{ + QString ret = location; + +#ifdef Q_OS_MAC + ret.remove(unusedFilePathPrefix); +#endif + + ret.remove(defaultFilePathPrefix); + return ret; +} + +typedef QMap BaudRateMap; + +// The OS specific defines can be found in termios.h + +static const BaudRateMap createStandardBaudRateMap() +{ + BaudRateMap baudRateMap; + +#ifdef B50 + baudRateMap.insert(50, B50); +#endif + +#ifdef B75 + baudRateMap.insert(75, B75); +#endif + +#ifdef B110 + baudRateMap.insert(110, B110); +#endif + +#ifdef B134 + baudRateMap.insert(134, B134); +#endif + +#ifdef B150 + baudRateMap.insert(150, B150); +#endif + +#ifdef B200 + baudRateMap.insert(200, B200); +#endif + +#ifdef B300 + baudRateMap.insert(300, B300); +#endif + +#ifdef B600 + baudRateMap.insert(600, B600); +#endif + +#ifdef B1200 + baudRateMap.insert(1200, B1200); +#endif + +#ifdef B1800 + baudRateMap.insert(1800, B1800); +#endif + +#ifdef B2400 + baudRateMap.insert(2400, B2400); +#endif + +#ifdef B4800 + baudRateMap.insert(4800, B4800); +#endif + +#ifdef B9600 + baudRateMap.insert(9600, B9600); +#endif + +#ifdef B19200 + baudRateMap.insert(19200, B19200); +#endif + +#ifdef B38400 + baudRateMap.insert(38400, B38400); +#endif + +#ifdef B57600 + baudRateMap.insert(57600, B57600); +#endif + +#ifdef B115200 + baudRateMap.insert(115200, B115200); +#endif + +#ifdef B230400 + baudRateMap.insert(230400, B230400); +#endif + +#ifdef B460800 + baudRateMap.insert(460800, B460800); +#endif + +#ifdef B500000 + baudRateMap.insert(500000, B500000); +#endif + +#ifdef B576000 + baudRateMap.insert(576000, B576000); +#endif + +#ifdef B921600 + baudRateMap.insert(921600, B921600); +#endif + +#ifdef B1000000 + baudRateMap.insert(1000000, B1000000); +#endif + +#ifdef B1152000 + baudRateMap.insert(1152000, B1152000); +#endif + +#ifdef B1500000 + baudRateMap.insert(1500000, B1500000); +#endif + +#ifdef B2000000 + baudRateMap.insert(2000000, B2000000); +#endif + +#ifdef B2500000 + baudRateMap.insert(2500000, B2500000); +#endif + +#ifdef B3000000 + baudRateMap.insert(3000000, B3000000); +#endif + +#ifdef B3500000 + baudRateMap.insert(3500000, B3500000); +#endif + +#ifdef B4000000 + baudRateMap.insert(4000000, B4000000); +#endif + + return baudRateMap; +} + +static const BaudRateMap& standardBaudRateMap() +{ + static const BaudRateMap baudRateMap = createStandardBaudRateMap(); + return baudRateMap; +} + +qint32 QSerialPortPrivate::baudRateFromSetting(qint32 setting) +{ + return standardBaudRateMap().key(setting); +} + +qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate) +{ + return standardBaudRateMap().value(baudRate); +} + +QList QSerialPortPrivate::standardBaudRates() +{ + return standardBaudRateMap().keys(); +} + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialport_unix_p.h b/libs/serialport/qserialport_unix_p.h new file mode 100644 index 0000000000000000000000000000000000000000..ce70c243b3c546e8699cd15b0c93a6c199eff05c --- /dev/null +++ b/libs/serialport/qserialport_unix_p.h @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSERIALPORT_UNIX_P_H +#define QSERIALPORT_UNIX_P_H + +#include "qserialport_p.h" + +#include +#include +#ifdef Q_OS_LINUX +# include +#endif + +QT_BEGIN_NAMESPACE + +class QSocketNotifier; + +class QSerialPortPrivate : public QSerialPortPrivateData +{ +public: + QSerialPortPrivate(QSerialPort *q); + + bool open(QIODevice::OpenMode mode); + void close(); + + QSerialPort::PinoutSignals pinoutSignals() const; + + bool setDataTerminalReady(bool set); + bool setRequestToSend(bool set); + + bool flush(); + bool clear(QSerialPort::Directions dir); + + bool sendBreak(int duration); + bool setBreakEnabled(bool set); + + qint64 systemInputQueueSize () const; + qint64 systemOutputQueueSize () const; + + qint64 bytesAvailable() const; + + qint64 readFromBuffer(char *data, qint64 maxSize); + qint64 writeToBuffer(const char *data, qint64 maxSize); + + bool waitForReadyRead(int msecs); + bool waitForBytesWritten(int msecs); + + bool setBaudRate(qint32 baudRate, QSerialPort::Directions dir); + bool setDataBits(QSerialPort::DataBits dataBits); + bool setParity(QSerialPort::Parity parity); + bool setStopBits(QSerialPort::StopBits stopBits); + bool setFlowControl(QSerialPort::FlowControl flow); + bool setDataErrorPolicy(QSerialPort::DataErrorPolicy policy); + + bool readNotification(); + bool writeNotification(int maxSize = INT_MAX); + bool exceptionNotification(); + + static QString portNameToSystemLocation(const QString &port); + static QString portNameFromSystemLocation(const QString &location); + + static qint32 baudRateFromSetting(qint32 setting); + static qint32 settingFromBaudRate(qint32 baudRate); + + static QList standardBaudRates(); + + struct termios currentTermios; + struct termios restoredTermios; +#ifdef Q_OS_LINUX + struct serial_struct currentSerialInfo; + struct serial_struct restoredSerialInfo; +#endif + int descriptor; + bool isCustomBaudRateSupported; + + QSocketNotifier *readNotifier; + QSocketNotifier *writeNotifier; + QSocketNotifier *exceptionNotifier; + + bool readPortNotifierCalled; + bool readPortNotifierState; + bool readPortNotifierStateSet; + + bool emittedReadyRead; + bool emittedBytesWritten; + +private: + bool updateTermios(); + + void detectDefaultSettings(); + QSerialPort::SerialPortError decodeSystemError() const; + + bool isReadNotificationEnabled() const; + void setReadNotificationEnabled(bool enable); + bool isWriteNotificationEnabled() const; + void setWriteNotificationEnabled(bool enable); + bool isExceptionNotificationEnabled() const; + void setExceptionNotificationEnabled(bool enable); + + bool waitForReadOrWrite(bool *selectForRead, bool *selectForWrite, + bool checkRead, bool checkWrite, + int msecs, bool *timedOut); + + qint64 readFromPort(char *data, qint64 maxSize); + qint64 writeToPort(const char *data, qint64 maxSize); + +#ifndef CMSPAR + qint64 writePerChar(const char *data, qint64 maxSize); +#endif + qint64 readPerChar(char *data, qint64 maxSize); + +}; + +QT_END_NAMESPACE + +#endif // QSERIALPORT_UNIX_P_H diff --git a/libs/serialport/qserialport_win.cpp b/libs/serialport/qserialport_win.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e8d4d62adb62dba18b79209eb1ea55ff0af14677 --- /dev/null +++ b/libs/serialport/qserialport_win.cpp @@ -0,0 +1,1091 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Copyright (C) 2012 Andre Hartmann +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialport_win_p.h" + +#ifndef Q_OS_WINCE +#include +#include +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#else +#include "qt4support/qwineventnotifier_p.h" +#endif + +#ifndef CTL_CODE +# define CTL_CODE(DeviceType, Function, Method, Access) ( \ + ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ + ) +#endif + +#ifndef FILE_DEVICE_SERIAL_PORT +# define FILE_DEVICE_SERIAL_PORT 27 +#endif + +#ifndef METHOD_BUFFERED +# define METHOD_BUFFERED 0 +#endif + +#ifndef FILE_ANY_ACCESS +# define FILE_ANY_ACCESS 0x00000000 +#endif + +#ifndef IOCTL_SERIAL_GET_DTRRTS +# define IOCTL_SERIAL_GET_DTRRTS \ + CTL_CODE(FILE_DEVICE_SERIAL_PORT, 30, METHOD_BUFFERED, FILE_ANY_ACCESS) +#endif + +#ifndef SERIAL_DTR_STATE +# define SERIAL_DTR_STATE 0x00000001 +#endif + +#ifndef SERIAL_RTS_STATE +# define SERIAL_RTS_STATE 0x00000002 +#endif + +QT_BEGIN_NAMESPACE + +#ifndef Q_OS_WINCE + +class AbstractOverlappedEventNotifier : public QWinEventNotifier +{ +public: + enum Type { CommEvent, ReadCompletionEvent, WriteCompletionEvent }; + + AbstractOverlappedEventNotifier(QSerialPortPrivate *d, Type type, bool manual, QObject *parent) + : QWinEventNotifier(parent), dptr(d), t(type) { + ::memset(&o, 0, sizeof(o)); + o.hEvent = ::CreateEvent(NULL, manual, FALSE, NULL); + setHandle(o.hEvent); + dptr->notifiers[o.hEvent] = this; + } + + virtual bool processCompletionRoutine() = 0; + + virtual ~AbstractOverlappedEventNotifier() { + setEnabled(false); + ::CancelIo(o.hEvent); + ::CloseHandle(o.hEvent); + } + + Type type() const { return t; } + OVERLAPPED *overlappedPointer() { return &o; } + +protected: + bool event(QEvent *e) Q_DECL_OVERRIDE { + const bool ret = QWinEventNotifier::event(e); + processCompletionRoutine(); + return ret; + } + + QSerialPortPrivate *dptr; + Type t; + OVERLAPPED o; +}; + +class CommOverlappedEventNotifier : public AbstractOverlappedEventNotifier +{ +public: + CommOverlappedEventNotifier(QSerialPortPrivate *d, DWORD eventMask, QObject *parent) + : AbstractOverlappedEventNotifier(d, CommEvent, false, parent) + , originalEventMask(eventMask), triggeredEventMask(0) { + ::SetCommMask(dptr->descriptor, originalEventMask); + startWaitCommEvent(); + } + + void startWaitCommEvent() { ::WaitCommEvent(dptr->descriptor, &triggeredEventMask, &o); } + + bool processCompletionRoutine() Q_DECL_OVERRIDE { + DWORD numberOfBytesTransferred = 0; + ::GetOverlappedResult(dptr->descriptor, &o, &numberOfBytesTransferred, FALSE); + + bool error = false; + + // Check for unexpected event. This event triggered when pulled previously + // opened device from the system, when opened as for not to read and not to + // write options and so forth. + if (triggeredEventMask == 0) + error = true; + + // Workaround for standard CDC ACM serial ports, for which triggered an + // unexpected event EV_TXEMPTY at data transmission. + if ((originalEventMask & triggeredEventMask) == 0) { + if ((triggeredEventMask & EV_TXEMPTY) == 0) + error = true; + } + + // Start processing a caught error. + if (error || (EV_ERR & triggeredEventMask)) + dptr->processIoErrors(error); + + if (!error) + dptr->startAsyncRead(); + + return !error; + } + +private: + DWORD originalEventMask; + DWORD triggeredEventMask; +}; + +class ReadOverlappedCompletionNotifier : public AbstractOverlappedEventNotifier +{ +public: + ReadOverlappedCompletionNotifier(QSerialPortPrivate *d, QObject *parent) + : AbstractOverlappedEventNotifier(d, ReadCompletionEvent, false, parent) {} + + bool processCompletionRoutine() Q_DECL_OVERRIDE { + DWORD numberOfBytesTransferred = 0; + ::GetOverlappedResult(dptr->descriptor, &o, &numberOfBytesTransferred, FALSE); + bool ret = dptr->completeAsyncRead(numberOfBytesTransferred); + + // start async read for possible remainder into driver queue + if (ret && (numberOfBytesTransferred > 0) && (dptr->policy == QSerialPort::IgnorePolicy)) { + dptr->startAsyncRead(); + } else { // driver queue is emplty, so startup wait comm event + CommOverlappedEventNotifier *n = + reinterpret_cast(dptr->lookupCommEventNotifier()); + if (n) + n->startWaitCommEvent(); + } + + return ret; + } +}; + +class WriteOverlappedCompletionNotifier : public AbstractOverlappedEventNotifier +{ +public: + WriteOverlappedCompletionNotifier(QSerialPortPrivate *d, QObject *parent) + : AbstractOverlappedEventNotifier(d, WriteCompletionEvent, false, parent) {} + + bool processCompletionRoutine() Q_DECL_OVERRIDE { + setEnabled(false); + DWORD numberOfBytesTransferred = 0; + ::GetOverlappedResult(dptr->descriptor, &o, &numberOfBytesTransferred, FALSE); + return dptr->completeAsyncWrite(numberOfBytesTransferred); + } +}; + +QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q) + : QSerialPortPrivateData(q) + , descriptor(INVALID_HANDLE_VALUE) + , parityErrorOccurred(false) + , actualReadBufferSize(0) + , actualWriteBufferSize(0) + , acyncWritePosition(0) + , readyReadEmitted(0) + , writeSequenceStarted(false) +{ +} + +bool QSerialPortPrivate::open(QIODevice::OpenMode mode) +{ + DWORD desiredAccess = 0; + DWORD originalEventMask = EV_ERR; + + if (mode & QIODevice::ReadOnly) { + desiredAccess |= GENERIC_READ; + originalEventMask |= EV_RXCHAR; + } + if (mode & QIODevice::WriteOnly) + desiredAccess |= GENERIC_WRITE; + + descriptor = ::CreateFile(reinterpret_cast(systemLocation.utf16()), + desiredAccess, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + + if (descriptor == INVALID_HANDLE_VALUE) { + q_ptr->setError(decodeSystemError()); + return false; + } + + if (!::GetCommState(descriptor, &restoredDcb)) { + q_ptr->setError(decodeSystemError()); + return false; + } + + currentDcb = restoredDcb; + currentDcb.fBinary = TRUE; + currentDcb.fInX = FALSE; + currentDcb.fOutX = FALSE; + currentDcb.fAbortOnError = FALSE; + currentDcb.fNull = FALSE; + currentDcb.fErrorChar = FALSE; + + if (!updateDcb()) + return false; + + if (!::GetCommTimeouts(descriptor, &restoredCommTimeouts)) { + q_ptr->setError(decodeSystemError()); + return false; + } + + ::memset(¤tCommTimeouts, 0, sizeof(currentCommTimeouts)); + currentCommTimeouts.ReadIntervalTimeout = MAXDWORD; + + if (!updateCommTimeouts()) + return false; + + if (originalEventMask & EV_RXCHAR) { + QWinEventNotifier *n = new ReadOverlappedCompletionNotifier(this, q_ptr); + n->setEnabled(true); + } + + QWinEventNotifier *n = new CommOverlappedEventNotifier(this, originalEventMask, q_ptr); + n->setEnabled(true); + + detectDefaultSettings(); + return true; +} + +void QSerialPortPrivate::close() +{ + ::CancelIo(descriptor); + + qDeleteAll(notifiers); + notifiers.clear(); + + readBuffer.clear(); + actualReadBufferSize = 0; + + writeSequenceStarted = false; + writeBuffer.clear(); + actualWriteBufferSize = 0; + acyncWritePosition = 0; + + readyReadEmitted = false; + parityErrorOccurred = false; + + if (settingsRestoredOnClose) { + ::SetCommState(descriptor, &restoredDcb); + ::SetCommTimeouts(descriptor, &restoredCommTimeouts); + } + + ::CloseHandle(descriptor); + descriptor = INVALID_HANDLE_VALUE; +} + +#endif // #ifndef Q_OS_WINCE + +QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() const +{ + DWORD modemStat = 0; + QSerialPort::PinoutSignals ret = QSerialPort::NoSignal; + + if (!::GetCommModemStatus(descriptor, &modemStat)) { + q_ptr->setError(decodeSystemError()); + return ret; + } + + if (modemStat & MS_CTS_ON) + ret |= QSerialPort::ClearToSendSignal; + if (modemStat & MS_DSR_ON) + ret |= QSerialPort::DataSetReadySignal; + if (modemStat & MS_RING_ON) + ret |= QSerialPort::RingIndicatorSignal; + if (modemStat & MS_RLSD_ON) + ret |= QSerialPort::DataCarrierDetectSignal; + + DWORD bytesReturned = 0; + if (::DeviceIoControl(descriptor, IOCTL_SERIAL_GET_DTRRTS, NULL, 0, + &modemStat, sizeof(modemStat), + &bytesReturned, NULL)) { + + if (modemStat & SERIAL_DTR_STATE) + ret |= QSerialPort::DataTerminalReadySignal; + if (modemStat & SERIAL_RTS_STATE) + ret |= QSerialPort::RequestToSendSignal; + } + + return ret; +} + +bool QSerialPortPrivate::setDataTerminalReady(bool set) +{ + return ::EscapeCommFunction(descriptor, set ? SETDTR : CLRDTR); +} + +bool QSerialPortPrivate::setRequestToSend(bool set) +{ + return ::EscapeCommFunction(descriptor, set ? SETRTS : CLRRTS); +} + +#ifndef Q_OS_WINCE + +bool QSerialPortPrivate::flush() +{ + return startAsyncWrite() && ::FlushFileBuffers(descriptor); +} + +bool QSerialPortPrivate::clear(QSerialPort::Directions dir) +{ + DWORD flags = 0; + if (dir & QSerialPort::Input) { + flags |= PURGE_RXABORT | PURGE_RXCLEAR; + actualReadBufferSize = 0; + } + if (dir & QSerialPort::Output) { + flags |= PURGE_TXABORT | PURGE_TXCLEAR; + actualWriteBufferSize = 0; + acyncWritePosition = 0; + writeSequenceStarted = false; + } + return ::PurgeComm(descriptor, flags); +} + +#endif + +bool QSerialPortPrivate::sendBreak(int duration) +{ + // FIXME: + if (setBreakEnabled(true)) { + ::Sleep(duration); + if (setBreakEnabled(false)) + return true; + } + return false; +} + +bool QSerialPortPrivate::setBreakEnabled(bool set) +{ + if (set) + return ::SetCommBreak(descriptor); + return ::ClearCommBreak(descriptor); +} + +qint64 QSerialPortPrivate::systemInputQueueSize () const +{ + COMSTAT cs; + ::memset(&cs, 0, sizeof(cs)); + if (!::ClearCommError(descriptor, NULL, &cs)) + return -1; + return cs.cbInQue; +} + +qint64 QSerialPortPrivate::systemOutputQueueSize () const +{ + COMSTAT cs; + ::memset(&cs, 0, sizeof(cs)); + if (!::ClearCommError(descriptor, NULL, &cs)) + return -1; + return cs.cbOutQue; +} + +#ifndef Q_OS_WINCE + +qint64 QSerialPortPrivate::bytesAvailable() const +{ + return actualReadBufferSize; +} + +qint64 QSerialPortPrivate::readFromBuffer(char *data, qint64 maxSize) +{ + if (actualReadBufferSize == 0) + return 0; + + qint64 readSoFar = -1; + if (maxSize == 1 && actualReadBufferSize > 0) { + *data = readBuffer.getChar(); + actualReadBufferSize--; + readSoFar = 1; + } else { + const qint64 bytesToRead = qMin(qint64(actualReadBufferSize), maxSize); + readSoFar = 0; + while (readSoFar < bytesToRead) { + const char *ptr = readBuffer.readPointer(); + const int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar, + qint64(readBuffer.nextDataBlockSize())); + ::memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock); + readSoFar += bytesToReadFromThisBlock; + readBuffer.free(bytesToReadFromThisBlock); + actualReadBufferSize -= bytesToReadFromThisBlock; + } + } + + return readSoFar; +} + +qint64 QSerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize) +{ + char *ptr = writeBuffer.reserve(maxSize); + if (maxSize == 1) { + *ptr = *data; + actualWriteBufferSize++; + } else { + ::memcpy(ptr, data, maxSize); + actualWriteBufferSize += maxSize; + } + + if (!writeSequenceStarted) + startAsyncWrite(WriteChunkSize); + + return maxSize; +} + +bool QSerialPortPrivate::waitForReadyRead(int msecs) +{ + QElapsedTimer stopWatch; + stopWatch.start(); + + do { + bool timedOut = false; + AbstractOverlappedEventNotifier *n = 0; + + if (!waitAnyEvent(timeoutValue(msecs, stopWatch.elapsed()), &timedOut, &n) || !n) { + // This is occur timeout or another error + q_ptr->setError(decodeSystemError()); + return false; + } + + switch (n->type()) { + case AbstractOverlappedEventNotifier::CommEvent: + if (!n->processCompletionRoutine()) + return false; + break; + case AbstractOverlappedEventNotifier::ReadCompletionEvent: + return n->processCompletionRoutine(); + case AbstractOverlappedEventNotifier::WriteCompletionEvent: + n->processCompletionRoutine(); + break; + default: // newer called + return false; + } + } while (msecs == -1 || timeoutValue(msecs, stopWatch.elapsed()) > 0); + + return false; +} + +bool QSerialPortPrivate::waitForBytesWritten(int msecs) +{ + if (writeBuffer.isEmpty()) + return false; + + QElapsedTimer stopWatch; + stopWatch.start(); + + forever { + bool timedOut = false; + AbstractOverlappedEventNotifier *n = 0; + + if (!waitAnyEvent(timeoutValue(msecs, stopWatch.elapsed()), &timedOut, &n) || !n) { + q_ptr->setError(decodeSystemError()); + return false; + } + + switch (n->type()) { + case AbstractOverlappedEventNotifier::CommEvent: + // do nothing, jump to ReadCompletionEvent case + case AbstractOverlappedEventNotifier::ReadCompletionEvent: + n->processCompletionRoutine(); + break; + case AbstractOverlappedEventNotifier::WriteCompletionEvent: + return n->processCompletionRoutine(); + default: // newer called + return false; + } + } + + return false; +} + +#endif // #ifndef Q_OS_WINCE + +bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions dir) +{ + if (dir != QSerialPort::AllDirections) { + q_ptr->setError(QSerialPort::UnsupportedOperationError); + return false; + } + currentDcb.BaudRate = baudRate; + return updateDcb(); +} + +bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits) +{ + currentDcb.ByteSize = dataBits; + return updateDcb(); +} + +bool QSerialPortPrivate::setParity(QSerialPort::Parity parity) +{ + currentDcb.fParity = TRUE; + switch (parity) { + case QSerialPort::NoParity: + currentDcb.Parity = NOPARITY; + currentDcb.fParity = FALSE; + break; + case QSerialPort::OddParity: + currentDcb.Parity = ODDPARITY; + break; + case QSerialPort::EvenParity: + currentDcb.Parity = EVENPARITY; + break; + case QSerialPort::MarkParity: + currentDcb.Parity = MARKPARITY; + break; + case QSerialPort::SpaceParity: + currentDcb.Parity = SPACEPARITY; + break; + default: + currentDcb.Parity = NOPARITY; + currentDcb.fParity = FALSE; + break; + } + return updateDcb(); +} + +bool QSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits) +{ + switch (stopBits) { + case QSerialPort::OneStop: + currentDcb.StopBits = ONESTOPBIT; + break; + case QSerialPort::OneAndHalfStop: + currentDcb.StopBits = ONE5STOPBITS; + break; + case QSerialPort::TwoStop: + currentDcb.StopBits = TWOSTOPBITS; + break; + default: + currentDcb.StopBits = ONESTOPBIT; + break; + } + return updateDcb(); +} + +bool QSerialPortPrivate::setFlowControl(QSerialPort::FlowControl flow) +{ + currentDcb.fInX = FALSE; + currentDcb.fOutX = FALSE; + currentDcb.fOutxCtsFlow = FALSE; + currentDcb.fRtsControl = RTS_CONTROL_DISABLE; + switch (flow) { + case QSerialPort::NoFlowControl: + break; + case QSerialPort::SoftwareControl: + currentDcb.fInX = TRUE; + currentDcb.fOutX = TRUE; + break; + case QSerialPort::HardwareControl: + currentDcb.fOutxCtsFlow = TRUE; + currentDcb.fRtsControl = RTS_CONTROL_HANDSHAKE; + break; + default: + break; + } + return updateDcb(); +} + +bool QSerialPortPrivate::setDataErrorPolicy(QSerialPort::DataErrorPolicy policy) +{ + policy = policy; + return true; +} + +#ifndef Q_OS_WINCE + +bool QSerialPortPrivate::startAsyncRead() +{ + DWORD bytesToRead = policy == QSerialPort::IgnorePolicy ? ReadChunkSize : 1; + + if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) { + bytesToRead = readBufferMaxSize - readBuffer.size(); + if (bytesToRead == 0) { + // Buffer is full. User must read data from the buffer + // before we can read more from the port. + return false; + } + } + + AbstractOverlappedEventNotifier *n = lookupReadCompletionNotifier(); + if (!n) { + q_ptr->setError(QSerialPort::ResourceError); + return false; + } + + char *ptr = readBuffer.reserve(bytesToRead); + + if (::ReadFile(descriptor, ptr, bytesToRead, NULL, n->overlappedPointer())) + return true; + + QSerialPort::SerialPortError error = decodeSystemError(); + if (error != QSerialPort::NoError) { + if (error != QSerialPort::ResourceError) + error = QSerialPort::ReadError; + q_ptr->setError(error); + + readBuffer.truncate(actualReadBufferSize); + return false; + } + + return true; +} + +bool QSerialPortPrivate::startAsyncWrite(int maxSize) +{ + qint64 nextSize = 0; + const char *ptr = writeBuffer.readPointerAtPosition(acyncWritePosition, nextSize); + + nextSize = qMin(nextSize, qint64(maxSize)); + acyncWritePosition += nextSize; + + // no more data to write + if (!ptr || nextSize == 0) + return true; + + writeSequenceStarted = true; + + AbstractOverlappedEventNotifier *n = lookupFreeWriteCompletionNotifier(); + if (!n) { + q_ptr->setError(QSerialPort::ResourceError); + return false; + } + + n->setEnabled(true); + + if (::WriteFile(descriptor, ptr, nextSize, NULL, n->overlappedPointer())) + return true; + + QSerialPort::SerialPortError error = decodeSystemError(); + if (error != QSerialPort::NoError) { + writeSequenceStarted = false; + + if (error != QSerialPort::ResourceError) + error = QSerialPort::WriteError; + + q_ptr->setError(error); + return false; + } + + return true; +} + +#endif // #ifndef Q_OS_WINCE + +bool QSerialPortPrivate::processIoErrors(bool error) +{ + if (error) { + q_ptr->setError(QSerialPort::ResourceError); + return true; + } + + DWORD errors = 0; + const bool ret = ::ClearCommError(descriptor, &errors, NULL); + if (ret && errors) { + if (errors & CE_FRAME) { + q_ptr->setError(QSerialPort::FramingError); + } else if (errors & CE_RXPARITY) { + q_ptr->setError(QSerialPort::ParityError); + parityErrorOccurred = true; + } else if (errors & CE_BREAK) { + q_ptr->setError(QSerialPort::BreakConditionError); + } else { + q_ptr->setError(QSerialPort::UnknownError); + } + } + return ret; +} + +#ifndef Q_OS_WINCE + +bool QSerialPortPrivate::completeAsyncRead(DWORD numberOfBytes) +{ + actualReadBufferSize += qint64(numberOfBytes); + readBuffer.truncate(actualReadBufferSize); + + if (numberOfBytes > 0) { + + // Process emulate policy. + if ((policy != QSerialPort::IgnorePolicy) && parityErrorOccurred) { + + parityErrorOccurred = false; + + // Ignore received character, remove it from buffer + if (policy == QSerialPort::SkipPolicy) { + readBuffer.getChar(); + // Force returning without emitting a readyRead() signal + return true; + } + + // Abort receiving + if (policy == QSerialPort::StopReceivingPolicy) { + readyReadEmitted = true; + emit q_ptr->readyRead(); + return true; + } + + // Replace received character by zero + if (policy == QSerialPort::PassZeroPolicy) { + readBuffer.getChar(); + readBuffer.putChar('\0'); + } + + } + + readyReadEmitted = true; + emit q_ptr->readyRead(); + } + return true; +} + +bool QSerialPortPrivate::completeAsyncWrite(DWORD numberOfBytes) +{ + writeBuffer.free(numberOfBytes); + actualWriteBufferSize -= qint64(numberOfBytes); + acyncWritePosition -= qint64(numberOfBytes); + + if (numberOfBytes > 0) + emit q_ptr->bytesWritten(numberOfBytes); + + if (writeBuffer.isEmpty()) + writeSequenceStarted = false; + else + startAsyncWrite(WriteChunkSize); + + return true; +} + +AbstractOverlappedEventNotifier *QSerialPortPrivate::lookupFreeWriteCompletionNotifier() +{ + // find first free not running write notifier + foreach (AbstractOverlappedEventNotifier *n, notifiers) { + if ((n->type() == AbstractOverlappedEventNotifier::WriteCompletionEvent) + && !n->isEnabled()) { + return n; + } + } + // if all write notifiers in use, then create new write notifier + return new WriteOverlappedCompletionNotifier(this, q_ptr); +} + +AbstractOverlappedEventNotifier *QSerialPortPrivate::lookupCommEventNotifier() +{ + foreach (AbstractOverlappedEventNotifier *n, notifiers) { + if (n->type() == AbstractOverlappedEventNotifier::CommEvent) + return n; + } + return 0; +} + +AbstractOverlappedEventNotifier *QSerialPortPrivate::lookupReadCompletionNotifier() +{ + foreach (AbstractOverlappedEventNotifier *n, notifiers) { + if (n->type() == AbstractOverlappedEventNotifier::ReadCompletionEvent) + return n; + } + return 0; +} + +bool QSerialPortPrivate::updateDcb() +{ + if (!::SetCommState(descriptor, ¤tDcb)) { + q_ptr->setError(decodeSystemError()); + return false; + } + return true; +} + +bool QSerialPortPrivate::updateCommTimeouts() +{ + if (!::SetCommTimeouts(descriptor, ¤tCommTimeouts)) { + q_ptr->setError(decodeSystemError()); + return false; + } + return true; +} + +#endif // #ifndef Q_OS_WINCE + +void QSerialPortPrivate::detectDefaultSettings() +{ + // Detect baud rate. + inputBaudRate = quint32(currentDcb.BaudRate); + outputBaudRate = inputBaudRate; + + // Detect databits. + switch (currentDcb.ByteSize) { + case 5: + dataBits = QSerialPort::Data5; + break; + case 6: + dataBits = QSerialPort::Data6; + break; + case 7: + dataBits = QSerialPort::Data7; + break; + case 8: + dataBits = QSerialPort::Data8; + break; + default: + dataBits = QSerialPort::UnknownDataBits; + break; + } + + // Detect parity. + if ((currentDcb.Parity == NOPARITY) && !currentDcb.fParity) + parity = QSerialPort::NoParity; + else if ((currentDcb.Parity == SPACEPARITY) && currentDcb.fParity) + parity = QSerialPort::SpaceParity; + else if ((currentDcb.Parity == MARKPARITY) && currentDcb.fParity) + parity = QSerialPort::MarkParity; + else if ((currentDcb.Parity == EVENPARITY) && currentDcb.fParity) + parity = QSerialPort::EvenParity; + else if ((currentDcb.Parity == ODDPARITY) && currentDcb.fParity) + parity = QSerialPort::OddParity; + else + parity = QSerialPort::UnknownParity; + + // Detect stopbits. + switch (currentDcb.StopBits) { + case ONESTOPBIT: + stopBits = QSerialPort::OneStop; + break; + case ONE5STOPBITS: + stopBits = QSerialPort::OneAndHalfStop; + break; + case TWOSTOPBITS: + stopBits = QSerialPort::TwoStop; + break; + default: + stopBits = QSerialPort::UnknownStopBits; + break; + } + + // Detect flow control. + if (!currentDcb.fOutxCtsFlow && (currentDcb.fRtsControl == RTS_CONTROL_DISABLE) + && !currentDcb.fInX && !currentDcb.fOutX) { + flow = QSerialPort::NoFlowControl; + } else if (!currentDcb.fOutxCtsFlow && (currentDcb.fRtsControl == RTS_CONTROL_DISABLE) + && currentDcb.fInX && currentDcb.fOutX) { + flow = QSerialPort::SoftwareControl; + } else if (currentDcb.fOutxCtsFlow && (currentDcb.fRtsControl == RTS_CONTROL_HANDSHAKE) + && !currentDcb.fInX && !currentDcb.fOutX) { + flow = QSerialPort::HardwareControl; + } else + flow = QSerialPort::UnknownFlowControl; +} + +QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const +{ + QSerialPort::SerialPortError error; + switch (::GetLastError()) { + case ERROR_IO_PENDING: + error = QSerialPort::NoError; + break; + case ERROR_MORE_DATA: + error = QSerialPort::NoError; + break; + case ERROR_FILE_NOT_FOUND: + error = QSerialPort::DeviceNotFoundError; + break; + case ERROR_ACCESS_DENIED: + error = QSerialPort::PermissionError; + break; + case ERROR_INVALID_HANDLE: + error = QSerialPort::ResourceError; + break; + case ERROR_INVALID_PARAMETER: + error = QSerialPort::UnsupportedOperationError; + break; + case ERROR_BAD_COMMAND: + error = QSerialPort::ResourceError; + break; + case ERROR_DEVICE_REMOVED: + error = QSerialPort::ResourceError; + break; + default: + error = QSerialPort::UnknownError; + break; + } + return error; +} + +#ifndef Q_OS_WINCE + +bool QSerialPortPrivate::waitAnyEvent(int msecs, bool *timedOut, + AbstractOverlappedEventNotifier **triggeredNotifier) +{ + Q_ASSERT(timedOut); + + QVector handles = notifiers.keys().toVector(); + DWORD waitResult = ::WaitForMultipleObjects(handles.count(), + handles.constData(), + FALSE, // wait any event + qMax(msecs, 0)); + if (waitResult == WAIT_TIMEOUT) { + *timedOut = true; + return false; + } + + if (int(waitResult) > (handles.count() - 1)) + return false; + + HANDLE h = handles.at(waitResult - WAIT_OBJECT_0); + *triggeredNotifier = notifiers.value(h); + return true; +} + +static const QLatin1String defaultPathPrefix("\\\\.\\"); + +QString QSerialPortPrivate::portNameToSystemLocation(const QString &port) +{ + QString ret = port; + if (!ret.contains(defaultPathPrefix)) + ret.prepend(defaultPathPrefix); + return ret; +} + +QString QSerialPortPrivate::portNameFromSystemLocation(const QString &location) +{ + QString ret = location; + if (ret.contains(defaultPathPrefix)) + ret.remove(defaultPathPrefix); + return ret; +} + +#endif // #ifndef Q_OS_WINCE + +// This table contains standard values of baud rates that +// are defined in MSDN and/or in Win SDK file winbase.h + +static const QList standardBaudRatePairList() +{ + + static const QList standardBaudRatesTable = QList() + + #ifdef CBR_110 + << CBR_110 + #endif + + #ifdef CBR_300 + << CBR_300 + #endif + + #ifdef CBR_600 + << CBR_600 + #endif + + #ifdef CBR_1200 + << CBR_1200 + #endif + + #ifdef CBR_2400 + << CBR_2400 + #endif + + #ifdef CBR_4800 + << CBR_4800 + #endif + + #ifdef CBR_9600 + << CBR_9600 + #endif + + #ifdef CBR_14400 + << CBR_14400 + #endif + + #ifdef CBR_19200 + << CBR_19200 + #endif + + #ifdef CBR_38400 + << CBR_38400 + #endif + + #ifdef CBR_56000 + << CBR_56000 + #endif + + #ifdef CBR_57600 + << CBR_57600 + #endif + + #ifdef CBR_115200 + << CBR_115200 + #endif + + #ifdef CBR_128000 + << CBR_128000 + #endif + + #ifdef CBR_256000 + << CBR_256000 + #endif + ; + + return standardBaudRatesTable; +}; + +qint32 QSerialPortPrivate::baudRateFromSetting(qint32 setting) +{ + const QList baudRatePairs = standardBaudRatePairList(); + const QList::const_iterator baudRatePairListConstIterator = qFind(baudRatePairs, setting); + + return (baudRatePairListConstIterator != baudRatePairs.constEnd()) ? *baudRatePairListConstIterator : 0; +} + +qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate) +{ + const QList baudRatePairList = standardBaudRatePairList(); + const QList::const_iterator baudRatePairListConstIterator = qFind(baudRatePairList, baudRate); + + return (baudRatePairListConstIterator != baudRatePairList.constEnd()) ? *baudRatePairListConstIterator : 0; +} + +QList QSerialPortPrivate::standardBaudRates() +{ + QList ret; + const QList baudRatePairs = standardBaudRatePairList(); + + foreach (qint32 baudRatePair, baudRatePairs) { + ret.append(baudRatePair); + } + + return ret; +} + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialport_win_p.h b/libs/serialport/qserialport_win_p.h new file mode 100644 index 0000000000000000000000000000000000000000..a59ea9a7bc7e35a7e57e3c43c5c11376f3326d97 --- /dev/null +++ b/libs/serialport/qserialport_win_p.h @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSERIALPORT_WIN_P_H +#define QSERIALPORT_WIN_P_H + +#include "qserialport_p.h" + +#include + +#ifndef Q_OS_WINCE +#include +QT_BEGIN_NAMESPACE +class QWinEventNotifier; +#else +#include +QT_BEGIN_NAMESPACE +class QThread; +#endif + +#ifndef Q_OS_WINCE +class AbstractOverlappedEventNotifier; +#endif + +class QSerialPortPrivate : public QSerialPortPrivateData +{ +public: + QSerialPortPrivate(QSerialPort *q); + + bool open(QIODevice::OpenMode mode); + void close(); + + QSerialPort::PinoutSignals pinoutSignals() const; + + bool setDataTerminalReady(bool set); + bool setRequestToSend(bool set); + + bool flush(); + bool clear(QSerialPort::Directions dir); + + bool sendBreak(int duration); + bool setBreakEnabled(bool set); + + qint64 systemInputQueueSize () const; + qint64 systemOutputQueueSize () const; + + qint64 bytesAvailable() const; + + qint64 readFromBuffer(char *data, qint64 maxSize); + qint64 writeToBuffer(const char *data, qint64 maxSize); + + bool waitForReadyRead(int msec); + bool waitForBytesWritten(int msec); + + bool setBaudRate(qint32 baudRate, QSerialPort::Directions dir); + bool setDataBits(QSerialPort::DataBits dataBits); + bool setParity(QSerialPort::Parity parity); + bool setStopBits(QSerialPort::StopBits stopBits); + bool setFlowControl(QSerialPort::FlowControl flowControl); + bool setDataErrorPolicy(QSerialPort::DataErrorPolicy policy); + + bool processIoErrors(bool error); +#ifndef Q_OS_WINCE + bool startAsyncRead(); + bool startAsyncWrite(int maxSize = INT_MAX); + bool completeAsyncRead(DWORD numberOfBytes); + bool completeAsyncWrite(DWORD numberOfBytes); + AbstractOverlappedEventNotifier *lookupFreeWriteCompletionNotifier(); + AbstractOverlappedEventNotifier *lookupCommEventNotifier(); + AbstractOverlappedEventNotifier *lookupReadCompletionNotifier(); +#else + bool notifyRead(); + bool notifyWrite(int maxSize = INT_MAX); +#endif + + static QString portNameToSystemLocation(const QString &port); + static QString portNameFromSystemLocation(const QString &location); + + static qint32 baudRateFromSetting(qint32 setting); + static qint32 settingFromBaudRate(qint32 baudRate); + + static QList standardBaudRates(); + + DCB currentDcb; + DCB restoredDcb; + COMMTIMEOUTS currentCommTimeouts; + COMMTIMEOUTS restoredCommTimeouts; + HANDLE descriptor; + bool parityErrorOccurred; + +#ifndef Q_OS_WINCE + QHash notifiers; + qint64 actualReadBufferSize; + qint64 actualWriteBufferSize; + qint64 acyncWritePosition; + bool readyReadEmitted; + bool writeSequenceStarted; +#else + QThread *eventNotifier; + QMutex settingsChangeMutex; +#endif + +private: + bool updateDcb(); + bool updateCommTimeouts(); + + void detectDefaultSettings(); + QSerialPort::SerialPortError decodeSystemError() const; + +#ifndef Q_OS_WINCE + bool waitAnyEvent(int msecs, bool *timedOut, + AbstractOverlappedEventNotifier **triggeredNotifier); +#else + bool waitForReadOrWrite(bool *selectForRead, bool *selectForWrite, + bool checkRead, bool checkWrite, + int msecs, bool *timedOut); +#endif + +}; + +QT_END_NAMESPACE + +#endif // QSERIALPORT_WIN_P_H diff --git a/libs/serialport/qserialport_wince.cpp b/libs/serialport/qserialport_wince.cpp new file mode 100644 index 0000000000000000000000000000000000000000..78d2746b16cb32985dcca0b8c944e950069c1436 --- /dev/null +++ b/libs/serialport/qserialport_wince.cpp @@ -0,0 +1,509 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Copyright (C) 2012 Andre Hartmann +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialport_win_p.h" + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QSerialPortPrivate; + +class CommEventNotifier : public QThread +{ + Q_OBJECT +signals: + void eventMask(quint32 mask); + +public: + CommEventNotifier(DWORD mask, QSerialPortPrivate *d, QObject *parent) + : QThread(parent), dptr(d), running(true) { + connect(this, SIGNAL(eventMask(quint32)), this, SLOT(processNotification(quint32))); + ::SetCommMask(dptr->descriptor, mask); + } + + virtual ~CommEventNotifier() { + running = false; + ::SetCommMask(dptr->descriptor, 0); + wait(); + } + +protected: + void run() Q_DECL_OVERRIDE { + DWORD mask = 0; + while (running) { + if (::WaitCommEvent(dptr->descriptor, &mask, FALSE)) { + // Wait until complete the operation changes the port settings, + // see updateDcb(). + dptr->settingsChangeMutex.lock(); + dptr->settingsChangeMutex.unlock(); + emit eventMask(quint32(mask)); + } + } + } + +private slots: + void processNotification(quint32 eventMask) { + + bool error = false; + + // Check for unexpected event. This event triggered when pulled previously + // opened device from the system, when opened as for not to read and not to + // write options and so forth. + if ((eventMask == 0) + || ((eventMask & (EV_ERR | EV_RXCHAR | EV_TXEMPTY)) == 0)) { + error = true; + } + + if (error || (EV_ERR & eventMask)) + dptr->processIoErrors(error); + if (EV_RXCHAR & eventMask) + dptr->notifyRead(); + if (EV_TXEMPTY & eventMask) + dptr->notifyWrite(QSerialPortPrivateData::WriteChunkSize); + } + +private: + QSerialPortPrivate *dptr; + mutable bool running; +}; + +class WaitCommEventBreaker : public QThread +{ + Q_OBJECT +public: + WaitCommEventBreaker(HANDLE descriptor, int timeout, QObject *parent = 0) + : QThread(parent), descriptor(descriptor), timeout(timeout), worked(false) { + start(); + } + + virtual ~WaitCommEventBreaker() { + stop(); + wait(); + } + + void stop() { + exit(0); + } + + bool isWorked() const { + return worked; + } + +protected: + void run() { + QTimer timer; + QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(processTimeout()), Qt::DirectConnection); + timer.start(timeout); + exec(); + worked = true; + } + +private slots: + void processTimeout() { + ::SetCommMask(descriptor, 0); + stop(); + } + +private: + HANDLE descriptor; + int timeout; + mutable bool worked; +}; + +QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q) + : QSerialPortPrivateData(q) + , descriptor(INVALID_HANDLE_VALUE) + , parityErrorOccurred(false) + , eventNotifier(0) +{ +} + +bool QSerialPortPrivate::open(QIODevice::OpenMode mode) +{ + DWORD desiredAccess = 0; + DWORD eventMask = EV_ERR; + + if (mode & QIODevice::ReadOnly) { + desiredAccess |= GENERIC_READ; + eventMask |= EV_RXCHAR; + } + if (mode & QIODevice::WriteOnly) { + desiredAccess |= GENERIC_WRITE; + eventMask |= EV_TXEMPTY; + } + + descriptor = ::CreateFile(reinterpret_cast(systemLocation.utf16()), + desiredAccess, 0, NULL, OPEN_EXISTING, 0, NULL); + + if (descriptor == INVALID_HANDLE_VALUE) { + q_ptr->setError(decodeSystemError()); + return false; + } + + if (!::GetCommState(descriptor, &restoredDcb)) { + q_ptr->setError(decodeSystemError()); + return false; + } + + currentDcb = restoredDcb; + currentDcb.fBinary = true; + currentDcb.fInX = false; + currentDcb.fOutX = false; + currentDcb.fAbortOnError = false; + currentDcb.fNull = false; + currentDcb.fErrorChar = false; + + if (!updateDcb()) + return false; + + if (!::GetCommTimeouts(descriptor, &restoredCommTimeouts)) { + q_ptr->setError(decodeSystemError()); + return false; + } + + ::memset(¤tCommTimeouts, 0, sizeof(currentCommTimeouts)); + currentCommTimeouts.ReadIntervalTimeout = MAXDWORD; + + if (!updateCommTimeouts()) + return false; + + eventNotifier = new CommEventNotifier(eventMask, this, q_ptr); + eventNotifier->start(); + + detectDefaultSettings(); + return true; +} + +void QSerialPortPrivate::close() +{ + if (eventNotifier) { + eventNotifier->deleteLater(); + eventNotifier = 0; + } + + if (settingsRestoredOnClose) { + ::SetCommState(descriptor, &restoredDcb); + ::SetCommTimeouts(descriptor, &restoredCommTimeouts); + } + + ::CloseHandle(descriptor); + descriptor = INVALID_HANDLE_VALUE; +} + +bool QSerialPortPrivate::flush() +{ + return notifyWrite() && ::FlushFileBuffers(descriptor); +} + +bool QSerialPortPrivate::clear(QSerialPort::Directions dir) +{ + DWORD flags = 0; + if (dir & QSerialPort::Input) + flags |= PURGE_RXABORT | PURGE_RXCLEAR; + if (dir & QSerialPort::Output) + flags |= PURGE_TXABORT | PURGE_TXCLEAR; + return ::PurgeComm(descriptor, flags); +} + +qint64 QSerialPortPrivate::bytesAvailable() const +{ + return readBuffer.size(); +} + +qint64 QSerialPortPrivate::readFromBuffer(char *data, qint64 maxSize) +{ + if (readBuffer.isEmpty()) + return 0; + + if (maxSize == 1) { + *data = readBuffer.getChar(); + return 1; + } + + const qint64 bytesToRead = qMin(qint64(readBuffer.size()), maxSize); + qint64 readSoFar = 0; + while (readSoFar < bytesToRead) { + const char *ptr = readBuffer.readPointer(); + const int bytesToReadFromThisBlock = qMin(int(bytesToRead - readSoFar), + readBuffer.nextDataBlockSize()); + ::memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock); + readSoFar += bytesToReadFromThisBlock; + readBuffer.free(bytesToReadFromThisBlock); + } + + return readSoFar; +} + +qint64 QSerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize) +{ + char *ptr = writeBuffer.reserve(maxSize); + if (maxSize == 1) + *ptr = *data; + else + ::memcpy(ptr, data, maxSize); + + // trigger write sequence + notifyWrite(QSerialPortPrivateData::WriteChunkSize); + + return maxSize; +} + +bool QSerialPortPrivate::waitForReadyRead(int msec) +{ + if (!readBuffer.isEmpty()) + return true; + + QElapsedTimer stopWatch; + + stopWatch.start(); + + forever { + bool readyToRead = false; + bool readyToWrite = false; + bool timedOut = false; + if (!waitForReadOrWrite(&readyToRead, &readyToWrite, + true, !writeBuffer.isEmpty(), + timeoutValue(msec, stopWatch.elapsed()), + &timedOut)) { + return false; + } + if (readyToRead) { + if (notifyRead()) + return true; + } + if (readyToWrite) + notifyWrite(WriteChunkSize); + } + return false; +} + +bool QSerialPortPrivate::waitForBytesWritten(int msec) +{ + if (writeBuffer.isEmpty()) + return false; + + QElapsedTimer stopWatch; + + stopWatch.start(); + + forever { + bool readyToRead = false; + bool readyToWrite = false; + bool timedOut = false; + if (!waitForReadOrWrite(&readyToRead, &readyToWrite, + true, !writeBuffer.isEmpty(), + timeoutValue(msec, stopWatch.elapsed()), + &timedOut)) { + return false; + } + if (readyToRead) { + if (!notifyRead()) + return false; + } + if (readyToWrite) { + if (notifyWrite(WriteChunkSize)) + return true; + } + } + return false; +} + +bool QSerialPortPrivate::notifyRead() +{ + DWORD bytesToRead = (policy == QSerialPort::IgnorePolicy) ? ReadChunkSize : 1; + + if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) { + bytesToRead = readBufferMaxSize - readBuffer.size(); + if (bytesToRead == 0) { + // Buffer is full. User must read data from the buffer + // before we can read more from the port. + return false; + } + } + + char *ptr = readBuffer.reserve(bytesToRead); + + DWORD readBytes = 0; + BOOL sucessResult = ::ReadFile(descriptor, ptr, bytesToRead, &readBytes, NULL); + + if (!sucessResult) { + readBuffer.truncate(bytesToRead); + q_ptr->setError(QSerialPort::ReadError); + return false; + } + + readBuffer.truncate(readBytes); + + // Process emulate policy. + if ((policy != QSerialPort::IgnorePolicy) && parityErrorOccurred) { + + parityErrorOccurred = false; + + switch (policy) { + case QSerialPort::SkipPolicy: + readBuffer.getChar(); + return true; + case QSerialPort::PassZeroPolicy: + readBuffer.getChar(); + readBuffer.putChar('\0'); + break; + case QSerialPort::StopReceivingPolicy: + // FIXME: Maybe need disable read notifier? + break; + default: + break; + } + } + + if (readBytes > 0) + emit q_ptr->readyRead(); + + return true; +} + +bool QSerialPortPrivate::notifyWrite(int maxSize) +{ + int nextSize = qMin(writeBuffer.nextDataBlockSize(), maxSize); + + const char *ptr = writeBuffer.readPointer(); + + DWORD bytesWritten = 0; + if (!::WriteFile(descriptor, ptr, nextSize, &bytesWritten, NULL)) { + q_ptr->setError(QSerialPort::WriteError); + return false; + } + + writeBuffer.free(bytesWritten); + + if (bytesWritten > 0) + emit q_ptr->bytesWritten(bytesWritten); + + return true; +} + +bool QSerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectForWrite, + bool checkRead, bool checkWrite, + int msecs, bool *timedOut) +{ + DWORD eventMask = 0; + // FIXME: Here the situation is not properly handled with zero timeout: + // breaker can work out before you call a method WaitCommEvent() + // and so it will loop forever! + WaitCommEventBreaker breaker(descriptor, qMax(msecs, 0)); + ::WaitCommEvent(descriptor, &eventMask, NULL); + breaker.stop(); + + if (breaker.isWorked()) + *timedOut = true; + + if (!breaker.isWorked()) { + if (checkRead) { + Q_ASSERT(selectForRead); + *selectForRead = eventMask & EV_RXCHAR; + } + if (checkWrite) { + Q_ASSERT(selectForWrite); + *selectForWrite = eventMask & EV_TXEMPTY; + } + + return true; + } + + return false; +} + +bool QSerialPortPrivate::updateDcb() +{ + QMutexLocker locker(&settingsChangeMutex); + + DWORD eventMask = 0; + // Save the event mask + if (!::GetCommMask(descriptor, &eventMask)) + return false; + + // Break event notifier from WaitCommEvent + ::SetCommMask(descriptor, 0); + // Change parameters + bool ret = ::SetCommState(descriptor, ¤tDcb); + if (!ret) + q_ptr->setError(decodeSystemError()); + // Restore the event mask + ::SetCommMask(descriptor, eventMask); + + return ret; +} + +bool QSerialPortPrivate::updateCommTimeouts() +{ + if (!::SetCommTimeouts(descriptor, ¤tCommTimeouts)) { + q_ptr->setError(decodeSystemError()); + return false; + } + return true; +} + +static const QLatin1String defaultPathPostfix(":"); + +QString QSerialPortPrivate::portNameToSystemLocation(const QString &port) +{ + QString ret = port; + if (!ret.contains(defaultPathPostfix)) + ret.append(defaultPathPostfix); + return ret; +} + +QString QSerialPortPrivate::portNameFromSystemLocation(const QString &location) +{ + QString ret = location; + if (ret.contains(defaultPathPostfix)) + ret.remove(defaultPathPostfix); + return ret; +} + +#include "qserialport_wince.moc" + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialportglobal.h b/libs/serialport/qserialportglobal.h new file mode 100644 index 0000000000000000000000000000000000000000..34c5ba4ffecda47477ac38f1595cbd2958088ad1 --- /dev/null +++ b/libs/serialport/qserialportglobal.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSERIALPORTGLOBAL_H +#define QSERIALPORTGLOBAL_H + +#include + +QT_BEGIN_NAMESPACE + +#ifndef QT_STATIC +# if defined(QT_BUILD_SERIALPORT_LIB) +# define Q_SERIALPORT_EXPORT Q_DECL_EXPORT +# else +//# define Q_SERIALPORT_EXPORT Q_DECL_IMPORT +# endif +#else +# define Q_SERIALPORT_EXPORT +#endif +# define Q_SERIALPORT_EXPORT +// The macro has been available only since Qt 5.0 +#ifndef Q_DECL_OVERRIDE +#define Q_DECL_OVERRIDE +#endif + +QT_END_NAMESPACE + +#endif // QSERIALPORTGLOBAL_H diff --git a/libs/serialport/qserialportinfo.cpp b/libs/serialport/qserialportinfo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..241d344aea8131b659febfe37ec70456dd377e26 --- /dev/null +++ b/libs/serialport/qserialportinfo.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** +** +** Copyright (C) 2011-2012 Denis Shienkov +** Copyright (C) 2011 Sergey Belyashov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialportinfo.h" +#include "qserialportinfo_p.h" +#include "qserialport.h" + +QT_BEGIN_NAMESPACE + + +/*! + \class QSerialPortInfo + + \brief Provides information about existing serial ports. + + \ingroup serialport-main + \inmodule QtSerialPort + \since 5.1 + + Use the static functions to generate a list of QSerialPortInfo + objects. Each QSerialPortInfo object in the list represents a single + serial port and can be queried for the port name, system location, + description, and manufacturer. The QSerialPortInfo class can also be + used as an input parameter for the setPort() method of the QSerialPort + class. + + \sa QSerialPort +*/ + +/*! + Constructs an empty QSerialPortInfo object. + + \sa isNull() +*/ +QSerialPortInfo::QSerialPortInfo() + : d_ptr(new QSerialPortInfoPrivate) +{ +} + +/*! + Constructs a copy of \a other. +*/ +QSerialPortInfo::QSerialPortInfo(const QSerialPortInfo &other) + : d_ptr(other.d_ptr ? new QSerialPortInfoPrivate(*other.d_ptr) : 0) +{ +} + +/*! + Constructs a QSerialPortInfo object from serial \a port. +*/ +QSerialPortInfo::QSerialPortInfo(const QSerialPort &port) + : d_ptr(new QSerialPortInfoPrivate) +{ + foreach (const QSerialPortInfo &serialPortInfo, availablePorts()) { + if (port.portName() == serialPortInfo.portName()) { + *this = serialPortInfo; + break; + } + } +} + +/*! + Constructs a QSerialPortInfo object from serial port \a name. + + This constructor finds the relevant serial port among the available ones + according to the port name \a name, and constructs the serial port info + instance for that port. +*/ +QSerialPortInfo::QSerialPortInfo(const QString &name) + : d_ptr(new QSerialPortInfoPrivate) +{ + foreach (const QSerialPortInfo &serialPortInfo, availablePorts()) { + if (name == serialPortInfo.portName()) { + *this = serialPortInfo; + break; + } + } +} + +/*! + Destroys the QSerialPortInfo object. References to the values in the + object become invalid. +*/ +QSerialPortInfo::~QSerialPortInfo() +{ +} + +/*! \fn void QSerialPortInfo::swap(QSerialPortInfo &other) + + Swaps QSerialPortInfo \a other with this QSerialPortInfo. This operation is + very fast and never fails. +*/ +void QSerialPortInfo::swap(QSerialPortInfo &other) +{ + d_ptr.swap(other.d_ptr); +} + +/*! + Sets the QSerialPortInfo object to be equal to \a other. +*/ +QSerialPortInfo& QSerialPortInfo::operator=(const QSerialPortInfo &other) +{ + QSerialPortInfo(other).swap(*this); + return *this; +} + +/*! + Returns the name of the serial port. +*/ +QString QSerialPortInfo::portName() const +{ + Q_D(const QSerialPortInfo); + return !d ? QString() : d->portName; +} + +/*! + Returns the system location of the serial port. +*/ +QString QSerialPortInfo::systemLocation() const +{ + Q_D(const QSerialPortInfo); + return !d ? QString() : d->device; +} + +/*! + Returns the description string of the serial port, + if available; otherwise returns an empty string. +*/ +QString QSerialPortInfo::description() const +{ + Q_D(const QSerialPortInfo); + return !d ? QString() : d->description; +} + +/*! + Returns the manufacturer string of the serial port, + if available; otherwise returns an empty string. +*/ +QString QSerialPortInfo::manufacturer() const +{ + Q_D(const QSerialPortInfo); + return !d ? QString() : d->manufacturer; +} + +/*! + Returns the 16-bit vendor number for the serial port, if available; + otherwise returns zero. +*/ +quint16 QSerialPortInfo::vendorIdentifier() const +{ + Q_D(const QSerialPortInfo); + return !d ? 0 : d->vendorIdentifier; +} + +/*! + Returns the 16-bit product number for the serial port, if available; + otherwise returns zero. +*/ +quint16 QSerialPortInfo::productIdentifier() const +{ + Q_D(const QSerialPortInfo); + return !d ? 0 : d->productIdentifier; +} + +/*! + Returns true if there is a valid 16-bit vendor number present; otherwise + returns false. +*/ +bool QSerialPortInfo::hasVendorIdentifier() const +{ + Q_D(const QSerialPortInfo); + return !d ? false : d->hasVendorIdentifier; +} + +/*! + Returns true if there is a valid 16-bit product number present; otherwise + returns false. +*/ +bool QSerialPortInfo::hasProductIdentifier() const +{ + Q_D(const QSerialPortInfo); + return !d ? false : d->hasProductIdentifier; +} + +/*! + \fn bool QSerialPortInfo::isNull() const + + Returns whether this QSerialPortInfo object holds a + serial port definition. +*/ + +/*! + \fn bool QSerialPortInfo::isBusy() const + + Returns true if serial port is busy; + otherwise returns false. +*/ + +/*! + \fn bool QSerialPortInfo::isValid() const + + Returns true if serial port is present on system; + otherwise returns false. +*/ + +/*! + \fn QList QSerialPortInfo::standardBaudRates() + + Returns a list of available standard baud rates supported by + the current serial port. +*/ + +/*! + \fn QList QSerialPortInfo::availablePorts() + + Returns a list of available serial ports on the system. +*/ + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialportinfo.h b/libs/serialport/qserialportinfo.h new file mode 100644 index 0000000000000000000000000000000000000000..cf47939e663f9e7bc21bda972269efe0a28340eb --- /dev/null +++ b/libs/serialport/qserialportinfo.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSERIALPORTINFO_H +#define QSERIALPORTINFO_H + +#include +#include + +#include +//#include + +QT_BEGIN_NAMESPACE + +class QSerialPort; +class QSerialPortInfoPrivate; +class QSerialPortInfoPrivateDeleter; + +class Q_SERIALPORT_EXPORT QSerialPortInfo +{ + Q_DECLARE_PRIVATE(QSerialPortInfo) +public: + QSerialPortInfo(); + explicit QSerialPortInfo(const QSerialPort &port); + explicit QSerialPortInfo(const QString &name); + QSerialPortInfo(const QSerialPortInfo &other); + ~QSerialPortInfo(); + + QSerialPortInfo& operator=(const QSerialPortInfo &other); + void swap(QSerialPortInfo &other); + + QString portName() const; + QString systemLocation() const; + QString description() const; + QString manufacturer() const; + + quint16 vendorIdentifier() const; + quint16 productIdentifier() const; + + bool hasVendorIdentifier() const; + bool hasProductIdentifier() const; + + bool isNull() const; + bool isBusy() const; + bool isValid() const; + + static QList standardBaudRates(); + static QList availablePorts(); + +private: + QScopedPointer d_ptr; +}; + +inline bool QSerialPortInfo::isNull() const +{ return !d_ptr; } + +QT_END_NAMESPACE + +#endif // QSERIALPORTINFO_H diff --git a/libs/serialport/qserialportinfo_mac.cpp b/libs/serialport/qserialportinfo_mac.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1a751dfcaf4dbf84cbd4870d1bb0d7be2d22a8ed --- /dev/null +++ b/libs/serialport/qserialportinfo_mac.cpp @@ -0,0 +1,272 @@ +/**************************************************************************** +** +** Copyright (C) 2011-2012 Denis Shienkov +** Copyright (C) 2011 Sergey Belyashov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialportinfo.h" +#include "qserialportinfo_p.h" + +#include + +#include +#include + +#include +#include // for kIOPropertyProductNameKey +#include +#if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4) +# include +#endif +#include + +QT_BEGIN_NAMESPACE + +enum { MATCHING_PROPERTIES_COUNT = 6 }; + +QList QSerialPortInfo::availablePorts() +{ + QList serialPortInfoList; + + int matchingPropertiesCounter = 0; + + + ::CFMutableDictionaryRef matching = ::IOServiceMatching(kIOSerialBSDServiceValue); + if (!matching) + return serialPortInfoList; + + ::CFDictionaryAddValue(matching, + CFSTR(kIOSerialBSDTypeKey), + CFSTR(kIOSerialBSDAllTypes)); + + io_iterator_t iter = 0; + kern_return_t kr = ::IOServiceGetMatchingServices(kIOMasterPortDefault, + matching, + &iter); + + if (kr != kIOReturnSuccess) + return serialPortInfoList; + + io_registry_entry_t service; + + while ((service = ::IOIteratorNext(iter))) { + + ::CFTypeRef device = 0; + ::CFTypeRef portName = 0; + ::CFTypeRef description = 0; + ::CFTypeRef manufacturer = 0; + ::CFTypeRef vendorIdentifier = 0; + ::CFTypeRef productIdentifier = 0; + + io_registry_entry_t entry = service; + + // Find MacOSX-specific properties names. + do { + + if (!device) { + device = + ::IORegistryEntrySearchCFProperty(entry, + kIOServicePlane, + CFSTR(kIOCalloutDeviceKey), + kCFAllocatorDefault, + 0); + if (device) + ++matchingPropertiesCounter; + } + + if (!portName) { + portName = + ::IORegistryEntrySearchCFProperty(entry, + kIOServicePlane, + CFSTR(kIOTTYDeviceKey), + kCFAllocatorDefault, + 0); + if (portName) + ++matchingPropertiesCounter; + } + + if (!description) { + description = + ::IORegistryEntrySearchCFProperty(entry, + kIOServicePlane, + CFSTR(kIOPropertyProductNameKey), + kCFAllocatorDefault, + 0); + if (!description) + description = + ::IORegistryEntrySearchCFProperty(entry, + kIOServicePlane, + CFSTR(kUSBProductString), + kCFAllocatorDefault, + 0); + if (!description) + description = + ::IORegistryEntrySearchCFProperty(entry, + kIOServicePlane, + CFSTR("BTName"), + kCFAllocatorDefault, + 0); + + if (description) + ++matchingPropertiesCounter; + } + + if (!manufacturer) { + manufacturer = + ::IORegistryEntrySearchCFProperty(entry, + kIOServicePlane, + CFSTR(kUSBVendorString), + kCFAllocatorDefault, + 0); + if (manufacturer) + ++matchingPropertiesCounter; + + } + + if (!vendorIdentifier) { + vendorIdentifier = + ::IORegistryEntrySearchCFProperty(entry, + kIOServicePlane, + CFSTR(kUSBVendorID), + kCFAllocatorDefault, + 0); + if (vendorIdentifier) + ++matchingPropertiesCounter; + + } + + if (!productIdentifier) { + productIdentifier = + ::IORegistryEntrySearchCFProperty(entry, + kIOServicePlane, + CFSTR(kUSBProductID), + kCFAllocatorDefault, + 0); + if (productIdentifier) + ++matchingPropertiesCounter; + + } + + // If all matching properties is found, then force break loop. + if (matchingPropertiesCounter == MATCHING_PROPERTIES_COUNT) + break; + + kr = ::IORegistryEntryGetParentEntry(entry, kIOServicePlane, &entry); + + } while (kr == kIOReturnSuccess); + + (void) ::IOObjectRelease(entry); + + // Convert from MacOSX-specific properties to Qt4-specific. + if (matchingPropertiesCounter > 0) { + + QSerialPortInfo serialPortInfo; + QByteArray buffer(MAXPATHLEN, 0); + + if (device) { + if (::CFStringGetCString(CFStringRef(device), + buffer.data(), + buffer.size(), + kCFStringEncodingUTF8)) { + serialPortInfo.d_ptr->device = QString::fromUtf8(buffer); + } + ::CFRelease(device); + } + + if (portName) { + if (::CFStringGetCString(CFStringRef(portName), + buffer.data(), + buffer.size(), + kCFStringEncodingUTF8)) { + serialPortInfo.d_ptr->portName = QString::fromUtf8(buffer); + } + ::CFRelease(portName); + } + + if (description) { + if (::CFStringGetCString(CFStringRef(description), + buffer.data(), + buffer.size(), + kCFStringEncodingUTF8)) { + serialPortInfo.d_ptr->description = QString::fromUtf8(buffer); + } + ::CFRelease(description); + } + + if (manufacturer) { + if (::CFStringGetCString(CFStringRef(manufacturer), + buffer.data(), + buffer.size(), + kCFStringEncodingUTF8)) { + serialPortInfo.d_ptr->manufacturer = QString::fromUtf8(buffer); + } + ::CFRelease(manufacturer); + } + + quint16 value = 0; + + if (vendorIdentifier) { + serialPortInfo.d_ptr->hasVendorIdentifier = ::CFNumberGetValue(CFNumberRef(vendorIdentifier), kCFNumberIntType, &value); + if (serialPortInfo.d_ptr->hasVendorIdentifier) + serialPortInfo.d_ptr->vendorIdentifier = value; + + ::CFRelease(vendorIdentifier); + } + + if (productIdentifier) { + serialPortInfo.d_ptr->hasProductIdentifier = ::CFNumberGetValue(CFNumberRef(productIdentifier), kCFNumberIntType, &value); + if (serialPortInfo.d_ptr->hasProductIdentifier) + serialPortInfo.d_ptr->productIdentifier = value; + + ::CFRelease(productIdentifier); + } + + serialPortInfoList.append(serialPortInfo); + } + + (void) ::IOObjectRelease(service); + } + + (void) ::IOObjectRelease(iter); + + return serialPortInfoList; +} + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialportinfo_p.h b/libs/serialport/qserialportinfo_p.h new file mode 100644 index 0000000000000000000000000000000000000000..1f12e69bac882758d7264ea7ad36909729199e8b --- /dev/null +++ b/libs/serialport/qserialportinfo_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2011-2012 Denis Shienkov +** Copyright (C) 2011 Sergey Belyashov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSERIALPORTINFO_P_H +#define QSERIALPORTINFO_P_H + +#include + +QT_BEGIN_NAMESPACE + +class QSerialPortInfoPrivate +{ +public: + QSerialPortInfoPrivate() + : vendorIdentifier(0) + , productIdentifier(0) + , hasVendorIdentifier(false) + , hasProductIdentifier(false) + {} + + ~QSerialPortInfoPrivate() {} + + QString portName; + QString device; + QString description; + QString manufacturer; + + quint16 vendorIdentifier; + quint16 productIdentifier; + + bool hasVendorIdentifier; + bool hasProductIdentifier; +}; + +class QSerialPortInfoPrivateDeleter +{ +public: + static void cleanup(QSerialPortInfoPrivate *p) { + delete p; + } +}; + +QT_END_NAMESPACE + +#endif // QSERIALPORTINFO_P_H diff --git a/libs/serialport/qserialportinfo_symbian.cpp b/libs/serialport/qserialportinfo_symbian.cpp new file mode 100644 index 0000000000000000000000000000000000000000..55120485e68235b98fd67c5b1443ea2549cca72d --- /dev/null +++ b/libs/serialport/qserialportinfo_symbian.cpp @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2011-2012 Denis Shienkov +** Copyright (C) 2011 Sergey Belyashov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialportinfo.h" +#include "qserialportinfo_p.h" +#include "qserialport_symbian_p.h" + +#include +//#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +// Physical device driver. +#ifdef __WINS__ +_LIT(KPddName, "ECDRV"); +#else // defined (__EPOC32__) +_LIT(KPddName, "EUART"); +#endif + +// Logical native device driver. +_LIT(KLddName,"ECOMM"); + +// Modules names. +_LIT(KRS232ModuleName , "ECUART"); +_LIT(KBluetoothModuleName , "BTCOMM"); +_LIT(KInfraRedModuleName , "IRCOMM"); +_LIT(KACMModuleName, "ECACM"); + +// Return false on error load. +static bool loadDevices() +{ + TInt r = KErrNone; +#ifdef __WINS__ + RFs fileServer; + r = User::LeaveIfError(fileServer.Connect()); + if (r != KErrNone) + return false; + fileServer.Close (); +#endif + + r = User::LoadPhysicalDevice(KPddName); + if (r != KErrNone && r != KErrAlreadyExists) + return false; //User::Leave(r); + + r = User::LoadLogicalDevice(KLddName); + if (r != KErrNone && r != KErrAlreadyExists) + return false; //User::Leave(r); + +#ifndef __WINS__ + r = StartC32(); + if (r != KErrNone && r != KErrAlreadyExists) + return false; //User::Leave(r); +#endif + + return true; +} + +QList QSerialPortInfo::availablePorts() +{ + QList serialPortInfoList; + + if (!loadDevices()) + return serialPortInfoList; + + RCommServ server; + TInt r = server.Connect(); + if (r != KErrNone) + return serialPortInfoList; //User::LeaveIfError(r); + + TSerialInfo nativeSerialInfo; // Native Symbian OS port info class. + QString s("%1::%2"); + + // FIXME: Get info about RS232 ports. + r = server.LoadCommModule(KRS232ModuleName); + //User::LeaveIfError(r); + if (r == KErrNone) { + r = server.GetPortInfo(KRS232ModuleName, nativeSerialInfo); + if (r == KErrNone) { + for (quint32 i = nativeSerialInfo.iLowUnit; i < nativeSerialInfo.iHighUnit + 1; ++i) { + + QSerialPortInfo serialPortInfo; + + serialPortInfo.d_ptr->device = s + .arg(QString::fromUtf16(nativeSerialInfo.iName.Ptr(), nativeSerialInfo.iName.Length())) + .arg(i); + serialPortInfo.d_ptr->portName = serialPortInfo.d_ptr->device; + serialPortInfo.d_ptr->description = + QString::fromUtf16(nativeSerialInfo.iDescription.Ptr(), nativeSerialInfo.iDescription.Length()); + serialPortInfo.d_ptr->manufacturer = QString(QObject::tr("Unknown.")); + serialPortInfoList.append(serialPortInfo); + } + } + } + + // FIXME: Get info about Bluetooth ports. + r = server.LoadCommModule(KBluetoothModuleName); + //User::LeaveIfError(r); + if (r == KErrNone) { + r = server.GetPortInfo(KBluetoothModuleName, nativeSerialInfo); + if (r == KErrNone) { + for (quint32 i = nativeSerialInfo.iLowUnit; i < nativeSerialInfo.iHighUnit + 1; ++i) { + + QSerialPortInfo serialPortInfo; + + serialPortInfo.d_ptr->device = s + .arg(QString::fromUtf16(nativeSerialInfo.iName.Ptr(), nativeSerialInfo.iName.Length())) + .arg(i); + serialPortInfo.d_ptr->portName = serialPortInfo.d_ptr->device; + serialPortInfo.d_ptr->description = + QString::fromUtf16(nativeSerialInfo.iDescription.Ptr(), nativeSerialInfo.iDescription.Length()); + serialPortInfo.d_ptr->manufacturer = QString(QObject::tr("Unknown.")); + serialPortInfoList.append(serialPortInfo); + } + } + } + + // FIXME: Get info about InfraRed ports. + r = server.LoadCommModule(KInfraRedModuleName); + //User::LeaveIfError(r); + if (r == KErrNone) { + r = server.GetPortInfo(KInfraRedModuleName, nativeSerialInfo); + if (r == KErrNone) { + for (quint32 i = nativeSerialInfo.iLowUnit; i < nativeSerialInfo.iHighUnit + 1; ++i) { + + QSerialPortInfo serialPortInfo; + + serialPortInfo.d_ptr->device = s + .arg(QString::fromUtf16(nativeSerialInfo.iName.Ptr(), nativeSerialInfo.iName.Length())) + .arg(i); + serialPortInfo.d_ptr->portName = serialPortInfo.d_ptr->device; + serialPortInfo.d_ptr->description = + QString::fromUtf16(nativeSerialInfo.iDescription.Ptr(), nativeSerialInfo.iDescription.Length()); + serialPortInfo.d_ptr->manufacturer = QString(QObject::tr("Unknown.")); + serialPortInfoList.append(serialPortInfo); + } + } + } + + // FIXME: Get info about ACM ports. + r = server.LoadCommModule(KACMModuleName); + //User::LeaveIfError(r); + if (r == KErrNone) { + r = server.GetPortInfo(KACMModuleName, nativeSerialInfo); + if (r == KErrNone) { + for (quint32 i = nativeSerialInfo.iLowUnit; i < nativeSerialInfo.iHighUnit + 1; ++i) { + + QSerialPortInfo serialPortInfo; + + serialPortInfo.d_ptr->device = s + .arg(QString::fromUtf16(nativeSerialInfo.iName.Ptr(), nativeSerialInfo.iName.Length())) + .arg(i); + serialPortInfo.d_ptr->portName = QSerialPortPrivate::portNameFromSystemLocation(serialPortInfo.d_ptr->device); + serialPortInfo.d_ptr->description = + QString::fromUtf16(nativeSerialInfo.iDescription.Ptr(), nativeSerialInfo.iDescription.Length()); + serialPortInfo.d_ptr->manufacturer = QString(QObject::tr("Unknown.")); + serialPortInfoList.append(serialPortInfo); + } + } + } + + return serialPortInfoList; +} + +QList QSerialPortInfo::standardBaudRates() +{ + return QSerialPortPrivate::standardBaudRates(); +} + +bool QSerialPortInfo::isBusy() const +{ + if (!loadDevices()) + return false; + + RCommServ server; + TInt r = server.Connect(); + if (r != KErrNone) + return false; + + RComm port; + TPtrC portName(static_cast(systemLocation().utf16()), systemLocation().length()); + r = port.Open(server, portName, ECommExclusive); + if (r == KErrNone) + port.Close(); + return r == KErrLocked; +} + +bool QSerialPortInfo::isValid() const +{ + if (!loadDevices()) + return false; + + RCommServ server; + TInt r = server.Connect(); + if (r != KErrNone) + return false; + + RComm port; + TPtrC portName(static_cast(systemLocation().utf16()), systemLocation().length()); + r = port.Open(server, portName, ECommExclusive); + if (r == KErrNone) + port.Close(); + return r == KErrNone || r == KErrLocked; +} + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialportinfo_unix.cpp b/libs/serialport/qserialportinfo_unix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1d56f4e22bde05311a6912aa0fe328b8dc5d6f3e --- /dev/null +++ b/libs/serialport/qserialportinfo_unix.cpp @@ -0,0 +1,261 @@ +/**************************************************************************** +** +** Copyright (C) 2011-2012 Denis Shienkov +** Copyright (C) 2011 Sergey Belyashov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialportinfo.h" +#include "qserialportinfo_p.h" +#include "qttylocker_unix_p.h" +#include "qserialport_unix_p.h" +#include + +#ifndef Q_OS_MAC + +#if defined (Q_OS_LINUX) && defined (HAVE_LIBUDEV) +extern "C" +{ +#include +} +#else +#include +#include +#endif + +#endif // Q_OS_MAC + +QT_BEGIN_NAMESPACE + +#ifndef Q_OS_MAC + +#if !(defined (Q_OS_LINUX) && defined (HAVE_LIBUDEV)) + +static inline const QStringList& filtersOfDevices() +{ + static const QStringList deviceFileNameFilterList = QStringList() + +# ifdef Q_OS_LINUX + << QLatin1String("ttyS*") // Standart UART 8250 and etc. + << QLatin1String("ttyUSB*") // Usb/serial converters PL2303 and etc. + << QLatin1String("ttyACM*") // CDC_ACM converters (i.e. Mobile Phones). + << QLatin1String("ttyGS*") // Gadget serial device (i.e. Mobile Phones with gadget serial driver). + << QLatin1String("ttyMI*") // MOXA pci/serial converters. + << QLatin1String("ttyAMA*") // AMBA serial device for embedded platform on ARM (i.e. Raspberry Pi). + << QLatin1String("rfcomm*") // Bluetooth serial device. + << QLatin1String("ircomm*"); // IrDA serial device. +# elif defined (Q_OS_FREEBSD) + << QLatin1String("cu*"); +# else + ; // Here for other *nix OS. +# endif + + return deviceFileNameFilterList; +} + +#endif + +QList QSerialPortInfo::availablePorts() +{ + QList serialPortInfoList; + +#if defined (Q_OS_LINUX) && defined (HAVE_LIBUDEV) + + // White list for devices without a parent + static const QString rfcommDeviceName(QLatin1String("rfcomm")); + + struct ::udev *udev = ::udev_new(); + if (udev) { + + struct ::udev_enumerate *enumerate = + ::udev_enumerate_new(udev); + + if (enumerate) { + + ::udev_enumerate_add_match_subsystem(enumerate, "tty"); + ::udev_enumerate_scan_devices(enumerate); + + struct ::udev_list_entry *devices = + ::udev_enumerate_get_list_entry(enumerate); + + struct ::udev_list_entry *dev_list_entry; + udev_list_entry_foreach(dev_list_entry, devices) { + + struct ::udev_device *dev = + ::udev_device_new_from_syspath(udev, + ::udev_list_entry_get_name(dev_list_entry)); + + if (dev) { + + QSerialPortInfo serialPortInfo; + + serialPortInfo.d_ptr->device = + QLatin1String(::udev_device_get_devnode(dev)); + serialPortInfo.d_ptr->portName = + QLatin1String(::udev_device_get_sysname(dev)); + + struct ::udev_device *parentdev = ::udev_device_get_parent(dev); + + bool canAppendToList = true; + + if (parentdev) { + + QLatin1String subsys(::udev_device_get_subsystem(parentdev)); + + if (subsys == QLatin1String("usb-serial") + || subsys == QLatin1String("usb")) { // USB bus type + // Append this devices and try get additional information about them. + serialPortInfo.d_ptr->description = QString( + QLatin1String(::udev_device_get_property_value(dev, + "ID_MODEL"))).replace('_', ' '); + serialPortInfo.d_ptr->manufacturer = QString( + QLatin1String(::udev_device_get_property_value(dev, + "ID_VENDOR"))).replace('_', ' '); + + serialPortInfo.d_ptr->vendorIdentifier = + QString::fromLatin1(::udev_device_get_property_value(dev, + "ID_VENDOR_ID")).toInt(&serialPortInfo.d_ptr->hasVendorIdentifier, 16); + + serialPortInfo.d_ptr->productIdentifier = + QString::fromLatin1(::udev_device_get_property_value(dev, + "ID_MODEL_ID")).toInt(&serialPortInfo.d_ptr->hasProductIdentifier, 16); + + } else if (subsys == QLatin1String("pnp")) { // PNP bus type + // Append this device. + // FIXME: How to get additional information about serial devices + // with this subsystem? + } else if (subsys == QLatin1String("platform")) { // Platform 'pseudo' bus for legacy device. + // Skip this devices because this type of subsystem does + // not include a real physical serial device. + canAppendToList = false; + } else { // Others types of subsystems. + // Append this devices because we believe that any other types of + // subsystems provide a real serial devices. For example, for devices + // such as ttyGSx, its driver provide an empty subsystem name, but it + // devices is a real physical serial devices. + // FIXME: How to get additional information about serial devices + // with this subsystems? + } + } else { // Devices without a parent + if (serialPortInfo.d_ptr->portName.startsWith(rfcommDeviceName)) { // Bluetooth device + bool ok; + // Check for an unsigned decimal integer at the end of the device name: "rfcomm0", "rfcomm15" + // devices with negative and invalid numbers in the name are rejected + int portNumber = serialPortInfo.d_ptr->portName.mid(rfcommDeviceName.length()).toInt(&ok); + + if (!ok || (portNumber < 0) || (portNumber > 255)) { + canAppendToList = false; + } + } else { + canAppendToList = false; + } + } + + if (canAppendToList) + serialPortInfoList.append(serialPortInfo); + + ::udev_device_unref(dev); + } + + } + + ::udev_enumerate_unref(enumerate); + } + + ::udev_unref(udev); + } + +#elif defined (Q_OS_FREEBSD) && defined (HAVE_LIBUSB) + // TODO: Implement me. +#else + + QDir devDir(QLatin1String("/dev")); + if (devDir.exists()) { + + devDir.setNameFilters(filtersOfDevices()); + devDir.setFilter(QDir::Files | QDir::System | QDir::NoSymLinks); + + QStringList foundDevices; // Found devices list. + + foreach (const QFileInfo &deviceFileInfo, devDir.entryInfoList()) { + QString deviceFilePath = deviceFileInfo.absoluteFilePath(); + if (!foundDevices.contains(deviceFilePath)) { + foundDevices.append(deviceFilePath); + + QSerialPortInfo serialPortInfo; + + serialPortInfo.d_ptr->device = deviceFilePath; + serialPortInfo.d_ptr->portName = QSerialPortPrivate::portNameFromSystemLocation(deviceFilePath); + + // Get description, manufacturer, vendor identifier, product + // identifier are not supported. + + serialPortInfoList.append(serialPortInfo); + + } + } + } + +#endif + + return serialPortInfoList; +} + +#endif // Q_OS_MAC + +// common part + +QList QSerialPortInfo::standardBaudRates() +{ + return QSerialPortPrivate::standardBaudRates(); +} + +bool QSerialPortInfo::isBusy() const +{ + bool currentPid = false; + return QTtyLocker::isLocked(portName().toLocal8Bit().constData(), ¤tPid); +} + +bool QSerialPortInfo::isValid() const +{ + QFile f(systemLocation()); + return f.exists(); +} + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialportinfo_win.cpp b/libs/serialport/qserialportinfo_win.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7ca1f5ef4c1cc16b3322a9ad5d9be7354f266aa1 --- /dev/null +++ b/libs/serialport/qserialportinfo_win.cpp @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** Copyright (C) 2011-2012 Denis Shienkov +** Copyright (C) 2011 Sergey Belyashov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialportinfo.h" +#include "qserialportinfo_p.h" +#include "qserialport_win_p.h" + +#ifndef Q_OS_WINCE +#include +#include +#endif + +#include +#include + +QT_BEGIN_NAMESPACE + +#ifndef Q_OS_WINCE + +static const GUID guidsArray[] = +{ + // Windows Ports Class GUID + { 0x4D36E978, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } }, + // Virtual Ports Class GUID (i.e. com0com and etc) + { 0xDF799E12, 0x3C56, 0x421B, { 0xB2, 0x98, 0xB6, 0xD3, 0x64, 0x2B, 0xC8, 0x78 } }, + // Windows Modems Class GUID + { 0x4D36E96D, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } }, + // Eltima Virtual Serial Port Driver v4 GUID + { 0xCC0EF009, 0xB820, 0x42F4, { 0x95, 0xA9, 0x9B, 0xFA, 0x6A, 0x5A, 0xB7, 0xAB } }, + // Advanced Virtual COM Port GUID + { 0x9341CD95, 0x4371, 0x4A37, { 0xA5, 0xAF, 0xFD, 0xB0, 0xA9, 0xD1, 0x96, 0x31 } }, +}; + +static QVariant deviceRegistryProperty(HDEVINFO deviceInfoSet, + PSP_DEVINFO_DATA deviceInfoData, + DWORD property) +{ + DWORD dataType = 0; + DWORD dataSize = 0; + ::SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, + property, &dataType, NULL, 0, &dataSize); + QByteArray data(dataSize, 0); + if (!::SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, NULL, + reinterpret_cast(data.data()), + dataSize, NULL) + || !dataSize) { + return QVariant(); + } + + switch (dataType) { + + case REG_EXPAND_SZ: + case REG_SZ: { + return QVariant(QString::fromWCharArray(reinterpret_cast(data.constData()))); + } + + case REG_MULTI_SZ: { + QStringList list; + int i = 0; + forever { + QString s = QString::fromWCharArray(reinterpret_cast(data.constData()) + i); + i += s.length() + 1; + if (s.isEmpty()) + break; + list.append(s); + } + return QVariant(list); + } + + default: + break; + } + + return QVariant(); +} + +static QString devicePortName(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData) +{ + static const wchar_t portKeyName[] = L"PortName"; + + const HKEY key = ::SetupDiOpenDevRegKey(deviceInfoSet, deviceInfoData, DICS_FLAG_GLOBAL, + 0, DIREG_DEV, KEY_READ); + if (key == INVALID_HANDLE_VALUE) + return QString(); + + DWORD dataSize; + if (::RegQueryValueEx(key, portKeyName, NULL, NULL, NULL, &dataSize) != ERROR_SUCCESS) { + ::RegCloseKey(key); + return QString(); + } + + QByteArray data(dataSize, 0); + + if (::RegQueryValueEx(key, portKeyName, NULL, NULL, + reinterpret_cast(data.data()), &dataSize) != ERROR_SUCCESS) { + ::RegCloseKey(key); + return QString(); + } + ::RegCloseKey(key); + return QString::fromWCharArray(((const wchar_t *)data.constData())); +} + +QList QSerialPortInfo::availablePorts() +{ + static const QString vendorIdentifierPrefix(QLatin1String("VID_")); + static const int vendorIdentifierSize = 4; + static const QString productIdentifierPrefix(QLatin1String("PID_")); + static const int productIdentifierSize = 4; + + QList serialPortInfoList; + static const int guidCount = sizeof(guidsArray)/sizeof(guidsArray[0]); + + for (int i = 0; i < guidCount; ++i) { + const HDEVINFO deviceInfoSet = ::SetupDiGetClassDevs(&guidsArray[i], NULL, 0, DIGCF_PRESENT); + if (deviceInfoSet == INVALID_HANDLE_VALUE) + return serialPortInfoList; + + SP_DEVINFO_DATA deviceInfoData; + ::memset(&deviceInfoData, 0, sizeof(deviceInfoData)); + deviceInfoData.cbSize = sizeof(deviceInfoData); + + DWORD index = 0; + while (::SetupDiEnumDeviceInfo(deviceInfoSet, index++, &deviceInfoData)) { + QSerialPortInfo serialPortInfo; + + QString s = devicePortName(deviceInfoSet, &deviceInfoData); + if (s.isEmpty() || s.contains(QLatin1String("LPT"))) + continue; + + serialPortInfo.d_ptr->portName = s; + serialPortInfo.d_ptr->device = QSerialPortPrivate::portNameToSystemLocation(s); + serialPortInfo.d_ptr->description = + deviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_DEVICEDESC).toString(); + serialPortInfo.d_ptr->manufacturer = + deviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_MFG).toString(); + + s = deviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_HARDWAREID).toStringList().first().toUpper(); + + int index = s.indexOf(vendorIdentifierPrefix); + if (index != -1) + serialPortInfo.d_ptr->vendorIdentifier = s.mid(index + vendorIdentifierPrefix.size(), vendorIdentifierSize) + .toInt(&serialPortInfo.d_ptr->hasVendorIdentifier, 16); + + index = s.indexOf(productIdentifierPrefix); + if (index != -1) + serialPortInfo.d_ptr->productIdentifier = s.mid(index + productIdentifierPrefix.size(), productIdentifierSize) + .toInt(&serialPortInfo.d_ptr->hasProductIdentifier, 16); + + serialPortInfoList.append(serialPortInfo); + } + ::SetupDiDestroyDeviceInfoList(deviceInfoSet); + } + return serialPortInfoList; +} + +#endif + +// common part + +QList QSerialPortInfo::standardBaudRates() +{ + return QSerialPortPrivate::standardBaudRates(); +} + +bool QSerialPortInfo::isBusy() const +{ + const HANDLE descriptor = ::CreateFile(reinterpret_cast(systemLocation().utf16()), + GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + + if (descriptor == INVALID_HANDLE_VALUE) { + if (::GetLastError() == ERROR_ACCESS_DENIED) + return true; + } else { + ::CloseHandle(descriptor); + } + return false; +} + +bool QSerialPortInfo::isValid() const +{ + const HANDLE descriptor = ::CreateFile(reinterpret_cast(systemLocation().utf16()), + GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + + if (descriptor == INVALID_HANDLE_VALUE) { + if (::GetLastError() != ERROR_ACCESS_DENIED) + return false; + } else { + ::CloseHandle(descriptor); + } + return true; +} + +QT_END_NAMESPACE diff --git a/libs/serialport/qserialportinfo_wince.cpp b/libs/serialport/qserialportinfo_wince.cpp new file mode 100644 index 0000000000000000000000000000000000000000..279aceae414064ede27ec745f1c4bf40028408f8 --- /dev/null +++ b/libs/serialport/qserialportinfo_wince.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2011-2012 Denis Shienkov +** Copyright (C) 2011 Sergey Belyashov +** Copyright (C) 2012 Laszlo Papp +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialportinfo.h" +#include "qserialportinfo_p.h" +#include "qserialport_win_p.h" + +#include + +QT_BEGIN_NAMESPACE + +static QString findDescription(HKEY parentKeyHandle, const QString &subKey) +{ + const static QString valueName(QLatin1String("FriendlyName")); + + QString result; + HKEY hSubKey = 0; + LONG res = ::RegOpenKeyEx(parentKeyHandle, reinterpret_cast(subKey.utf16()), + 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hSubKey); + + if (res == ERROR_SUCCESS) { + + DWORD dataType = 0; + DWORD dataSize = 0; + res = ::RegQueryValueEx(hSubKey, reinterpret_cast(valueName.utf16()), + NULL, &dataType, NULL, &dataSize); + + if (res == ERROR_SUCCESS) { + QByteArray data(dataSize, 0); + res = ::RegQueryValueEx(hSubKey, reinterpret_cast(valueName.utf16()), + NULL, NULL, + reinterpret_cast(data.data()), + &dataSize); + + if (res == ERROR_SUCCESS) { + switch (dataType) { + case REG_EXPAND_SZ: + case REG_SZ: + if (dataSize) + result = QString::fromWCharArray(reinterpret_cast(data.constData())); + break; + default: + break; + } + } + } else { + DWORD index = 0; + dataSize = 255; // Max. key length (see MSDN). + QByteArray data(dataSize, 0); + while (::RegEnumKeyEx(hSubKey, index++, + reinterpret_cast(data.data()), &dataSize, + NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { + + result = findDescription(hSubKey, + QString::fromUtf16(reinterpret_cast(data.data()), dataSize)); + if (!result.isEmpty()) + break; + } + } + ::RegCloseKey(hSubKey); + } + return result; +} + +QList QSerialPortInfo::availablePorts() +{ + QList serialPortInfoList; + + DEVMGR_DEVICE_INFORMATION di; + di.dwSize = sizeof(di); + const HANDLE hSearch = ::FindFirstDevice(DeviceSearchByLegacyName, + L"COM*", + &di); + if (hSearch != INVALID_HANDLE_VALUE) { + do { + QSerialPortInfo serialPortInfo; + serialPortInfo.d_ptr->device = QString::fromWCharArray(di.szLegacyName); + serialPortInfo.d_ptr->portName = QSerialPortPrivate::portNameFromSystemLocation(serialPortInfo.d_ptr->device); + serialPortInfo.d_ptr->description = findDescription(HKEY_LOCAL_MACHINE, + QString::fromWCharArray(di.szDeviceKey)); + + // Get manufacturer, vendor identifier, product identifier are not + // possible. + + serialPortInfoList.append(serialPortInfo); + + } while (::FindNextDevice(hSearch, &di)); + ::FindClose(hSearch); + } + + return serialPortInfoList; +} + +QT_END_NAMESPACE diff --git a/libs/serialport/qt4support/install-helper.pri b/libs/serialport/qt4support/install-helper.pri new file mode 100644 index 0000000000000000000000000000000000000000..52577095e3b69e9af0786de0525d104a03d59a3c --- /dev/null +++ b/libs/serialport/qt4support/install-helper.pri @@ -0,0 +1,43 @@ +QTSERIALPORT_PROJECT_INCLUDEDIR = $$QTSERIALPORT_BUILD_ROOT/include/QtSerialPort +QTSERIALPORT_PROJECT_INCLUDEDIR ~=s,/,$$QMAKE_DIR_SEP, + +system("$$QMAKE_MKDIR $$QTSERIALPORT_PROJECT_INCLUDEDIR") + +for(header_file, PUBLIC_HEADERS) { + header_file ~=s,/,$$QMAKE_DIR_SEP, + system("$$QMAKE_COPY \"$${header_file}\" \"$$QTSERIALPORT_PROJECT_INCLUDEDIR\"") +} + +# This is a quick workaround for generating forward header with Qt4. + +unix { + system("echo \'$${LITERAL_HASH}include \"qserialport.h\"\' > \"$$QTSERIALPORT_PROJECT_INCLUDEDIR/QSerialPort\"") + system("echo \'$${LITERAL_HASH}include \"qserialportinfo.h\"\' > \"$$QTSERIALPORT_PROJECT_INCLUDEDIR/QSerialPortInfo\"") +} win32 { + system("echo $${LITERAL_HASH}include \"qserialport.h\" > \"$$QTSERIALPORT_PROJECT_INCLUDEDIR/QSerialPort\"") + system("echo $${LITERAL_HASH}include \"qserialportinfo.h\" > \"$$QTSERIALPORT_PROJECT_INCLUDEDIR/QSerialPortInfo\"") +} + +PUBLIC_HEADERS += \ + $$PUBLIC_HEADERS \ + \"$$QTSERIALPORT_PROJECT_INCLUDEDIR/QSerialPort\" \ + \"$$QTSERIALPORT_PROJECT_INCLUDEDIR/QSerialPortInfo\" + +target_headers.files = $$PUBLIC_HEADERS +target_headers.path = $$[QT_INSTALL_PREFIX]/include/QtSerialPort +INSTALLS += target_headers + +mkspecs_features.files = $$QTSERIALPORT_PROJECT_ROOT/src/serialport/qt4support/serialport.prf +mkspecs_features.path = $$[QT_INSTALL_DATA]/mkspecs/features +INSTALLS += mkspecs_features + +win32 { + dlltarget.path = $$[QT_INSTALL_BINS] + INSTALLS += dlltarget +} + +target.path = $$[QT_INSTALL_LIBS] +INSTALLS += target + +INCLUDEPATH += $$QTSERIALPORT_BUILD_ROOT/include $$QTSERIALPORT_BUILD_ROOT/include/QtSerialPort +DEFINES += QT_BUILD_SERIALPORT_LIB diff --git a/libs/serialport/qt4support/qringbuffer_p.h b/libs/serialport/qt4support/qringbuffer_p.h new file mode 100644 index 0000000000000000000000000000000000000000..ddd10e54358ceb10483e14f2a6bbc3ab0aabc03e --- /dev/null +++ b/libs/serialport/qt4support/qringbuffer_p.h @@ -0,0 +1,451 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRINGBUFFER_P_H +#define QRINGBUFFER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QRingBuffer +{ +public: + explicit inline QRingBuffer(int growth = 4096) : basicBlockSize(growth) { + buffers << QByteArray(); + clear(); + } + + inline int nextDataBlockSize() const { + return (tailBuffer == 0 ? tail : buffers.first().size()) - head; + } + + inline const char *readPointer() const { + return buffers.isEmpty() ? 0 : (buffers.first().constData() + head); + } + + // access the bytes at a specified position + // the out-variable length will contain the amount of bytes readable + // from there, e.g. the amount still the same QByteArray + inline const char *readPointerAtPosition(qint64 pos, qint64 &length) const { + if (buffers.isEmpty()) { + length = 0; + return 0; + } + + if (pos >= bufferSize) { + length = 0; + return 0; + } + + // special case: it is in the first buffer + int nextDataBlockSizeValue = nextDataBlockSize(); + if (pos - head < nextDataBlockSizeValue) { + length = nextDataBlockSizeValue - pos; + return buffers.at(0).constData() + head + pos; + } + + // special case: we only had one buffer and tried to read over it + if (buffers.length() == 1) { + length = 0; + return 0; + } + + // skip the first + pos -= nextDataBlockSizeValue; + + // normal case: it is somewhere in the second to the-one-before-the-tailBuffer + for (int i = 1; i < tailBuffer; i++) { + if (pos >= buffers[i].size()) { + pos -= buffers[i].size(); + continue; + } + + length = buffers[i].length() - pos; + return buffers[i].constData() + pos; + } + + // it is in the tail buffer + length = tail - pos; + return buffers[tailBuffer].constData() + pos; + } + + inline void free(int bytes) { + bufferSize -= bytes; + if (bufferSize < 0) + bufferSize = 0; + + for (;;) { + int nextBlockSize = nextDataBlockSize(); + if (bytes < nextBlockSize) { + head += bytes; + if (head == tail && tailBuffer == 0) + head = tail = 0; + break; + } + + bytes -= nextBlockSize; + if (buffers.count() == 1) { + if (buffers.at(0).size() != basicBlockSize) + buffers[0].resize(basicBlockSize); + head = tail = 0; + tailBuffer = 0; + break; + } + + buffers.removeAt(0); + --tailBuffer; + head = 0; + } + + if (isEmpty()) + clear(); // try to minify/squeeze us + } + + inline char *reserve(int bytes) { + // if this is a fresh empty QRingBuffer + if (bufferSize == 0) { + buffers[0].resize(qMax(basicBlockSize, bytes)); + bufferSize += bytes; + tail = bytes; + return buffers[tailBuffer].data(); + } + + bufferSize += bytes; + + // if there is already enough space, simply return. + if (tail + bytes <= buffers.at(tailBuffer).size()) { + char *writePtr = buffers[tailBuffer].data() + tail; + tail += bytes; + return writePtr; + } + + // if our buffer isn't half full yet, simply resize it. + if (tail < buffers.at(tailBuffer).size() / 2) { + buffers[tailBuffer].resize(tail + bytes); + char *writePtr = buffers[tailBuffer].data() + tail; + tail += bytes; + return writePtr; + } + + // shrink this buffer to its current size + buffers[tailBuffer].resize(tail); + + // create a new QByteArray with the right size + buffers << QByteArray(); + ++tailBuffer; + buffers[tailBuffer].resize(qMax(basicBlockSize, bytes)); + tail = bytes; + return buffers[tailBuffer].data(); + } + + inline void truncate(int pos) { + if (pos < size()) + chop(size() - pos); + } + + inline void chop(int bytes) { + bufferSize -= bytes; + if (bufferSize < 0) + bufferSize = 0; + + for (;;) { + // special case: head and tail are in the same buffer + if (tailBuffer == 0) { + tail -= bytes; + if (tail <= head) + tail = head = 0; + return; + } + + if (bytes <= tail) { + tail -= bytes; + return; + } + + bytes -= tail; + buffers.removeAt(tailBuffer); + + --tailBuffer; + tail = buffers.at(tailBuffer).size(); + } + + if (isEmpty()) + clear(); // try to minify/squeeze us + } + + inline bool isEmpty() const { + return tailBuffer == 0 && tail == 0; + } + + inline int getChar() { + if (isEmpty()) + return -1; + char c = *readPointer(); + free(1); + return int(uchar(c)); + } + + inline void putChar(char c) { + char *ptr = reserve(1); + *ptr = c; + } + + inline void ungetChar(char c) { + --head; + if (head < 0) { + buffers.prepend(QByteArray()); + buffers[0].resize(basicBlockSize); + head = basicBlockSize - 1; + ++tailBuffer; + } + buffers[0][head] = c; + ++bufferSize; + } + + inline int size() const { + return bufferSize; + } + + inline void clear() { + buffers.erase(buffers.begin() + 1, buffers.end()); + buffers[0].resize(0); + buffers[0].squeeze(); + + head = tail = 0; + tailBuffer = 0; + bufferSize = 0; + } + + inline int indexOf(char c) const { + int index = 0; + for (int i = 0; i < buffers.size(); ++i) { + int start = 0; + int end = buffers.at(i).size(); + + if (i == 0) + start = head; + if (i == tailBuffer) + end = tail; + const char *ptr = buffers.at(i).data() + start; + for (int j = start; j < end; ++j) { + if (*ptr++ == c) + return index; + ++index; + } + } + return -1; + } + + inline int indexOf(char c, int maxLength) const { + int index = 0; + int remain = qMin(size(), maxLength); + for (int i = 0; remain && i < buffers.size(); ++i) { + int start = 0; + int end = buffers.at(i).size(); + + if (i == 0) + start = head; + if (i == tailBuffer) + end = tail; + if (remain < end - start) { + end = start + remain; + remain = 0; + } else { + remain -= end - start; + } + const char *ptr = buffers.at(i).data() + start; + for (int j = start; j < end; ++j) { + if (*ptr++ == c) + return index; + ++index; + } + } + return -1; + } + + inline int read(char *data, int maxLength) { + int bytesToRead = qMin(size(), maxLength); + int readSoFar = 0; + while (readSoFar < bytesToRead) { + const char *ptr = readPointer(); + int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar, nextDataBlockSize()); + if (data) + memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock); + readSoFar += bytesToReadFromThisBlock; + free(bytesToReadFromThisBlock); + } + return readSoFar; + } + + inline QByteArray read(int maxLength) { + QByteArray tmp; + tmp.resize(qMin(maxLength, size())); + read(tmp.data(), tmp.size()); + return tmp; + } + + inline QByteArray readAll() { + return read(size()); + } + + // read an unspecified amount (will read the first buffer) + inline QByteArray read() { + if (bufferSize == 0) + return QByteArray(); + + // multiple buffers, just take the first one + if (head == 0 && tailBuffer != 0) { + QByteArray qba = buffers.takeFirst(); + --tailBuffer; + bufferSize -= qba.length(); + return qba; + } + + // one buffer with good value for head. Just take it. + if (head == 0 && tailBuffer == 0) { + QByteArray qba = buffers.takeFirst(); + qba.resize(tail); + buffers << QByteArray(); + bufferSize = 0; + tail = 0; + return qba; + } + + // Bad case: We have to memcpy. + // We can avoid by initializing the QRingBuffer with basicBlockSize of 0 + // and only using this read() function. + QByteArray qba(readPointer(), nextDataBlockSize()); + buffers.removeFirst(); + head = 0; + if (tailBuffer == 0) { + buffers << QByteArray(); + tail = 0; + } else { + --tailBuffer; + } + bufferSize -= qba.length(); + return qba; + } + + // append a new buffer to the end + inline void append(const QByteArray &qba) { + buffers[tailBuffer].resize(tail); + buffers << qba; + ++tailBuffer; + tail = qba.length(); + bufferSize += qba.length(); + } + + inline QByteArray peek(int maxLength) const { + int bytesToRead = qMin(size(), maxLength); + if (maxLength <= 0) + return QByteArray(); + QByteArray ret; + ret.resize(bytesToRead); + int readSoFar = 0; + for (int i = 0; readSoFar < bytesToRead && i < buffers.size(); ++i) { + int start = 0; + int end = buffers.at(i).size(); + if (i == 0) + start = head; + if (i == tailBuffer) + end = tail; + const int len = qMin(ret.size()-readSoFar, end-start); + memcpy(ret.data()+readSoFar, buffers.at(i).constData()+start, len); + readSoFar += len; + } + Q_ASSERT(readSoFar == ret.size()); + return ret; + } + + inline int skip(int length) { + return read(0, length); + } + + inline int readLine(char *data, int maxLength) { + int index = indexOf('\n'); + if (index == -1) + return read(data, maxLength); + if (maxLength <= 0) + return -1; + + int readSoFar = 0; + while (readSoFar < index + 1 && readSoFar < maxLength - 1) { + int bytesToRead = qMin((index + 1) - readSoFar, nextDataBlockSize()); + bytesToRead = qMin(bytesToRead, (maxLength - 1) - readSoFar); + memcpy(data + readSoFar, readPointer(), bytesToRead); + readSoFar += bytesToRead; + free(bytesToRead); + } + + // Terminate it. + data[readSoFar] = '\0'; + return readSoFar; + } + + inline bool canReadLine() const { + return indexOf('\n') != -1; + } + +private: + QList buffers; + int head, tail; + int tailBuffer; // always buffers.size() - 1 + int basicBlockSize; + int bufferSize; +}; + +QT_END_NAMESPACE + +#endif // QRINGBUFFER_P_H diff --git a/libs/serialport/qt4support/qwineventnotifier_p.h b/libs/serialport/qt4support/qwineventnotifier_p.h new file mode 100644 index 0000000000000000000000000000000000000000..bd1203e59c176bbe20fcf7e9c9ff7200354aee3b --- /dev/null +++ b/libs/serialport/qt4support/qwineventnotifier_p.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINEVENTNOTIFIER_P_H +#define QWINEVENTNOTIFIER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qobject.h" +#include "QtCore/qt_windows.h" + +QT_BEGIN_NAMESPACE + +class Q_CORE_EXPORT QWinEventNotifier : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QObject) + +public: + explicit QWinEventNotifier(QObject *parent = 0); + explicit QWinEventNotifier(HANDLE hEvent, QObject *parent = 0); + ~QWinEventNotifier(); + + void setHandle(HANDLE hEvent); + HANDLE handle() const; + + bool isEnabled() const; + +public Q_SLOTS: + void setEnabled(bool enable); + +Q_SIGNALS: + void activated(HANDLE hEvent); + +protected: + bool event(QEvent * e); + +private: + Q_DISABLE_COPY(QWinEventNotifier) + + HANDLE handleToEvent; + bool enabled; +}; + +QT_END_NAMESPACE + +#endif // QWINEVENTNOTIFIER_P_H diff --git a/libs/serialport/qt4support/serialport.prf b/libs/serialport/qt4support/serialport.prf new file mode 100644 index 0000000000000000000000000000000000000000..9779b4c8224a05b0ecfc104d0a9f8af6812cd4e7 --- /dev/null +++ b/libs/serialport/qt4support/serialport.prf @@ -0,0 +1,27 @@ +qtAddLibrary(QtSerialPort) + +!isEmpty(QTSERIALPORT_BUILD_ROOT) { + INCLUDEPATH -= $$QMAKE_INCDIR_QT/QtSerialPort + QMAKE_INCDIR += $$QTSERIALPORT_BUILD_ROOT/include $$QTSERIALPORT_BUILD_ROOT/include/QtSerialPort + + QTSERIALPORT_BUILD_SUBDIR = src/serialport + debug_and_release_target { + CONFIG(debug, debug|release) { + QTSERIALPORT_BUILD_SUBDIR = $$QTSERIALPORT_BUILD_SUBDIR/debug + } else { + QTSERIALPORT_BUILD_SUBDIR = $$QTSERIALPORT_BUILD_SUBDIR/release + } + } + + QMAKE_LIBDIR += $$QTSERIALPORT_BUILD_ROOT/$$QTSERIALPORT_BUILD_SUBDIR +} + +mac { + LIBS -= -framework QtSerialPort$${QT_LIBINFIX} + + if(!debug_and_release|build_pass):CONFIG(debug, debug|release) { + LIBS += -lQtSerialPort$${QT_LIBINFIX}_debug + } else { + LIBS += -lQtSerialPort$${QT_LIBINFIX} + } +} diff --git a/libs/serialport/qttylocker_unix.cpp b/libs/serialport/qttylocker_unix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8184bd9c035998dd912495a9adc976a28a129f76 --- /dev/null +++ b/libs/serialport/qttylocker_unix.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qttylocker_unix_p.h" + +#ifdef HAVE_BAUDBOY_H +# include +# include +#elif defined (HAVE_LOCKDEV_H) +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +#endif // defined (HAVE_BAUDBOY_H) + +QT_BEGIN_NAMESPACE + +#if !(defined (HAVE_BAUDBOY_H) || defined (HAVE_LOCKDEV_H)) + +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) +# define QStringLiteral QLatin1String +#endif + +static inline const QStringList& lockDirectoryList() +{ + static const QStringList lockDirectoryEntries = QStringList() + << QStringLiteral("/var/lock") + << QStringLiteral("/etc/locks") + << QStringLiteral("/var/spool/locks") + << QStringLiteral("/var/spool/uucp") + << QStringLiteral("/tmp"); + + return lockDirectoryEntries; +} + +// Returns the full path first found in the directory where you can create a lock file +// (ie a directory with access to the read/write). +// Verification of directories is of the order in accordance with the order +// of records in the variable lockDirList. +static +QString lookupFirstSharedLockDir() +{ + QStringList directoryList = lockDirectoryList(); + + foreach (const QString &lockDirectory, directoryList) { + if (::access(lockDirectory.toLocal8Bit().constData(), R_OK | W_OK) == 0) + return lockDirectory; + } + return QString(); +} + +// Returns the name of the lock file which is tied to the +// device name, eg "LCK..ttyS0", etc. +static +QString generateLockFileNameAsNamedForm(const char *portName) +{ + QString result(lookupFirstSharedLockDir()); + if (!result.isEmpty()) { + result.append(QLatin1String("/LCK..")); + result.append(QString::fromLatin1(portName).replace(QLatin1Char('/'), QLatin1Char('_'))); + } + return result; +} + +#endif //!(defined (HAVE_BAUDBOY_H) || defined (HAVE_LOCKDEV_H)) + +// Try lock serial device. However, other processes can not access it. +bool QTtyLocker::lock(const char *portName) +{ +#ifdef HAVE_BAUDBOY_H + if (::ttylock(portName) + ::ttywait(portName); + return ::ttylock(portName) != -1; +#elif defined (HAVE_LOCKDEV_H) + return ::dev_lock(portName) != -1; +#else + QFile f(generateLockFileNameAsNamedForm(portName)); + if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + QString content(QLatin1String(" %1 %2\x0A")); + content = content.arg(::getpid()).arg(::getuid()); + if (f.write(content.toLocal8Bit()) > 0) { + f.close(); + return true; + } + f.close(); + } + return false; +#endif +} + +// Try unlock serial device. However, other processes can access it. +bool QTtyLocker::unlock(const char *portName) +{ +#ifdef HAVE_BAUDBOY_H + return ::ttyunlock(portName != -1; +#elif defined (HAVE_LOCKDEV_H) + return ::dev_unlock(portName, ::getpid()) != -1; +#else + QFile f(generateLockFileNameAsNamedForm(portName)); + return f.remove(); +#endif +} + +// Verifies the device is locked or not. +// If returned currentPid = true - this means that the device is locked the current process. +bool QTtyLocker::isLocked(const char *portName, bool *currentPid) +{ + if (!currentPid) + return true; + + *currentPid = false; + +#ifdef HAVE_BAUDBOY_H + return ::ttylocked(portName) != -1; +#elif defined (HAVE_LOCKDEV_H) + return ::dev_testlock(portName) != -1; +#else + + QFile f(generateLockFileNameAsNamedForm(portName)); + if (!f.exists()) + return false; + if (!f.open(QIODevice::ReadOnly)) + return true; + + QString content(QLatin1String(f.readAll())); + f.close(); + + const pid_t pid = content.section(' ', 0, 0, QString::SectionSkipEmpty).toInt(); + + if (::kill(pid, 0) == -1) { + if (errno == ESRCH) // Process does not exists + return false; + } else { + if (::getpid() == pid) // Process exists and it is "their", i.e current + *currentPid = true; + } + + return true; + +#endif +} + +QT_END_NAMESPACE diff --git a/libs/serialport/qttylocker_unix_p.h b/libs/serialport/qttylocker_unix_p.h new file mode 100644 index 0000000000000000000000000000000000000000..9dce5d05dea4a1ba5da0511982273c9392c36693 --- /dev/null +++ b/libs/serialport/qttylocker_unix_p.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Denis Shienkov +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#ifndef TTYLOCKER_UNIX_P_H +#define TTYLOCKER_UNIX_P_H + +QT_BEGIN_NAMESPACE + +class QTtyLocker +{ +public: + static bool lock(const char *portName); + static bool unlock(const char *portName); + static bool isLocked(const char *portName, bool *currentPid); +}; + +QT_END_NAMESPACE + +#endif // TTYLOCKER_UNIX_P_H diff --git a/libs/serialport/serialport-lib.pri b/libs/serialport/serialport-lib.pri new file mode 100644 index 0000000000000000000000000000000000000000..db8ff74604c51269c8ebccd1d3c659842ad3fd81 --- /dev/null +++ b/libs/serialport/serialport-lib.pri @@ -0,0 +1,87 @@ +INCLUDEPATH += $$PWD + +unix { + CONFIG += link_pkgconfig + + packagesExist(libudev) { + DEFINES += HAVE_LIBUDEV + PKGCONFIG += libudev + } +} + +PUBLIC_HEADERS += \ + $$PWD/qserialportglobal.h \ + $$PWD/qserialport.h \ + $$PWD/qserialportinfo.h + +PRIVATE_HEADERS += \ + $$PWD/qserialport_p.h \ + $$PWD/qserialportinfo_p.h + +SOURCES += \ + $$PWD/qserialport.cpp \ + $$PWD/qserialportinfo.cpp + +win32 { + PRIVATE_HEADERS += \ + $$PWD/qserialport_win_p.h + + SOURCES += \ + $$PWD/qserialport_win.cpp \ + $$PWD/qserialportinfo_win.cpp + + !wince*: { + LIBS += -lsetupapi -ladvapi32 + } else { + SOURCES += \ + $$PWD/qserialport_wince.cpp \ + $$PWD/qserialportinfo_wince.cpp + } +} + +symbian { + MMP_RULES += EXPORTUNFROZEN + #MMP_RULES += DEBUGGABLE_UDEBONLY + TARGET.UID3 = 0xE7E62DFD + TARGET.CAPABILITY = + TARGET.EPOCALLOWDLLDATA = 1 + addFiles.sources = QtSerialPort.dll + addFiles.path = !:/sys/bin + DEPLOYMENT += addFiles + + # FIXME !!! + #INCLUDEPATH += c:/Nokia/devices/Nokia_Symbian3_SDK_v1.0/epoc32/include/platform + INCLUDEPATH += c:/QtSDK/Symbian/SDKs/Symbian3Qt473/epoc32/include/platform + + PRIVATE_HEADERS += \ + $$PWD/qserialport_symbian_p.h + + SOURCES += \ + $$PWD/qserialport_symbian.cpp \ + $$PWD/qserialportinfo_symbian.cpp + + LIBS += -leuser -lefsrv -lc32 +} + +unix:!symbian { + PRIVATE_HEADERS += \ + $$PWD/qttylocker_unix_p.h \ + $$PWD/qserialport_unix_p.h + + SOURCES += \ + $$PWD/qttylocker_unix.cpp \ + $$PWD/qserialport_unix.cpp \ + $$PWD/qserialportinfo_unix.cpp + + macx { + SOURCES += $$PWD/qserialportinfo_mac.cpp + + LIBS += -framework IOKit -framework CoreFoundation + } else { + linux*:contains( DEFINES, HAVE_LIBUDEV ) { + LIBS += -ludev + } + } +} + +HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS diff --git a/libs/serialport/serialport.pro b/libs/serialport/serialport.pro new file mode 100644 index 0000000000000000000000000000000000000000..d329a0b782bf0c02c14f21afc59377e35730f721 --- /dev/null +++ b/libs/serialport/serialport.pro @@ -0,0 +1,17 @@ +QT = core + +QMAKE_DOCS = $$PWD/doc/qtserialport.qdocconf +include($$PWD/serialport-lib.pri) + +greaterThan(QT_MAJOR_VERSION, 4) { + load(qt_build_config) + QT += core-private + TARGET = QtSerialPort + load(qt_module) +} else { + TEMPLATE = lib + TARGET = $$qtLibraryTarget(QtSerialPort$$QT_LIBINFIX) + include($$PWD/qt4support/install-helper.pri) + CONFIG += module create_prl + mac:QMAKE_FRAMEWORK_BUNDLE_NAME = $$TARGET +} diff --git a/qgcunittest.pro b/qgcunittest.pro index 308ce32dc84423a9cdfd85bed225b2bd8ab109a0..b8b8a5d564e2a318327f50c45d160f652e402aa2 100644 --- a/qgcunittest.pro +++ b/qgcunittest.pro @@ -200,6 +200,7 @@ FORMS += src/ui/MainWindow.ui \ src/ui/QGCMAVLinkLogPlayer.ui \ src/ui/QGCWaypointListMulti.ui \ src/ui/QGCUDPLinkConfiguration.ui \ + src/ui/QGCTCPLinkConfiguration.ui \ src/ui/QGCSettingsWidget.ui \ src/ui/UASControlParameters.ui \ src/ui/map/QGCMapTool.ui \ @@ -323,6 +324,7 @@ HEADERS += src/MG.h \ src/uas/QGCMAVLinkUASFactory.h \ src/ui/QGCWaypointListMulti.h \ src/ui/QGCUDPLinkConfiguration.h \ + src/ui/QGCTCPLinkConfiguration.h \ src/ui/QGCSettingsWidget.h \ src/ui/uas/UASControlParameters.h \ src/uas/QGCUASParamManager.h \ @@ -490,6 +492,7 @@ SOURCES += src/QGCCore.cc \ src/uas/QGCMAVLinkUASFactory.cc \ src/ui/QGCWaypointListMulti.cc \ src/ui/QGCUDPLinkConfiguration.cc \ + src/ui/QGCTCPLinkConfiguration.cc \ src/ui/QGCSettingsWidget.cc \ src/ui/uas/UASControlParameters.cpp \ src/uas/QGCUASParamManager.cc \ diff --git a/qgroundcontrol.pri b/qgroundcontrol.pri index 5b14ef2935facd1d41705abb8ebc80fd747bc48e..a7599d7c51d24cdd46968a7ff79667ba4636598f 100644 --- a/qgroundcontrol.pri +++ b/qgroundcontrol.pri @@ -28,6 +28,14 @@ win32-msvc2008|win32-msvc2010|win32-msvc2012 { # Turn off serial port warnings DEFINES += _TTY_NOWARN_ +# This is the list of application resources which must be copied to the build target location +# We create one list and use it in each build type so that the various build flavors don't +# get out of sync. +COPY_RESOURCE_LIST = \ + $$BASEDIR/files \ + $$BASEDIR/qml \ + $$BASEDIR/data + # MAC OS X macx|macx-g++42|macx-g++|macx-llvm: { @@ -47,80 +55,74 @@ macx|macx-g++42|macx-g++|macx-llvm: { ICON = $$BASEDIR/files/images/icons/macx.icns - # Copy contributed files - QMAKE_POST_LINK += && cp -rf $$BASEDIR/files $$TARGETDIR/qgroundcontrol.app/Contents/MacOS - # Copy google earth starter file - QMAKE_POST_LINK += && cp -f $$BASEDIR/files/images/earth.html $$TARGETDIR/qgroundcontrol.app/Contents/MacOS - # Copy CSS stylesheets - QMAKE_POST_LINK += && cp -f $$BASEDIR/files/styles/style-dark.css $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/style-dark.css - QMAKE_POST_LINK += && cp -f $$BASEDIR/files/styles/style-light.css $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/style-light.css - # Copy support files - QMAKE_POST_LINK += && cp -rf $$BASEDIR/files $$TARGETDIR/qgroundcontrol.app/Contents/MacOS + # Copy application resources + for(COPY_DIR, COPY_RESOURCE_LIST):QMAKE_POST_LINK += && cp -rf $${COPY_DIR} $$TARGETDIR/qgroundcontrol.app/Contents/MacOS + # Copy MAVLink QMAKE_POST_LINK += && cp -rf $$BASEDIR/libs/mavlink $$TARGETDIR/qgroundcontrol.app/Contents/MacOS # Copy libraries - QMAKE_POST_LINK += && mkdir -p $$TARGETDIR/qgroundcontrol.app/Contents/libs - QMAKE_POST_LINK += && cp -rf $$BASEDIR/libs/lib/mac64/lib/* $$TARGETDIR/qgroundcontrol.app/Contents/libs + QMAKE_POST_LINK += && mkdir -p $$TARGETDIR/qgroundcontrol.app/Contents/libs + QMAKE_POST_LINK += && cp -rf $$BASEDIR/libs/lib/mac64/lib/* $$TARGETDIR/qgroundcontrol.app/Contents/libs # Copy frameworks QMAKE_POST_LINK += && mkdir -p $$TARGETDIR/qgroundcontrol.app/Contents/Frameworks QMAKE_POST_LINK += && cp -rf $$BASEDIR/libs/lib/Frameworks/* $$TARGETDIR/qgroundcontrol.app/Contents/Frameworks # Fix library paths inside executable - QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol - QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol - QMAKE_POST_LINK += && install_name_tool -change libosgViewer.dylib "@executable_path/../libs/libosgViewer.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol - QMAKE_POST_LINK += && install_name_tool -change libosgGA.dylib "@executable_path/../libs/libosgGA.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol - QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol - QMAKE_POST_LINK += && install_name_tool -change libosgText.dylib "@executable_path/../libs/libosgText.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol - QMAKE_POST_LINK += && install_name_tool -change libosgWidget.dylib "@executable_path/../libs/libosgWidget.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol + QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol + QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol + QMAKE_POST_LINK += && install_name_tool -change libosgViewer.dylib "@executable_path/../libs/libosgViewer.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol + QMAKE_POST_LINK += && install_name_tool -change libosgGA.dylib "@executable_path/../libs/libosgGA.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol + QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol + QMAKE_POST_LINK += && install_name_tool -change libosgText.dylib "@executable_path/../libs/libosgText.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol + QMAKE_POST_LINK += && install_name_tool -change libosgWidget.dylib "@executable_path/../libs/libosgWidget.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol # Fix library paths within libraries (inter-library dependencies) # OSG GA LIBRARY - QMAKE_POST_LINK += && install_name_tool -change libosgGA.dylib "@executable_path/../libs/libosgGA.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib - QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib - QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgGA.dylib "@executable_path/../libs/libosgGA.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib + QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib + QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgGA.dylib # OSG DB LIBRARY - QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgDB.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgDB.dylib - QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgDB.dylib - QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgDB.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgDB.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgDB.dylib + QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgDB.dylib + QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgDB.dylib # OSG TEXT LIBRARY - QMAKE_POST_LINK += && install_name_tool -change libosgText.dylib "@executable_path/../libs/libosgText.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib - QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib - QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgText.dylib "@executable_path/../libs/libosgText.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib + QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib + QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgText.dylib # OSG UTIL LIBRARY - QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgUtil.dylib - QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgUtil.dylib + QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgUtil.dylib + QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgUtil.dylib # OSG VIEWER LIBRARY - QMAKE_POST_LINK += && install_name_tool -change libosgGA.dylib "@executable_path/../libs/libosgGA.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgText.dylib "@executable_path/../libs/libosgText.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib - QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib - QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgGA.dylib "@executable_path/../libs/libosgGA.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgText.dylib "@executable_path/../libs/libosgText.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib + QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib + QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgViewer.dylib # OSG WIDGET LIBRARY - QMAKE_POST_LINK += && install_name_tool -change libosgGA.dylib "@executable_path/../libs/libosgGA.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgText.dylib "@executable_path/../libs/libosgText.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib - QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib - QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib - QMAKE_POST_LINK += && install_name_tool -change libosgViewer.dylib "@executable_path/../libs/libosgViewer.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgGA.dylib "@executable_path/../libs/libosgGA.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgText.dylib "@executable_path/../libs/libosgText.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgDB.dylib "@executable_path/../libs/libosgDB.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgUtil.dylib "@executable_path/../libs/libosgUtil.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib + QMAKE_POST_LINK += && install_name_tool -change libosg.dylib "@executable_path/../libs/libosg.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib + QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib + QMAKE_POST_LINK += && install_name_tool -change libosgViewer.dylib "@executable_path/../libs/libosgViewer.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosgWidget.dylib # CORE OSG LIBRARY - QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosg.dylib + QMAKE_POST_LINK += && install_name_tool -change libOpenThreads.dylib "@executable_path/../libs/libOpenThreads.dylib" $$TARGETDIR/qgroundcontrol.app/Contents/libs/libosg.dylib # SDL Framework QMAKE_POST_LINK += && install_name_tool -change "@rpath/SDL.framework/Versions/A/SDL" "@executable_path/../Frameworks/SDL.framework/Versions/A/SDL" $$TARGETDIR/qgroundcontrol.app/Contents/MacOS/qgroundcontrol @@ -243,10 +245,9 @@ linux-g++|linux-g++-64{ QMAKE_POST_LINK += && mkdir -p $$TARGETDIR } DESTDIR = $$TARGETDIR - QMAKE_POST_LINK += && cp -rf $$BASEDIR/files $$TARGETDIR - QMAKE_POST_LINK += && cp -rf $$BASEDIR/data $$TARGETDIR - QMAKE_POST_LINK += && mkdir -p $$TARGETDIR/files/images - QMAKE_POST_LINK += && cp -rf $$BASEDIR/files/styles/Vera.ttf $$TARGETDIR/files/styles/Vera.ttf + + # Copy application resources + for(COPY_DIR, COPY_RESOURCE_LIST):QMAKE_POST_LINK += && cp -rf $${COPY_DIR} $$TARGETDIR # osg/osgEarth dynamic casts might fail without this compiler option. # see http://osgearth.org/wiki/FAQ for details. @@ -333,6 +334,7 @@ win32-msvc2008|win32-msvc2010|win32-msvc2012 { # Copy dependencies BASEDIR_WIN = $$replace(BASEDIR,"/","\\") TARGETDIR_WIN = $$replace(TARGETDIR,"/","\\") + COPY_RESOURCE_LIST_WIN = $$replace(COPY_RESOURCE_LIST, "/","\\") CONFIG(debug, debug|release) { # Copy supporting library DLLs @@ -341,8 +343,7 @@ win32-msvc2008|win32-msvc2010|win32-msvc2012 { QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$BASEDIR_WIN\\libs\\thirdParty\\libxbee\\lib\\libxbee.dll" "$$TARGETDIR_WIN\\debug"$$escape_expand(\\n)) # Copy application resources - QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$BASEDIR_WIN\\files" "$$TARGETDIR_WIN\\debug\\files" /E /I $$escape_expand(\\n)) - QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$BASEDIR_WIN\\models" "$$TARGETDIR_WIN\\debug\\models" /E /I $$escape_expand(\\n)) + for(COPY_DIR, COPY_RESOURCE_LIST):QMAKE_POST_LINK += $$quote(xcopy /D /Y "$${COPY_DIR}" "$$TARGETDIR_WIN\\debug" /E /I $$escape_expand(\\n)) # Copy Qt DLLs QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$(QTDIR)\\plugins" "$$TARGETDIR_WIN\\debug" /E /I $$escape_expand(\\n)) @@ -358,17 +359,23 @@ win32-msvc2008|win32-msvc2010|win32-msvc2012 { QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$(QTDIR)\\bin\\QtWebKitd4.dll" "$$TARGETDIR_WIN\\debug"$$escape_expand(\\n)) QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$(QTDIR)\\bin\\QtXmld4.dll" "$$TARGETDIR_WIN\\debug"$$escape_expand(\\n)) QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$(QTDIR)\\bin\\QtXmlPatternsd4.dll" "$$TARGETDIR_WIN\\debug"$$escape_expand(\\n)) + QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$(QTDIR)\\bin\\QtDeclaratived4.dll" "$$TARGETDIR_WIN\\debug"$$escape_expand(\\n)) + QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$(QTDIR)\\bin\\QtScriptd4.dll" "$$TARGETDIR_WIN\\debug"$$escape_expand(\\n)) } CONFIG(release, debug|release) { + + # Use link time code generation for beteer optimization (I believe this is supported in msvc express, but not 100% sure) + QMAKE_LFLAGS_LTCG = /LTCG + QMAKE_CFLAGS_LTCG = -GL + # Copy supporting library DLLs QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$BASEDIR_WIN\\libs\\lib\\sdl\\win32\\SDL.dll" "$$TARGETDIR_WIN\\release"$$escape_expand(\\n)) QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$BASEDIR_WIN\\libs\\mavlink" "$$TARGETDIR_WIN\\release\\mavlink" /E /I $$escape_expand(\\n)) QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$BASEDIR_WIN\\libs\\thirdParty\\libxbee\\lib\\libxbee.dll" "$$TARGETDIR_WIN\\release"$$escape_expand(\\n)) # Copy application resources - QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$BASEDIR_WIN\\files" "$$TARGETDIR_WIN\\release\\files" /E /I $$escape_expand(\\n)) - QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$BASEDIR_WIN\\models" "$$TARGETDIR_WIN\\release\\models" /E /I $$escape_expand(\\n)) + for(COPY_DIR, COPY_RESOURCE_LIST_WIN):QMAKE_POST_LIST += $$quote(xcopy /D /Y "$${COPY_DIR}" "$$TARGETDIR_WIN\\release" /E /I $$escape_expand(\\n)) # Copy Qt DLLs QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$(QTDIR)\\plugins" "$$TARGETDIR_WIN\\release" /E /I $$escape_expand(\\n)) @@ -384,6 +391,8 @@ win32-msvc2008|win32-msvc2010|win32-msvc2012 { QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$(QTDIR)\\bin\\QtWebKit4.dll" "$$TARGETDIR_WIN\\release"$$escape_expand(\\n)) QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$(QTDIR)\\bin\\QtXml4.dll" "$$TARGETDIR_WIN\\release"$$escape_expand(\\n)) QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$(QTDIR)\\bin\\QtXmlPatterns4.dll" "$$TARGETDIR_WIN\\release"$$escape_expand(\\n)) + QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$(QTDIR)\\bin\\QtDeclarative4.dll" "$$TARGETDIR_WIN\\release"$$escape_expand(\\n)) + QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$(QTDIR)\\bin\\QtScript4.dll" "$$TARGETDIR_WIN\\release"$$escape_expand(\\n)) QMAKE_POST_LINK += $$quote(del /F "$$TARGETDIR_WIN\\release\\qgroundcontrol.exp"$$escape_expand(\\n)) QMAKE_POST_LINK += $$quote(del /F "$$TARGETDIR_WIN\\release\\qgroundcontrol.lib"$$escape_expand(\\n)) diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index 8282fb3d80cf1d3f7dd94745aa4a2a00e06e9a7b..3f48dc0f24f79ea010624249b3d1fcc023294fae 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -20,14 +20,17 @@ # Qt configuration CONFIG += qt \ - thread + thread \ + console + QT += network \ opengl \ svg \ xml \ phonon \ webkit \ - sql + sql \ + declarative TEMPLATE = app TARGET = qgroundcontrol @@ -45,6 +48,9 @@ linux-g++|linux-g++-64{ TARGETDIR = $${OUT_PWD} BUILDDIR = $${OUT_PWD}/build } + + + LANGUAGE = C++ OBJECTS_DIR = $${BUILDDIR}/obj MOC_DIR = $${BUILDDIR}/moc @@ -55,6 +61,12 @@ MAVLINKPATH = $$BASEDIR/libs/mavlink/include/mavlink/v1.0 DEFINES += MAVLINK_NO_DATA win32 { + VERSION = 2.0.0.227 + QMAKE_TARGET_COMPANY = qgroundcontrol.org + QMAKE_TARGET_PRODUCT = qgroundcontrol + QMAKE_TARGET_DESCRIPTION = "Open source ground control app provided by QGroundControl dev team" + QMAKE_TARGET_COPYRIGHT = "Copyright (C) 2013 QGroundControl Development Team. All rights reserved." + QMAKE_INCDIR_QT = $$(QTDIR)/include QMAKE_LIBDIR_QT = $$(QTDIR)/lib QMAKE_UIC = "$$(QTDIR)/bin/uic.exe" @@ -72,7 +84,9 @@ win32 { } } - +macx { + QMAKE_INFO_PLIST = Custom-Info.plist +} ################################################################# # EXTERNAL LIBRARY CONFIGURATION @@ -114,7 +128,6 @@ isEmpty(MAVLINK_CONF) { INCLUDEPATH += $$MAVLINKPATH/common } else { INCLUDEPATH += $$MAVLINKPATH/$$MAVLINK_CONF - #DEFINES += 'MAVLINK_CONF="$${MAVLINK_CONF}.h"' DEFINES += $$sprintf('QGC_USE_%1_MESSAGES', $$upper($$MAVLINK_CONF)) } @@ -135,30 +148,46 @@ INCLUDEPATH += \ include(src/apps/mavlinkgen/mavlinkgen.pri) +# Include QUpgrade tool +exists(qupgrade) { + SOURCES += qupgrade/src/apps/qupgrade/qgcfirmwareupgradeworker.cpp \ + qupgrade/src/apps/qupgrade/uploader.cpp \ + qupgrade/src/apps/qupgrade/dialog_bare.cpp \ + qupgrade/src/apps/qupgrade/boardwidget.cpp + + HEADERS += qupgrade/src/apps/qupgrade/qgcfirmwareupgradeworker.h \ + qupgrade/src/apps/qupgrade/uploader.h \ + qupgrade/src/apps/qupgrade/dialog_bare.h \ + qupgrade/src/apps/qupgrade/boardwidget.h + + FORMS += qupgrade/src/apps/qupgrade/dialog_bare.ui \ + qupgrade/src/apps/qupgrade/boardwidget.ui + + RESOURCES += qupgrade/qupgrade.qrc + + linux*:CONFIG += qesp_linux_udev + + include(qupgrade/libs/qextserialport/src/qextserialport.pri) + INCLUDEPATH += qupgrade/src/apps/qupgrade + + DEFINES += "QUPGRADE_SUPPORT" +} + +# Include GLC library +#include(libs/GLC_lib/glc_lib.pri) # Include QWT plotting library include(libs/qwt/qwt.pri) + DEPENDPATH += . \ - plugins \ - libs/thirdParty/qserialport/include \ - libs/thirdParty/qserialport/include/QtSerialPort \ - libs/thirdParty/qserialport \ - libs/qextserialport - -INCLUDEPATH += . \ - libs/thirdParty/qserialport/include \ - libs/thirdParty/qserialport/include/QtSerialPort \ - libs/thirdParty/qserialport/src \ - libs/qextserialport -# Include serial port library (QSerial) -include(qserialport.pri) - -# Serial port detection (ripped-off from qextserialport library) -macx|macx-g++|macx-g++42::SOURCES += libs/qextserialport/qextserialenumerator_osx.cpp -linux-g++::SOURCES += libs/qextserialport/qextserialenumerator_unix.cpp -linux-g++-64::SOURCES += libs/qextserialport/qextserialenumerator_unix.cpp -win32-msvc2008|win32-msvc2010|win32-msvc2012::SOURCES += libs/qextserialport/qextserialenumerator_win.cpp + plugins + +INCLUDEPATH += . + +# Include serial port library (QSerialPort) +include(libs/serialport/qserialport.pri) + # Input FORMS += src/ui/MainWindow.ui \ src/ui/CommSettings.ui \ @@ -198,6 +227,7 @@ FORMS += src/ui/MainWindow.ui \ src/ui/QGCMAVLinkLogPlayer.ui \ src/ui/QGCWaypointListMulti.ui \ src/ui/QGCUDPLinkConfiguration.ui \ + src/ui/QGCTCPLinkConfiguration.ui \ src/ui/QGCSettingsWidget.ui \ src/ui/UASControlParameters.ui \ src/ui/map/QGCMapTool.ui \ @@ -223,6 +253,7 @@ FORMS += src/ui/MainWindow.ui \ src/ui/mission/QGCMissionDoStartSearch.ui \ src/ui/mission/QGCMissionDoFinishSearch.ui \ src/ui/QGCVehicleConfig.ui \ + src/ui/QGCPX4VehicleConfig.ui \ src/ui/QGCHilConfiguration.ui \ src/ui/QGCHilFlightGearConfiguration.ui \ src/ui/QGCHilJSBSimConfiguration.ui \ @@ -237,8 +268,43 @@ FORMS += src/ui/MainWindow.ui \ src/ui/uas/QGCMessageView.ui \ src/ui/JoystickButton.ui \ src/ui/JoystickAxis.ui \ + src/ui/configuration/ApmHardwareConfig.ui \ + src/ui/configuration/ApmSoftwareConfig.ui \ + src/ui/configuration/FrameTypeConfig.ui \ + src/ui/configuration/CompassConfig.ui \ + src/ui/configuration/AccelCalibrationConfig.ui \ + src/ui/configuration/RadioCalibrationConfig.ui \ + src/ui/configuration/FlightModeConfig.ui \ + src/ui/configuration/Radio3DRConfig.ui \ + src/ui/configuration/BatteryMonitorConfig.ui \ + src/ui/configuration/SonarConfig.ui \ + src/ui/configuration/AirspeedConfig.ui \ + src/ui/configuration/OpticalFlowConfig.ui \ + src/ui/configuration/OsdConfig.ui \ + src/ui/configuration/AntennaTrackerConfig.ui \ + src/ui/configuration/CameraGimbalConfig.ui \ + src/ui/configuration/BasicPidConfig.ui \ + src/ui/configuration/StandardParamConfig.ui \ + src/ui/configuration/GeoFenceConfig.ui \ + src/ui/configuration/FailSafeConfig.ui \ + src/ui/configuration/AdvancedParamConfig.ui \ + src/ui/configuration/ArduCopterPidConfig.ui \ + src/ui/configuration/ApmPlaneLevel.ui \ + src/ui/configuration/ParamWidget.ui \ + src/ui/configuration/ArduPlanePidConfig.ui \ + src/ui/configuration/AdvParameterList.ui \ + src/ui/configuration/ArduRoverPidConfig.ui \ + src/ui/QGCConfigView.ui \ src/ui/main/QGCViewModeSelection.ui \ - src/ui/main/QGCWelcomeMainWindow.ui + src/ui/main/QGCWelcomeMainWindow.ui \ + src/ui/configuration/terminalconsole.ui \ + src/ui/configuration/SerialSettingsDialog.ui \ + src/ui/configuration/ApmFirmwareConfig.ui \ + src/ui/px4_configuration/QGCPX4AirframeConfig.ui \ + src/ui/px4_configuration/QGCPX4MulticopterConfig.ui \ + src/ui/px4_configuration/QGCPX4SensorCalibration.ui \ + src/ui/designer/QGCXYPlot.ui + INCLUDEPATH += src \ src/ui \ src/ui/linechart \ @@ -255,6 +321,7 @@ INCLUDEPATH += src \ src/ui/map3D \ src/ui/mission \ src/ui/designer \ + src/ui/configuration \ src/ui/main HEADERS += src/MG.h \ src/QGCCore.h \ @@ -286,6 +353,7 @@ HEADERS += src/MG.h \ src/ui/CameraView.h \ src/comm/MAVLinkSimulationLink.h \ src/comm/UDPLink.h \ + src/comm/TCPLink.h \ src/ui/ParameterInterface.h \ src/ui/WaypointList.h \ src/Waypoint.h \ @@ -341,6 +409,7 @@ HEADERS += src/MG.h \ src/uas/QGCMAVLinkUASFactory.h \ src/ui/QGCWaypointListMulti.h \ src/ui/QGCUDPLinkConfiguration.h \ + src/ui/QGCTCPLinkConfiguration.h \ src/ui/QGCSettingsWidget.h \ src/ui/uas/UASControlParameters.h \ src/uas/QGCUASParamManager.h \ @@ -349,7 +418,6 @@ HEADERS += src/MG.h \ src/ui/map/Waypoint2DIcon.h \ src/ui/map/QGCMapTool.h \ src/ui/map/QGCMapToolBar.h \ - libs/qextserialport/qextserialenumerator.h \ src/QGCGeo.h \ src/ui/QGCToolBar.h \ src/ui/QGCStatusBar.h \ @@ -376,6 +444,7 @@ HEADERS += src/MG.h \ src/ui/mission/QGCMissionDoStartSearch.h \ src/ui/mission/QGCMissionDoFinishSearch.h \ src/ui/QGCVehicleConfig.h \ + src/ui/QGCPX4VehicleConfig.h \ src/comm/QGCHilLink.h \ src/ui/QGCHilConfiguration.h \ src/ui/QGCHilFlightGearConfiguration.h \ @@ -384,7 +453,6 @@ HEADERS += src/MG.h \ src/ui/designer/QGCComboBox.h \ src/ui/designer/QGCTextLabel.h \ src/ui/submainwindow.h \ - src/ui/dockwidgettitlebareventfilter.h \ src/ui/uas/UASQuickView.h \ src/ui/uas/UASQuickViewItem.h \ src/ui/linechart/ChartPlot.h \ @@ -399,8 +467,51 @@ HEADERS += src/MG.h \ src/ui/uas/QGCMessageView.h \ src/ui/JoystickButton.h \ src/ui/JoystickAxis.h \ + src/ui/configuration/ApmHardwareConfig.h \ + src/ui/configuration/ApmSoftwareConfig.h \ + src/ui/configuration/FrameTypeConfig.h \ + src/ui/configuration/CompassConfig.h \ + src/ui/configuration/AccelCalibrationConfig.h \ + src/ui/configuration/RadioCalibrationConfig.h \ + src/ui/configuration/FlightModeConfig.h \ + src/ui/configuration/Radio3DRConfig.h \ + src/ui/configuration/BatteryMonitorConfig.h \ + src/ui/configuration/SonarConfig.h \ + src/ui/configuration/AirspeedConfig.h \ + src/ui/configuration/OpticalFlowConfig.h \ + src/ui/configuration/OsdConfig.h \ + src/ui/configuration/AntennaTrackerConfig.h \ + src/ui/configuration/CameraGimbalConfig.h \ + src/ui/configuration/AP2ConfigWidget.h \ + src/ui/configuration/BasicPidConfig.h \ + src/ui/configuration/StandardParamConfig.h \ + src/ui/configuration/GeoFenceConfig.h \ + src/ui/configuration/FailSafeConfig.h \ + src/ui/configuration/AdvancedParamConfig.h \ + src/ui/configuration/ArduCopterPidConfig.h \ + src/ui/apmtoolbar.h \ + src/ui/configuration/ApmPlaneLevel.h \ + src/ui/configuration/ParamWidget.h \ + src/ui/configuration/ArduPlanePidConfig.h \ + src/ui/configuration/AdvParameterList.h \ + src/ui/configuration/ArduRoverPidConfig.h \ + src/ui/QGCConfigView.h \ src/ui/main/QGCViewModeSelection.h \ - src/ui/main/QGCWelcomeMainWindow.h + src/ui/main/QGCWelcomeMainWindow.h \ + src/ui/configuration/console.h \ + src/ui/configuration/SerialSettingsDialog.h \ + src/ui/configuration/terminalconsole.h \ + src/ui/configuration/ApmHighlighter.h \ + src/ui/configuration/ApmFirmwareConfig.h \ + src/uas/UASParameterDataModel.h \ + src/uas/UASParameterCommsMgr.h \ + src/ui/QGCPendingParamWidget.h \ + src/ui/px4_configuration/QGCPX4AirframeConfig.h \ + src/ui/QGCBaseParamWidget.h \ + src/ui/px4_configuration/QGCPX4MulticopterConfig.h \ + src/ui/px4_configuration/QGCPX4SensorCalibration.h \ + src/ui/designer/QGCXYPlot.h \ + src/ui/menuactionhelper.h # Google Earth is only supported on Mac OS and Windows with Visual Studio Compiler macx|macx-g++|macx-g++42|win32-msvc2008|win32-msvc2010|win32-msvc2012::HEADERS += src/ui/map3D/QGCGoogleEarthView.h @@ -470,6 +581,7 @@ SOURCES += src/main.cc \ src/ui/CameraView.cc \ src/comm/MAVLinkSimulationLink.cc \ src/comm/UDPLink.cc \ + src/comm/TCPLink.cc \ src/ui/ParameterInterface.cc \ src/ui/WaypointList.cc \ src/Waypoint.cc \ @@ -524,6 +636,7 @@ SOURCES += src/main.cc \ src/uas/QGCMAVLinkUASFactory.cc \ src/ui/QGCWaypointListMulti.cc \ src/ui/QGCUDPLinkConfiguration.cc \ + src/ui/QGCTCPLinkConfiguration.cc \ src/ui/QGCSettingsWidget.cc \ src/ui/uas/UASControlParameters.cpp \ src/uas/QGCUASParamManager.cc \ @@ -557,6 +670,7 @@ SOURCES += src/main.cc \ src/ui/mission/QGCMissionDoStartSearch.cc \ src/ui/mission/QGCMissionDoFinishSearch.cc \ src/ui/QGCVehicleConfig.cc \ + src/ui/QGCPX4VehicleConfig.cc \ src/ui/QGCHilConfiguration.cc \ src/ui/QGCHilFlightGearConfiguration.cc \ src/ui/QGCHilJSBSimConfiguration.cc \ @@ -564,7 +678,6 @@ SOURCES += src/main.cc \ src/ui/designer/QGCComboBox.cc \ src/ui/designer/QGCTextLabel.cc \ src/ui/submainwindow.cpp \ - src/ui/dockwidgettitlebareventfilter.cpp \ src/ui/uas/UASQuickViewItem.cc \ src/ui/uas/UASQuickView.cc \ src/ui/linechart/ChartPlot.cc \ @@ -576,11 +689,54 @@ SOURCES += src/main.cc \ src/ui/QGCTabbedInfoView.cpp \ src/ui/UASRawStatusView.cpp \ src/ui/PrimaryFlightDisplay.cc \ - src/ui/uas/QGCMessageView.cc \ src/ui/JoystickButton.cc \ src/ui/JoystickAxis.cc \ + src/ui/uas/QGCMessageView.cc \ + src/ui/configuration/ApmHardwareConfig.cc \ + src/ui/configuration/ApmSoftwareConfig.cc \ + src/ui/configuration/FrameTypeConfig.cc \ + src/ui/configuration/CompassConfig.cc \ + src/ui/configuration/AccelCalibrationConfig.cc \ + src/ui/configuration/RadioCalibrationConfig.cc \ + src/ui/configuration/FlightModeConfig.cc \ + src/ui/configuration/Radio3DRConfig.cc \ + src/ui/configuration/BatteryMonitorConfig.cc \ + src/ui/configuration/SonarConfig.cc \ + src/ui/configuration/AirspeedConfig.cc \ + src/ui/configuration/OpticalFlowConfig.cc \ + src/ui/configuration/OsdConfig.cc \ + src/ui/configuration/AntennaTrackerConfig.cc \ + src/ui/configuration/CameraGimbalConfig.cc \ + src/ui/configuration/AP2ConfigWidget.cc \ + src/ui/configuration/BasicPidConfig.cc \ + src/ui/configuration/StandardParamConfig.cc \ + src/ui/configuration/GeoFenceConfig.cc \ + src/ui/configuration/FailSafeConfig.cc \ + src/ui/configuration/AdvancedParamConfig.cc \ + src/ui/configuration/ArduCopterPidConfig.cc \ + src/ui/apmtoolbar.cpp \ + src/ui/configuration/ApmPlaneLevel.cc \ + src/ui/configuration/ParamWidget.cc \ + src/ui/configuration/ArduPlanePidConfig.cc \ + src/ui/configuration/AdvParameterList.cc \ + src/ui/configuration/ArduRoverPidConfig.cc \ + src/ui/QGCConfigView.cc \ src/ui/main/QGCViewModeSelection.cc \ - src/ui/main/QGCWelcomeMainWindow.cc + src/ui/main/QGCWelcomeMainWindow.cc \ + src/ui/configuration/terminalconsole.cpp \ + src/ui/configuration/console.cpp \ + src/ui/configuration/SerialSettingsDialog.cc \ + src/ui/configuration/ApmHighlighter.cc \ + src/ui/configuration/ApmFirmwareConfig.cc \ + src/uas/UASParameterDataModel.cc \ + src/uas/UASParameterCommsMgr.cc \ + src/ui/QGCPendingParamWidget.cc \ + src/ui/px4_configuration/QGCPX4AirframeConfig.cc \ + src/ui/QGCBaseParamWidget.cc \ + src/ui/px4_configuration/QGCPX4MulticopterConfig.cc \ + src/ui/px4_configuration/QGCPX4SensorCalibration.cc \ + src/ui/designer/QGCXYPlot.cc \ + src/ui/menuactionhelper.cpp # Enable Google Earth only on Mac OS and Windows with Visual Studio compiler macx|macx-g++|macx-g++42|win32-msvc2008|win32-msvc2010|win32-msvc2012::SOURCES += src/ui/map3D/QGCGoogleEarthView.cc @@ -716,4 +872,32 @@ unix:!macx:!symbian: LIBS += -losg OTHER_FILES += \ dongfang_notes.txt \ - src/ui/dongfang-scrapyard.txt + src/ui/dongfang-scrapyard.txt \ + qml/components/DigitalDisplay.qml \ + qml/components/StatusDisplay.qml + +OTHER_FILES += \ + qml/ApmToolBar.qml \ + qml/components/Button.qml \ + qml/components/TextButton.qml \ + qml/resources/qgroundcontrol/toolbar/connect.png \ + qml/resources/qgroundcontrol/toolbar/flightplanner.png \ + qml/resources/qgroundcontrol/toolbar/helpwizard.png \ + qml/resources/qgroundcontrol/toolbar/softwareconfig.png \ + qml/resources/qgroundcontrol/toolbar/terminal.png \ + qml/resources/qgroundcontrol/toolbar/simulation.png \ + qml/resources/qgroundcontrol/toolbar/hardwareconfig.png \ + qml/resources/qgroundcontrol/toolbar/flightdata.png \ + qml/resources/qgroundcontrol/toolbar/disconnect.png \ + qml/resources/qgroundcontrol/toolbar/donate.png \ + + +#qmlcomponents.path += $${DESTDIR}$${TARGET}/components +#qmlcomponents.files += ./components/Button.qml + +#sources.files += ApmToolBar.qml +#sources.path += $$DESTDIR/qml +#target.path += qgroundcontrol +#INSTALLS += sources target + +message( BASEDIR $$BASEDIR DESTDIR $$DESTDIR TARGET $$TARGET TARGETDIR $$TARGETDIR) diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index b6b141040a2f9dca3148c6aa52803e3b2f4bcf2f..4ba6ddc2e5dd410d30082a0b90215f5850d9b9d3 100644 --- a/qgroundcontrol.qrc +++ b/qgroundcontrol.qrc @@ -102,11 +102,102 @@ files/images/patterns/lenna.jpg files/images/rc_stick.svg files/images/actions/qgroundcontrol-connect.svg + files/images/mavs/frames_plus.png + files/images/mavs/frames_x.png + files/images/mavs/frames-05.png + files/images/devices/BR-HMC5883-01-2.jpg + files/images/devices/BR-APMPWRDEAN-2.jpg + files/images/devices/AC-0004-11-2.jpg + files/images/devices/BR-0004-03-2.jpg + files/images/devices/BR-0016-01-3T.jpg + files/images/devices/MinimOSD.jpg + files/images/devices/cameraGimalPitch1.png + files/images/devices/cameraGimalRoll1.png + files/images/devices/cameraGimalYaw.png + files/images/devices/Shutter.png files/images/actions/qgroundcontrol-generic.svg files/images/actions/qgroundcontrol-px4.svg files/images/actions/qgroundcontrol-apm.svg files/images/actions/qgroundcontrol-ardrone.svg files/images/actions/qgroundcontrol-wifi.svg + files/images/firmware/apmcopter.png + files/images/firmware/apmplane.png + files/images/firmware/apmrover.png + files/images/firmware/FW icons 2013+logos.ai + files/images/firmware/heli.png + files/images/firmware/heli_off.png + files/images/firmware/heli_on.png + files/images/firmware/hexa_off.png + files/images/firmware/hexa_on.png + files/images/firmware/hexaplus.png + files/images/firmware/hexax.png + files/images/firmware/hexay.png + files/images/firmware/octaplus.png + files/images/firmware/octax.png + files/images/firmware/octo_off.png + files/images/firmware/octo_on.png + files/images/firmware/octx.png + files/images/firmware/plane.png + files/images/firmware/plane_off.png + files/images/firmware/plane_on.png + files/images/firmware/quad_off.png + files/images/firmware/quad_on.png + files/images/firmware/quad_T_off.png + files/images/firmware/quad_T_on.png + files/images/firmware/quadplus.png + files/images/firmware/quadx.png + files/images/firmware/quady.png + files/images/firmware/rover.png + files/images/firmware/rover_off.png + files/images/firmware/rover_on.png + files/images/firmware/Tir_off.png + files/images/firmware/Tir_on.png + files/images/firmware/triy.png + files/images/firmware/X8.png + files/images/firmware/X8_on.png + files/images/firmware/Y6_off.png + files/images/firmware/Y6_on.png + files/images/px4/airframes/quad_x.png + files/images/px4/airframes/quad_+.png + files/images/px4/airframes/octo_+.png + files/images/px4/airframes/hexa_+.png + files/images/px4/airframes/hexa_x.png + files/images/px4/airframes/octo_x.png + files/images/px4/airframes/flying_wing.png + files/images/px4/airframes/plane_ert.png + files/images/px4/airframes/plane_aert.png + files/images/px4/airframes/quad_h.png + files/images/px4/calibration/arrows.png + files/images/px4/calibration/accel_x+.png + files/images/px4/calibration/accel_x-.png + files/images/px4/calibration/accel_y-.png + files/images/px4/calibration/accel_z+.png + files/images/px4/calibration/accel_z-.png + files/images/px4/calibration/accel_y+.png + files/images/px4/calibration/mag_calibration_figure8.png + files/images/px4/menu/sensors.png + files/images/px4/menu/firmware_upgrade.png + files/images/px4/menu/plane.png + files/images/px4/menu/remote.png + files/images/px4/menu/cogwheels.png + files/images/px4/rc/cessna_back.png + files/images/px4/rc/cessna_side.png + files/images/px4/calibration/3dr_gps/gps_15.png + files/images/px4/calibration/3dr_gps/gps_14.png + files/images/px4/calibration/3dr_gps/gps_13.png + files/images/px4/calibration/3dr_gps/gps_12.png + files/images/px4/calibration/3dr_gps/gps_19.png + files/images/px4/calibration/3dr_gps/gps_18.png + files/images/px4/calibration/3dr_gps/gps_17.png + files/images/px4/calibration/3dr_gps/gps_16.png + files/images/px4/calibration/3dr_gps/gps_07.png + files/images/px4/calibration/3dr_gps/gps_06.png + files/images/px4/calibration/3dr_gps/gps_04.png + files/images/px4/calibration/3dr_gps/gps_03.png + files/images/px4/calibration/3dr_gps/gps_02.png + files/images/px4/calibration/3dr_gps/gps_01.png + files/images/px4/calibration/3dr_gps/gps_24.png + files/images/px4/calibration/3dr_gps/gps_00.png files/styles/Vera.ttf diff --git a/qml/ApmToolBar.qml b/qml/ApmToolBar.qml new file mode 100644 index 0000000000000000000000000000000000000000..23a78150796efd1196e6598ca79b92f0d09242ee --- /dev/null +++ b/qml/ApmToolBar.qml @@ -0,0 +1,210 @@ +import QtQuick 1.1 +import "./components" + + +Rectangle { + id: toolbar + + property alias backgroundColor : toolbar.color + property alias linkNameLabel: linkDevice.label + property alias baudrateLabel: baudrate.label + property bool connected: false + property bool armed: false + property string armedstr: "DISARMED" + + width: toolbar.width + height: 72 + color: "black" + border.color: "black" + + onArmedChanged: { + if (armed) { + statusDisplay.statusText = "ARMED" + statusDisplay.statusTextColor = "red" + statusDisplay.statusBackgroundColor = "#FF880000" + } + else { + statusDisplay.statusText = "DISARMED" + statusDisplay.statusTextColor = "yellow" + statusDisplay.statusBackgroundColor = "black" + } + } + + onConnectedChanged: { + if (connected){ + console.log("APM Tool BAR QML: connected") + connectButton.image = "./resources/qgroundcontrol/toolbar/disconnect.png" + connectButton.label = "DISCONNECT" + } else { + console.log("APM Tool BAR QML: disconnected") + connectButton.image = "./resources/qgroundcontrol/toolbar/connect.png" + connectButton.label = "CONNECT" + } + } + +// [BB] The code below should work, not sure why. replaced with code above +// Connections { +// target: globalObj +// onMAVConnected: { +// console.log("QML Change Connection " + connected) +// if (connected){ +// console.log("connected") +// connectButton.image = "./resources/qgroundcontrol/toolbar/disconnect.png" +// } else { +// console.log("disconnected") +// connectButton.image = "./resources/qgroundcontrol/toolbar/connect.png" +// } +// } +// } + + Row { + anchors.left: parent.left + spacing: 10 + + Rectangle { // Spacer + width: 5 + height: parent.height + color: "black" + } + + Button { + id: flightDataView + label: "FLIGHT DATA" + image: "./resources/qgroundcontrol/toolbar/flightdata.png" + onClicked: { + globalObj.triggerFlightView() + } + } + + Button { + id: flightPlanView + label: "FLIGHT PLAN" + image: "./resources/qgroundcontrol/toolbar/flightplanner.png" + onClicked: globalObj.triggerFlightPlanView() + } + + Button { + id: hardwareConfigView + label: "HARDWARE" + image: "./resources/qgroundcontrol/toolbar/hardwareconfig.png" + margins: 8 + onClicked: globalObj.triggerHardwareView() + } + + Button { + id: softwareConfigView + label: "SOFTWARE" + image: "./resources/qgroundcontrol/toolbar/softwareconfig.png" + margins: 8 + onClicked: globalObj.triggerSoftwareView() + } + + Button { + id: simulationView + label: "SIMULATION" + image: "./resources/qgroundcontrol/toolbar/simulation.png" + onClicked: globalObj.triggerSimulationView() + } + + Button { + id: terminalView + label: "TERMINAL" + image: "./resources/qgroundcontrol/toolbar/terminal.png" + onClicked: globalObj.triggerTerminalView() + } + + Rectangle { // Spacer + width: 5 + height: parent.height + color: "black" + } + + StatusDisplay { + id: statusDisplay + width: 110 + statusText: "DISARMED" + statusTextColor: "yellow" + statusBackgroundColor: "black" + } + + Rectangle { // Spacer + width: 5 + height: parent.height + color: "black" + } + +// [BB] Commented out ToolBar Status info work. +// WIP: To be fixed later +// DigitalDisplay { // Information Pane +// title:"Mode" +// textValue: "Stabilize" +// color: "black" +// } +// DigitalDisplay { // Information Pane +// title: "Speed" +// textValue: "11.0m/s" +// color: "black" +// } +// DigitalDisplay { // Information Pane +// title: "Alt" +// textValue: "20.0m" +// color: "black" +// } +// DigitalDisplay { // Information Pane +// title: "Volts" +// textValue: "14.8V" +// color: "black" +// } +// DigitalDisplay { // Information Pane +// title: "Current" +// textValue: "12.0A" +// color: "black" +// } +// DigitalDisplay { // Information Pane +// title: "Level" +// textValue: "77%" +// color: "black" +// } + + } + + Row { + anchors.right: parent.right + spacing: 2 + + TextButton { + id: linkDevice + label: "none" + minWidth: 100 + + onClicked: globalObj.showConnectionDialog() + } + + TextButton { + id: baudrate + label: "none" + minWidth: 100 + + onClicked: globalObj.showConnectionDialog() + } + + Rectangle { + width: 5 + height: parent.height + color: "black" + } + + Button { + id: connectButton + label: "CONNECT" + image: "./resources/qgroundcontrol/toolbar/connect.png" + onClicked: globalObj.connectMAV() + } + + Rectangle { // Spacer + width: 5 + height: parent.height + color: "black" + } + } +} diff --git a/qml/components/Button.qml b/qml/components/Button.qml new file mode 100644 index 0000000000000000000000000000000000000000..798a161076bb015a7845c7ac3254e2c4e7a8e9d8 --- /dev/null +++ b/qml/components/Button.qml @@ -0,0 +1,70 @@ +import QtQuick 1.1 + +Rectangle { + signal clicked + + property string label: "button label" + property alias image: buttonImage.source + property int margins: 2 + + id: button + width: 72 + height: 72 + radius: 3 + smooth: true + border.width: 2 + + Text { + id: buttonLabel + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + anchors.margins: 5 + text: label + color: "white" + font.pointSize: 10 + } + + Image { + id: buttonImage + anchors.horizontalCenter: button.horizontalCenter + anchors.top: buttonLabel.bottom + anchors.margins: margins + source: image + fillMode: Image.PreserveAspectFit + width: image.width + height: image.height + } + + signal buttonClick() + + onButtonClick: { + console.log(buttonLabel.text + " clicked calling signal") + clicked() + } + + // Highlighting and ativation section + property color buttonColor: "black" + property color onHoverbuttonColor: "lightblue" + property color onHoverColor: "darkblue" + property color borderColor: "black" + + MouseArea { + id: buttonMouseArea + anchors.fill: parent + onClicked: buttonClick() + hoverEnabled: true + onEntered: { + parent.border.color = onHoverColor + parent.color = onHoverbuttonColor + } + onExited: { + parent.border.color = borderColor + parent.color = buttonColor + } + onPressed: parent.color = Qt.darker(onHoverbuttonColor, 1.5) + onReleased: parent.color = buttonColor + } + color: buttonColor + border.color: borderColor +} + diff --git a/qml/components/DigitalDisplay.qml b/qml/components/DigitalDisplay.qml new file mode 100644 index 0000000000000000000000000000000000000000..dc70d0149c9b9e79a4a5dc508815a94dc23c9450 --- /dev/null +++ b/qml/components/DigitalDisplay.qml @@ -0,0 +1,30 @@ +import QtQuick 1.1 + +Rectangle { + + property alias title: displayTitle.text + property string textValue: "none" + + width: 110 + height: parent.height/3 + anchors.verticalCenter: parent.verticalCenter + border.color: "white" + + Text { + id:displayTitle + anchors.left: parent.left + anchors.leftMargin: 3 + anchors.verticalCenter: parent.verticalCenter + text: "blank" + color: "white" + } + + Text { + id:displayValue + anchors.right: parent.right + anchors.rightMargin: 3 + anchors.verticalCenter: parent.verticalCenter + text: textValue + color: "white" + } +} diff --git a/qml/components/StatusDisplay.qml b/qml/components/StatusDisplay.qml new file mode 100644 index 0000000000000000000000000000000000000000..9d4f6ade628325a3025b0e133e63913c9e5314e3 --- /dev/null +++ b/qml/components/StatusDisplay.qml @@ -0,0 +1,24 @@ +import QtQuick 1.1 + +Rectangle { + id: statusDisplay + property alias statusText: armedText.text + property alias statusTextColor: armedText.color + property alias statusBackgroundColor: statusDisplay.color + + width: 100 + height: parent.height/3 + anchors.verticalCenter: parent.verticalCenter + radius: 3 + border.color: "white" + border.width: 1 + + Text { + id: armedText + anchors.centerIn: parent + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + font.pixelSize: 20 + } + +} diff --git a/qml/components/TextButton.qml b/qml/components/TextButton.qml new file mode 100644 index 0000000000000000000000000000000000000000..c7b2b32226103c85779769e3af60df0cda11ab68 --- /dev/null +++ b/qml/components/TextButton.qml @@ -0,0 +1,70 @@ +import QtQuick 1.1 + +Rectangle { + signal clicked + + property string label: "Text Button label" + property int minWidth: 75 + property int minHeight: 0 + property int margin: 5 + + width: textBox.width + height: 72 + anchors.verticalCenter: parent.verticalCenter + color: "black" + + signal buttonClick() + + onButtonClick: { + console.log(label + " clicked calling signal") + clicked() + } + + // Highlighting and ativation section + property color buttonColor: "black" + property color onHoverbuttonColor: "lightblue" + property color onHoverColor: "darkblue" + property color borderColor: "white" + + Rectangle { + width: textButtonLabel.paintedwidth + anchors.centerIn: parent + + Rectangle{ + id: textBox + anchors.centerIn: parent + width: minWidth > textButtonLabel.paintedWidth + margin ? minWidth : textButtonLabel.paintedWidth + margin + height: minHeight > textButtonLabel.paintedHeight + margin ? minHeight : textButtonLabel.paintedHeight + margin + + Text { + id: textButtonLabel + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + anchors.margins: 2 + text: label + color: "white" + font.pointSize: 11 + } + + MouseArea { + id: textButtonMouseArea + anchors.fill: parent + onClicked: buttonClick() + hoverEnabled: true + onEntered: { + parent.border.color = onHoverColor + parent.color = onHoverbuttonColor + } + onExited: { + parent.border.color = borderColor + parent.color = buttonColor + } + onPressed: parent.color = Qt.darker(onHoverbuttonColor, 1.5) + onReleased: parent.color = buttonColor + } + color: buttonColor + border.color: borderColor + border.width: 1 + } + } +} diff --git a/qml/resources/qgroundcontrol/toolbar/connect.png b/qml/resources/qgroundcontrol/toolbar/connect.png new file mode 100644 index 0000000000000000000000000000000000000000..8572674974bcefde8dc4b54972a423a5a19837ff Binary files /dev/null and b/qml/resources/qgroundcontrol/toolbar/connect.png differ diff --git a/qml/resources/qgroundcontrol/toolbar/disconnect.png b/qml/resources/qgroundcontrol/toolbar/disconnect.png new file mode 100644 index 0000000000000000000000000000000000000000..57f2f505da1eb32c90369f4fc9b154f7de5646f8 Binary files /dev/null and b/qml/resources/qgroundcontrol/toolbar/disconnect.png differ diff --git a/qml/resources/qgroundcontrol/toolbar/donate.png b/qml/resources/qgroundcontrol/toolbar/donate.png new file mode 100644 index 0000000000000000000000000000000000000000..80b1a14612ba76b405ec518f9c81148e6b24d28c Binary files /dev/null and b/qml/resources/qgroundcontrol/toolbar/donate.png differ diff --git a/qml/resources/qgroundcontrol/toolbar/flightdata.png b/qml/resources/qgroundcontrol/toolbar/flightdata.png new file mode 100644 index 0000000000000000000000000000000000000000..aa8fb3663f815da198374f57b40db001778dc462 Binary files /dev/null and b/qml/resources/qgroundcontrol/toolbar/flightdata.png differ diff --git a/qml/resources/qgroundcontrol/toolbar/flightplanner.png b/qml/resources/qgroundcontrol/toolbar/flightplanner.png new file mode 100644 index 0000000000000000000000000000000000000000..72e1b40ec8414bb24275b5f8d592b4284184e764 Binary files /dev/null and b/qml/resources/qgroundcontrol/toolbar/flightplanner.png differ diff --git a/qml/resources/qgroundcontrol/toolbar/hardwareconfig.png b/qml/resources/qgroundcontrol/toolbar/hardwareconfig.png new file mode 100644 index 0000000000000000000000000000000000000000..56fb5619310d64ab6b454779df81a7824c32fa63 Binary files /dev/null and b/qml/resources/qgroundcontrol/toolbar/hardwareconfig.png differ diff --git a/qml/resources/qgroundcontrol/toolbar/helpwizard.png b/qml/resources/qgroundcontrol/toolbar/helpwizard.png new file mode 100644 index 0000000000000000000000000000000000000000..ac5c20a2a7c52fcb60a407c395919addf6202452 Binary files /dev/null and b/qml/resources/qgroundcontrol/toolbar/helpwizard.png differ diff --git a/qml/resources/qgroundcontrol/toolbar/simulation.png b/qml/resources/qgroundcontrol/toolbar/simulation.png new file mode 100644 index 0000000000000000000000000000000000000000..e8a1c31a04ab6f9f9267abbf1c0bd08771ef97ce Binary files /dev/null and b/qml/resources/qgroundcontrol/toolbar/simulation.png differ diff --git a/qml/resources/qgroundcontrol/toolbar/softwareconfig.png b/qml/resources/qgroundcontrol/toolbar/softwareconfig.png new file mode 100644 index 0000000000000000000000000000000000000000..e2516db4060dee69ff7486243576d3749edfe97f Binary files /dev/null and b/qml/resources/qgroundcontrol/toolbar/softwareconfig.png differ diff --git a/qml/resources/qgroundcontrol/toolbar/terminal.png b/qml/resources/qgroundcontrol/toolbar/terminal.png new file mode 100644 index 0000000000000000000000000000000000000000..bb639d3bd4c15454884a44cc664ca7585e99e3b7 Binary files /dev/null and b/qml/resources/qgroundcontrol/toolbar/terminal.png differ diff --git a/qupgrade b/qupgrade new file mode 160000 index 0000000000000000000000000000000000000000..faa4f1a757b372ac1534d76cf996501b296557a7 --- /dev/null +++ b/qupgrade @@ -0,0 +1 @@ +Subproject commit faa4f1a757b372ac1534d76cf996501b296557a7 diff --git a/qupgrade.pro b/qupgrade.pro index 728a67558e795cb6749036c0bf56a99ef9373413..72096c1de02febe7e4ed059a93edbf27264d4d58 100644 --- a/qupgrade.pro +++ b/qupgrade.pro @@ -84,7 +84,7 @@ include(qserialport.pri) macx|macx-g++|macx-g++42::SOURCES += libs/qextserialport/qextserialenumerator_osx.cpp linux-g++::SOURCES += libs/qextserialport/qextserialenumerator_unix.cpp linux-g++-64::SOURCES += libs/qextserialport/qextserialenumerator_unix.cpp -win32::SOURCES += libs/qextserialport/qextserialenumerator_win.cpp +win32-g++::SOURCES += libs/qextserialport/qextserialenumerator_win.cpp win32-msvc2008|win32-msvc2010::SOURCES += libs/qextserialport/qextserialenumerator_win.cpp # ------------------------------------------------- @@ -242,6 +242,8 @@ win32-msvc2008|win32-msvc2010 { QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$(QTDIR)\\bin\\QtWebKit4.dll" "$$TARGETDIR_WIN\\release"$$escape_expand(\\n)) QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$(QTDIR)\\bin\\QtXml4.dll" "$$TARGETDIR_WIN\\release"$$escape_expand(\\n)) QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$(QTDIR)\\bin\\QtXmlPatterns4.dll" "$$TARGETDIR_WIN\\release"$$escape_expand(\\n)) + QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$(QTDIR)\\bin\\QtDeclarative4.dll" "$$TARGETDIR_WIN\\debug"$$escape_expand(\\n)) + QMAKE_POST_LINK += $$quote(xcopy /D /Y "$$(QTDIR)\\bin\\QtScript4.dll" "$$TARGETDIR_WIN\\debug"$$escape_expand(\\n)) QMAKE_POST_LINK += $$quote(del /F "$$TARGETDIR_WIN\\release\\qupgrade.exp"$$escape_expand(\\n)) QMAKE_POST_LINK += $$quote(del /F "$$TARGETDIR_WIN\\release\\qupgrade.lib"$$escape_expand(\\n)) diff --git a/src/GAudioOutput.cc b/src/GAudioOutput.cc index 364ca018c5821884145eae4db3b5e39ef7f1a24f..e4f158d5efe4cd14e7465541d258bcfef8ba94d9 100644 --- a/src/GAudioOutput.cc +++ b/src/GAudioOutput.cc @@ -1,352 +1,387 @@ -/*===================================================================== - -QGroundControl Open Source Ground Control Station - -(c) 2009, 2010 QGROUNDCONTROL PROJECT - -This file is part of the QGROUNDCONTROL project - - QGROUNDCONTROL 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 3 of the License, or - (at your option) any later version. - - QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . - -======================================================================*/ - -/** - * @file - * @brief Implementation of audio output - * - * @author Lorenz Meier - * - */ - -#include -#include -#include -#include "GAudioOutput.h" -#include "MG.h" - -#include - -#ifdef Q_OS_MAC -#include -#endif - -// Speech synthesis is only supported with MSVC compiler -#if _MSC_VER2 -// Documentation: http://msdn.microsoft.com/en-us/library/ee125082%28v=VS.85%29.aspx -#define _ATL_APARTMENT_THREADED - -#include -//You may derive a class from CComModule and use it if you want to override something, -//but do not change the name of _Module -extern CComModule _Module; -#include - -#include - -//using System; -//using System.Speech.Synthesis; -#endif - -#ifdef Q_OS_LINUX -extern "C" { -#include - cst_voice* register_cmu_us_kal(const char* voxdir); -}; -#endif - - - -/** - * This class follows the singleton design pattern - * @see http://en.wikipedia.org/wiki/Singleton_pattern - * A call to this function thus returns the only instance of this object - * the call can occur at any place in the code, no reference to the - * GAudioOutput object has to be passed. - */ -GAudioOutput* GAudioOutput::instance() -{ - static GAudioOutput* _instance = 0; - if(_instance == 0) - { - _instance = new GAudioOutput(); - // Set the application as parent to ensure that this object - // will be destroyed when the main application exits - _instance->setParent(qApp); - } - return _instance; -} - -#define QGC_GAUDIOOUTPUT_KEY QString("QGC_AUDIOOUTPUT_") - -GAudioOutput::GAudioOutput(QObject* parent) : QObject(parent), - voiceIndex(0), - emergency(false), - muted(false) -{ - // Load settings - QSettings settings; - settings.sync(); - muted = settings.value(QGC_GAUDIOOUTPUT_KEY+"muted", muted).toBool(); - - -#ifdef Q_OS_LINUX - flite_init(); -#endif - -#if _MSC_VER2 - - ISpVoice * pVoice = NULL; - if (FAILED(::CoInitialize(NULL))) - { - qDebug("Creating COM object for audio output failed!"); - } - else - { - - HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice;); - if( SUCCEEDED( hr ) ) - { - hr = pVoice->Speak(L"Hello world", 0, NULL); - pVoice->Release(); - pVoice = NULL; - } - } -#endif - // Initialize audio output - //m_media = new Phonon::MediaObject(this); - //Phonon::AudioOutput *audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this); - //createPath(m_media, audioOutput); - - // Prepare regular emergency signal, will be fired off on calling startEmergency() - emergencyTimer = new QTimer(); - connect(emergencyTimer, SIGNAL(timeout()), this, SLOT(beep())); - - switch (voiceIndex) { - case 0: - selectFemaleVoice(); - break; - default: - selectMaleVoice(); - break; - } -} - -//GAudioOutput::~GAudioOutput() -//{ -//#ifdef _MSC_VER2 -// ::CoUninitialize(); -//#endif -//} - -void GAudioOutput::mute(bool mute) -{ - if (mute != muted) - { - this->muted = mute; - QSettings settings; - settings.setValue(QGC_GAUDIOOUTPUT_KEY+"muted", this->muted); - settings.sync(); - emit mutedChanged(muted); - } -} - -bool GAudioOutput::isMuted() -{ - return this->muted; -} - -bool GAudioOutput::say(QString text, int severity) -{ - if (!muted) - { - // TODO Add severity filter - Q_UNUSED(severity); - bool res = false; - if (!emergency) - { - - // Speech synthesis is only supported with MSVC compiler -#ifdef _MSC_VER2 - SpeechSynthesizer synth = new SpeechSynthesizer(); - synth.SelectVoice("Microsoft Anna"); - synth.SpeakText(text.toStdString().c_str()); - res = true; -#endif - -#ifdef Q_OS_LINUX - QTemporaryFile file; - file.setFileTemplate("XXXXXX.wav"); - if (file.open()) { - cst_voice* v = register_cmu_us_kal(NULL); - cst_wave* wav = flite_text_to_wave(text.toStdString().c_str(), v); - // file.fileName() returns the unique file name - cst_wave_save(wav, file.fileName().toStdString().c_str(), "riff"); - //m_media->setCurrentSource(Phonon::MediaSource(file.fileName().toStdString().c_str())); - //m_media->play(); - res = true; - } -#endif - -#ifdef Q_OS_MAC - // Slashes necessary to have the right start to the sentence - // copying data prevents SpeakString from reading additional chars - text = "\\" + text; - QStdWString str = text.toStdWString(); - unsigned char str2[1024] = {}; - memcpy(str2, text.toAscii().data(), str.length()); - SpeakString(str2); - res = true; -#endif - } - return res; - } - else - { - return false; - } -} - -/** - * @param text This message will be played after the alert beep - */ -bool GAudioOutput::alert(QString text) -{ - if (!emergency || !muted) - { - // Play alert sound - beep(); - // Say alert message - say(text, 2); - return true; - } - else - { - return false; - } -} - -void GAudioOutput::notifyPositive() -{ - if (!muted) - { - // Use QFile to transform path for all OS - QFile f(QCoreApplication::applicationDirPath()+QString("/files/audio/double_notify.wav")); - //m_media->setCurrentSource(Phonon::MediaSource(f.fileName().toStdString().c_str())); - //m_media->play(); - } -} - -void GAudioOutput::notifyNegative() -{ - if (!muted) - { - // Use QFile to transform path for all OS - QFile f(QCoreApplication::applicationDirPath()+QString("/files/audio/flat_notify.wav")); - //m_media->setCurrentSource(Phonon::MediaSource(f.fileName().toStdString().c_str())); - //m_media->play(); - } -} - -/** - * The emergency sound will be played continously during the emergency. - * call stopEmergency() to disable it again. No speech synthesis or other - * audio output is available during the emergency. - * - * @return true if the emergency could be started, false else - */ -bool GAudioOutput::startEmergency() -{ - if (!emergency) - { - emergency = true; - // Beep immediately and then start timer - if (!muted) beep(); - emergencyTimer->start(1500); - QTimer::singleShot(5000, this, SLOT(stopEmergency())); - } - return true; -} - -/** - * Stops the continous emergency sound. Use startEmergency() to start - * the emergency sound. - * - * @return true if the emergency could be stopped, false else - */ -bool GAudioOutput::stopEmergency() -{ - if (emergency) { - emergency = false; - emergencyTimer->stop(); - } - return true; -} - -void GAudioOutput::beep() -{ - if (!muted) - { - // Use QFile to transform path for all OS - QFile f(QCoreApplication::applicationDirPath()+QString("/files/audio/alert.wav")); - qDebug() << "FILE:" << f.fileName(); - //m_media->setCurrentSource(Phonon::MediaSource(f.fileName().toStdString().c_str())); - //m_media->play(); - } -} - -void GAudioOutput::selectFemaleVoice() -{ -#ifdef Q_OS_LINUX - //this->voice = register_cmu_us_slt(NULL); -#endif -} - -void GAudioOutput::selectMaleVoice() -{ -#ifdef Q_OS_LINUX - //this->voice = register_cmu_us_rms(NULL); -#endif -} - -/* -void GAudioOutput::selectNeutralVoice() -{ -#ifdef Q_OS_LINUX - this->voice = register_cmu_us_awb(NULL); -#endif -}*/ - -QStringList GAudioOutput::listVoices(void) -{ - QStringList l; -#ifdef Q_OS_LINUX2 - cst_voice *voice; - const cst_val *v; - - - - printf("Voices available: "); - for (v=flite_voice_list; v; v=val_cdr(v)) { - voice = val_voice(val_car(v)); - QString s; - s.sprintf("%s",voice->name); - printf("%s",voice->name); - l.append(s); - } - printf("\n"); - -#endif - return l; - -} +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2009, 2010 QGROUNDCONTROL PROJECT + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL 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 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Implementation of audio output + * + * @author Lorenz Meier + * + */ + +#include +#include +#include +#include "GAudioOutput.h" +#include "MG.h" + +#include + +#ifdef Q_OS_MAC +#include +#endif + +// Speech synthesis is only supported with MSVC compiler +#if _MSC_VER +// Documentation: http://msdn.microsoft.com/en-us/library/ee125082%28v=VS.85%29.aspx +#include + +//using System; +//using System.Speech.Synthesis; +#endif + +#ifdef Q_OS_LINUX +extern "C" { +#include + cst_voice *register_cmu_us_kal(const char *voxdir); +}; +#endif + +#ifdef _MSC_VER +ISpVoice *GAudioOutput::pVoice = NULL; +#endif + +/** + * This class follows the singleton design pattern + * @see http://en.wikipedia.org/wiki/Singleton_pattern + * A call to this function thus returns the only instance of this object + * the call can occur at any place in the code, no reference to the + * GAudioOutput object has to be passed. + */ +GAudioOutput *GAudioOutput::instance() +{ + static GAudioOutput *_instance = 0; + + if (_instance == 0) + { + _instance = new GAudioOutput(); + // Set the application as parent to ensure that this object + // will be destroyed when the main application exits + _instance->setParent(qApp); + } + + return _instance; +} + +#define QGC_GAUDIOOUTPUT_KEY QString("QGC_AUDIOOUTPUT_") + +GAudioOutput::GAudioOutput(QObject *parent) : QObject(parent), + voiceIndex(0), + emergency(false), + muted(false) +{ + // Load settings + QSettings settings; + settings.sync(); + muted = settings.value(QGC_GAUDIOOUTPUT_KEY + "muted", muted).toBool(); + + +#ifdef Q_OS_LINUX + flite_init(); +#endif + +#if _MSC_VER + pVoice = NULL; + + if (FAILED(::CoInitialize(NULL))) + { + qDebug("Creating COM object for audio output failed!"); + } + + else + { + + HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice); + + if (SUCCEEDED(hr)) + { + hr = pVoice->Speak(L"QGC audio output active!", 0, NULL); + //pVoice->Release(); + //pVoice = NULL; + } + } + +#endif + // Initialize audio output + m_media = new Phonon::MediaObject(this); + Phonon::AudioOutput *audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this); + createPath(m_media, audioOutput); + + // Prepare regular emergency signal, will be fired off on calling startEmergency() + emergencyTimer = new QTimer(); + connect(emergencyTimer, SIGNAL(timeout()), this, SLOT(beep())); + + switch (voiceIndex) + { + case 0: + selectFemaleVoice(); + break; + + default: + selectMaleVoice(); + break; + } +} + +GAudioOutput::~GAudioOutput() +{ +#ifdef _MSC_VER + pVoice->Release(); + pVoice = NULL; + ::CoUninitialize(); +#endif +} + + +void GAudioOutput::mute(bool mute) +{ + if (mute != muted) + { + this->muted = mute; + QSettings settings; + settings.setValue(QGC_GAUDIOOUTPUT_KEY + "muted", this->muted); + settings.sync(); + emit mutedChanged(muted); + } +} + +bool GAudioOutput::isMuted() +{ + return this->muted; +} + +bool GAudioOutput::say(QString text, int severity) +{ + if (!muted) + { + // TODO Add severity filter + Q_UNUSED(severity); + bool res = false; + + if (!emergency) + { + + // Speech synthesis is only supported with MSVC compiler +#ifdef _MSC_VER + /*SpeechSynthesizer synth = new SpeechSynthesizer(); + synth.SelectVoice("Microsoft Anna"); + synth.SpeakText(text.toStdString().c_str()); + res = true;*/ + /*ISpVoice * pVoice = NULL; + if (FAILED(::CoInitialize(NULL))) + { + qDebug("Creating COM object for audio output failed!"); + } + else + { + HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice); + if( SUCCEEDED( hr ) ) + { + hr = */pVoice->Speak(text.toStdWString().c_str(), SPF_ASYNC, NULL); + /*pVoice->WaitUntilDone(5000); + pVoice->Release(); + pVoice = NULL; + } + }*/ +#endif + +#ifdef Q_OS_LINUX + QTemporaryFile file; + file.setFileTemplate("XXXXXX.wav"); + + if (file.open()) + { + cst_voice *v = register_cmu_us_kal(NULL); + cst_wave *wav = flite_text_to_wave(text.toStdString().c_str(), v); + // file.fileName() returns the unique file name + cst_wave_save(wav, file.fileName().toStdString().c_str(), "riff"); + m_media->setCurrentSource(Phonon::MediaSource(QUrl::fromLocalFile(file.fileName().toStdString().c_str()))); + m_media->play(); + res = true; + } + +#endif + +#ifdef Q_OS_MAC + // Slashes necessary to have the right start to the sentence + // copying data prevents SpeakString from reading additional chars + text = "\\" + text; + QStdWString str = text.toStdWString(); + unsigned char str2[1024] = {}; + memcpy(str2, text.toAscii().data(), str.length()); + SpeakString(str2); + res = true; +#endif + } + + return res; + } + + else + { + return false; + } +} + +/** + * @param text This message will be played after the alert beep + */ +bool GAudioOutput::alert(QString text) +{ + if (!emergency || !muted) + { + // Play alert sound + beep(); + // Say alert message + say(text, 2); + return true; + } + + else + { + return false; + } +} + +void GAudioOutput::notifyPositive() +{ + if (!muted) + { + // Use QFile to transform path for all OS + QFile f(QCoreApplication::applicationDirPath() + QString("/files/audio/double_notify.wav")); + //m_media->setCurrentSource(Phonon::MediaSource(f.fileName().toStdString().c_str())); + //m_media->play(); + } +} + +void GAudioOutput::notifyNegative() +{ + if (!muted) + { + // Use QFile to transform path for all OS + QFile f(QCoreApplication::applicationDirPath() + QString("/files/audio/flat_notify.wav")); + //m_media->setCurrentSource(Phonon::MediaSource(f.fileName().toStdString().c_str())); + //m_media->play(); + } +} + +/** + * The emergency sound will be played continously during the emergency. + * call stopEmergency() to disable it again. No speech synthesis or other + * audio output is available during the emergency. + * + * @return true if the emergency could be started, false else + */ +bool GAudioOutput::startEmergency() +{ + if (!emergency) + { + emergency = true; + + // Beep immediately and then start timer + if (!muted) beep(); + + emergencyTimer->start(1500); + QTimer::singleShot(5000, this, SLOT(stopEmergency())); + } + + return true; +} + +/** + * Stops the continous emergency sound. Use startEmergency() to start + * the emergency sound. + * + * @return true if the emergency could be stopped, false else + */ +bool GAudioOutput::stopEmergency() +{ + if (emergency) + { + emergency = false; + emergencyTimer->stop(); + } + + return true; +} + +void GAudioOutput::beep() +{ + if (!muted) + { + // Use QFile to transform path for all OS + QFile f(QCoreApplication::applicationDirPath() + QString("/files/audio/alert.wav")); + qDebug() << "FILE:" << f.fileName(); + //m_media->setCurrentSource(Phonon::MediaSource(f.fileName().toStdString().c_str())); + //m_media->play(); + } +} + +void GAudioOutput::selectFemaleVoice() +{ +#ifdef Q_OS_LINUX + //this->voice = register_cmu_us_slt(NULL); +#endif +} + +void GAudioOutput::selectMaleVoice() +{ +#ifdef Q_OS_LINUX + //this->voice = register_cmu_us_rms(NULL); +#endif +} + +/* +void GAudioOutput::selectNeutralVoice() +{ +#ifdef Q_OS_LINUX + this->voice = register_cmu_us_awb(NULL); +#endif +}*/ + +QStringList GAudioOutput::listVoices(void) +{ + QStringList l; +#ifdef Q_OS_LINUX2 + cst_voice *voice; + const cst_val *v; + + + + printf("Voices available: "); + + for (v = flite_voice_list; v; v = val_cdr(v)) + { + voice = val_voice(val_car(v)); + QString s; + s.sprintf("%s", voice->name); + printf("%s", voice->name); + l.append(s); + } + + printf("\n"); + +#endif + return l; + +} diff --git a/src/GAudioOutput.h b/src/GAudioOutput.h index 78667290a0c9a1b68aa31a817575dc082f7499bf..2f7ecdf948f281002346175467f459103052a890 100644 --- a/src/GAudioOutput.h +++ b/src/GAudioOutput.h @@ -59,10 +59,15 @@ This file is part of the PIXHAWK project extern "C" { cst_voice *REGISTER_VOX(const char *voxdir); void UNREGISTER_VOX(cst_voice *vox); - cst_voice* register_cmu_us_kal16(const char *voxdir); + cst_voice *register_cmu_us_kal16(const char *voxdir); } #endif +#if _MSC_VER +// Documentation: http://msdn.microsoft.com/en-us/library/ee125082%28v=VS.85%29.aspx +#include +#endif + /** * @brief Audio Output (speech synthesizer and "beep" output) * This class follows the singleton design pattern @@ -73,10 +78,11 @@ class GAudioOutput : public QObject Q_OBJECT public: /** @brief Get the singleton instance */ - static GAudioOutput* instance(); + static GAudioOutput *instance(); /** @brief List available voices */ QStringList listVoices(void); - enum { + enum + { VOICE_MALE = 0, VOICE_FEMALE } QGVoice; @@ -86,7 +92,7 @@ public: public slots: /** @brief Say this text if current output priority matches */ - bool say(QString text, int severity=1); + bool say(QString text, int severity = 1); /** @brief Play alert sound and say notification message */ bool alert(QString text); /** @brief Start emergency sound */ @@ -115,16 +121,20 @@ protected: #endif #ifdef Q_OS_LINUX //cst_voice* voice; ///< The flite voice object +#endif +#ifdef _MSC_VER + static ISpVoice *pVoice; #endif int voiceIndex; ///< The index of the flite voice to use (awb, slt, rms) - Phonon::MediaObject* m_media; ///< The output object for audio - Phonon::AudioOutput* m_audioOutput; + Phonon::MediaObject *m_media; ///< The output object for audio + Phonon::AudioOutput *m_audioOutput; bool emergency; ///< Emergency status flag - QTimer* emergencyTimer; + QTimer *emergencyTimer; bool muted; private: - GAudioOutput(QObject* parent=NULL); -// ~GAudioOutput(); + GAudioOutput(QObject *parent = NULL); + ~GAudioOutput(); }; #endif // AUDIOOUTPUT_H + diff --git a/src/QGC.h b/src/QGC.h index bf36900d332a8dd1365ead9e14eacd0d1ebbb35f..e49b2a4ce76c27b6452519d64740fc0466f6c634 100644 --- a/src/QGC.h +++ b/src/QGC.h @@ -49,7 +49,7 @@ inline bool isinf(T value) { return (value == std::numeric_limits::infinity() || (-1*value) == std::numeric_limits::infinity()) && std::numeric_limits::has_infinity; } -#else +#elif defined __APPLE__ #include #ifndef isnan #define isnan(x) std::isnan(x) diff --git a/src/QGCCore.cc b/src/QGCCore.cc index d78341c2c0e4a7050c9e918e54ca5db403ae47e8..04fe7e7b8cb61fb4d80c9ceeaf31d0efeb23b075 100644 --- a/src/QGCCore.cc +++ b/src/QGCCore.cc @@ -53,6 +53,7 @@ This file is part of the QGROUNDCONTROL project #endif #include "UDPLink.h" #include "MAVLinkSimulationLink.h" +#include "SerialLink.h" /** @@ -76,8 +77,8 @@ QGCCore::QGCCore(bool firstStart, int &argc, char* argv[]) : QApplication(argc, // Set application name this->setApplicationName(QGC_APPLICATION_NAME); this->setApplicationVersion(QGC_APPLICATION_VERSION); - this->setOrganizationName(QLatin1String("QGroundControl")); - this->setOrganizationDomain("org.qgroundcontrol"); + this->setOrganizationName(QGC::ORG_NAME); + this->setOrganizationDomain(QGC::ORG_DOMAIN); // Set settings format QSettings::setDefaultFormat(QSettings::IniFormat); @@ -167,7 +168,16 @@ QGCCore::QGCCore(bool firstStart, int &argc, char* argv[]) : QApplication(argc, // to make sure that all components are initialized when the // first messages arrive udpLink = new UDPLink(QHostAddress::Any, 14550); - MainWindow::instance()->addLink(udpLink); + LinkManager::instance()->add(udpLink); + } else if (mainWindow->getCustomMode() == MainWindow::CUSTOM_MODE_PX4) { + udpLink = new UDPLink(QHostAddress::Any, 14550); + LinkManager::instance()->add(udpLink); + SerialLink *slink = new SerialLink(); + LinkManager::instance()->add(slink); + } else { + // We want to have a default serial link available for "quick" connecting. + SerialLink *slink = new SerialLink(); + LinkManager::instance()->add(slink); } #ifdef OPAL_RT @@ -175,13 +185,12 @@ QGCCore::QGCCore(bool firstStart, int &argc, char* argv[]) : QApplication(argc, OpalLink* opalLink = new OpalLink(); MainWindow::instance()->addLink(opalLink); #endif - MAVLinkSimulationLink* simulationLink = new MAVLinkSimulationLink(":/demo-log.txt"); - simulationLink->disconnect(); // Remove splash screen splashScreen->finish(mainWindow); - if (upgraded) mainWindow->showInfoMessage(tr("Default Settings Loaded"), tr("QGroundControl has been upgraded from version %1 to version %2. Some of your user preferences have been reset to defaults for safety reasons. Please adjust them where needed.").arg(lastApplicationVersion).arg(QGC_APPLICATION_VERSION)); + if (upgraded) mainWindow->showInfoMessage(tr("Default Settings Loaded"), + tr("qgroundcontrol has been upgraded from version %1 to version %2. Some of your user preferences have been reset to defaults for safety reasons. Please adjust them where needed.").arg(lastApplicationVersion).arg(QGC_APPLICATION_VERSION)); // Check if link could be connected if (udpLink && !udpLink->connect()) diff --git a/src/comm/LinkInterface.h b/src/comm/LinkInterface.h index 9d62a6c77c4e4ef8c52f241f1af8cc6cb3bc827b..9ecf75ac1d537ae2f1458e246bd19c422f413c72 100644 --- a/src/comm/LinkInterface.h +++ b/src/comm/LinkInterface.h @@ -61,6 +61,8 @@ public: */ virtual QString getName() const = 0; + virtual void requestReset() = 0; + /** * @brief Determine the connection status * diff --git a/src/comm/LinkManager.cc b/src/comm/LinkManager.cc index 59fc3a99eeea97b7ccea5c2dfce717df25d8a039..de948775727412d940074df04e8812e0e990dd23 100644 --- a/src/comm/LinkManager.cc +++ b/src/comm/LinkManager.cc @@ -84,13 +84,13 @@ void LinkManager::addProtocol(LinkInterface* link, ProtocolInterface* protocol) { // Connect link to protocol // the protocol will receive new bytes from the link - if(!link || !protocol) return; + if (!link || !protocol) return; QList linkList = protocolLinks.values(protocol); // If protocol has not been added before (list length == 0) // OR if link has not been added to protocol, add - if ((linkList.length() > 0 && !linkList.contains(link)) || linkList.length() == 0) + if (!linkList.contains(link)) { // Protocol is new, add connect(link, SIGNAL(bytesReceived(LinkInterface*, QByteArray)), protocol, SLOT(receiveBytes(LinkInterface*, QByteArray))); @@ -210,3 +210,18 @@ const QList LinkManager::getLinks() { return QList(links); } + +const QList LinkManager::getSerialLinks() +{ + QList s; + + foreach (LinkInterface* i, links) + { + SerialLink* link = qobject_cast(i); + + if (link) + s.append(link); + } + + return s; +} diff --git a/src/comm/LinkManager.h b/src/comm/LinkManager.h index ae7590ce729ac1565b0f56f666cd804965a769b6..f949ba909a6247eecb83340b63fbd3e809af23b7 100644 --- a/src/comm/LinkManager.h +++ b/src/comm/LinkManager.h @@ -36,6 +36,7 @@ This file is part of the PIXHAWK project #include #include #include +#include #include /** @@ -64,6 +65,9 @@ public: /** @brief Get a list of all links */ const QList getLinks(); + /** @brief Get a list of all serial links */ + const QList getSerialLinks(); + /** @brief Get a list of all protocols */ const QList getProtocols() { return protocolLinks.uniqueKeys(); diff --git a/src/comm/MAVLinkProtocol.cc b/src/comm/MAVLinkProtocol.cc index 4941c68a948d902830e3ef56d3658e46339e6c45..66f0280d8d9fe78537e1766bd2d6b4bd7298f76d 100644 --- a/src/comm/MAVLinkProtocol.cc +++ b/src/comm/MAVLinkProtocol.cc @@ -198,7 +198,7 @@ void MAVLinkProtocol::linkStatusChanged(bool connected) link->writeBytes(init, sizeof(init)); // Stop any running mavlink instance - char* cmd = "mavlink stop\n"; + const char* cmd = "mavlink stop\n"; link->writeBytes(cmd, strlen(cmd)); link->writeBytes(init, 2); cmd = "uorb start"; @@ -228,8 +228,11 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b) int linkId = link->getId(); static int mavlink09Count = 0; + static int nonmavlinkCount = 0; static bool decodedFirstPacket = false; static bool warnedUser = false; + static bool checkedUserNonMavlink = false; + static bool warnedUserNonMavlink = false; // FIXME: Add check for if link->getId() >= MAVLINK_COMM_NUM_BUFFERS for (int position = 0; position < b.size(); position++) { @@ -244,12 +247,41 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b) emit protocolStatusMessage("MAVLink Version or Baud Rate Mismatch", "Your MAVLink device seems to use the deprecated version 0.9, while QGroundControl only supports version 1.0+. Please upgrade the MAVLink version of your autopilot. If your autopilot is using version 1.0, check if the baud rates of QGroundControl and your autopilot are the same."); } - // Count parser errors as well. - totalErrorCounter[linkId] += status.packet_rx_drop_count; - + if (decodeState == 0 && !decodedFirstPacket) + { + nonmavlinkCount++; + if (nonmavlinkCount > 2000 && !warnedUserNonMavlink) + { + //2000 bytes with no mavlink message. Are we connected to a mavlink capable device? + if (!checkedUserNonMavlink) + { + link->requestReset(); + checkedUserNonMavlink = true; + } + else + { + warnedUserNonMavlink = true; + emit protocolStatusMessage("MAVLink Baud Rate Mismatch", "Please check if the baud rates of QGroundControl and your autopilot are the same."); + } + } + } if (decodeState == 1) { decodedFirstPacket = true; + + if(message.msgid == MAVLINK_MSG_ID_PING) + { + // process ping requests (tgt_system and tgt_comp must be zero) + mavlink_ping_t ping; + mavlink_msg_ping_decode(&message, &ping); + if(!ping.target_system && !ping.target_component) + { + mavlink_message_t msg; + mavlink_msg_ping_pack(getSystemId(), getComponentId(), &msg, ping.time_usec, ping.seq, message.sysid, message.compid); + sendMessage(msg); + } + } + #if defined(QGC_PROTOBUF_ENABLED) if (message.msgid == MAVLINK_MSG_ID_EXTENDED_MESSAGE) @@ -521,7 +553,7 @@ void MAVLinkProtocol::sendMessage(mavlink_message_t message) for (i = links.begin(); i != links.end(); ++i) { sendMessage(*i, message); - qDebug() << __FILE__ << __LINE__ << "SENT MESSAGE OVER" << ((LinkInterface*)*i)->getName() << "LIST SIZE:" << links.size(); +// qDebug() << __FILE__ << __LINE__ << "SENT MESSAGE OVER" << ((LinkInterface*)*i)->getName() << "LIST SIZE:" << links.size(); } } diff --git a/src/comm/MAVLinkSimulationLink.h b/src/comm/MAVLinkSimulationLink.h index 505a9012f77a2f03ecc10d35b79ba01090d889ee..f5befb91fc5fbd6e4d2a363cc2dd8546a0e4dc3e 100644 --- a/src/comm/MAVLinkSimulationLink.h +++ b/src/comm/MAVLinkSimulationLink.h @@ -54,7 +54,7 @@ public: qint64 bytesAvailable(); void run(); - + void requestReset() { } bool connect(); bool disconnect(); diff --git a/src/comm/QGCFlightGearLink.cc b/src/comm/QGCFlightGearLink.cc index 61341b048839ba72b215c3a52f32b31a3cf27ddb..7926fa28c257b5cf8b955bb0ed88575e0ae5b28d 100644 --- a/src/comm/QGCFlightGearLink.cc +++ b/src/comm/QGCFlightGearLink.cc @@ -26,6 +26,7 @@ This file is part of the QGROUNDCONTROL project * @brief Definition of UDP connection (server) for unmanned vehicles * @see Flightgear Manual http://mapserver.flightgear.org/getstart.pdf * @author Lorenz Meier + * @author Thomas Gubler * */ @@ -44,7 +45,8 @@ QGCFlightGearLink::QGCFlightGearLink(UASInterface* mav, QString startupArguments process(NULL), terraSync(NULL), flightGearVersion(0), - startupArguments(startupArguments) + startupArguments(startupArguments), + _sensorHilEnabled(true) { this->host = host; this->port = port+mav->getUASID(); @@ -172,6 +174,7 @@ void QGCFlightGearLink::updateControls(uint64_t time, float rollAilerons, float QString state("%1\t%2\t%3\t%4\t%5\n"); state = state.arg(rollAilerons).arg(pitchElevator).arg(yawRudder).arg(true).arg(throttle); writeBytes(state.toAscii().constData(), state.length()); +// qDebug() << "updated controls" << rollAilerons << pitchElevator << yawRudder << throttle; } else { @@ -227,49 +230,146 @@ void QGCFlightGearLink::readBytes() // Print string QString state(b); - //qDebug() << "FG LINK GOT:" << state; +// qDebug() << "FG LINK GOT:" << state; QStringList values = state.split("\t"); // Check length - if (values.size() != 17) + const int nValues = 21; + if (values.size() != nValues) { - qDebug() << "RETURN LENGTH MISMATCHING EXPECTED" << 17 << "BUT GOT" << values.size(); + qDebug() << "RETURN LENGTH MISMATCHING EXPECTED" << nValues << "BUT GOT" << values.size(); qDebug() << state; return; } // Parse string float roll, pitch, yaw, rollspeed, pitchspeed, yawspeed; - double lat, lon, alt; + double lat, lon, alt; + float ind_airspeed; + float true_airspeed; + float vx, vy, vz, xacc, yacc, zacc; + float diff_pressure; + float temperature; + float abs_pressure; + float mag_variation, mag_dip, xmag_ned, ymag_ned, zmag_ned, xmag_body, ymag_body, zmag_body; - // XXX add - float ind_airspeed = 0.0f; - float true_airspeed = 0.0f; - double vx, vy, vz, xacc, yacc, zacc; lat = values.at(1).toDouble(); lon = values.at(2).toDouble(); alt = values.at(3).toDouble(); - roll = values.at(4).toDouble(); - pitch = values.at(5).toDouble(); - yaw = values.at(6).toDouble(); - rollspeed = values.at(7).toDouble(); - pitchspeed = values.at(8).toDouble(); - yawspeed = values.at(9).toDouble(); + roll = values.at(4).toFloat(); + pitch = values.at(5).toFloat(); + yaw = values.at(6).toFloat(); + rollspeed = values.at(7).toFloat(); + pitchspeed = values.at(8).toFloat(); + yawspeed = values.at(9).toFloat(); - xacc = values.at(10).toDouble(); - yacc = values.at(11).toDouble(); - zacc = values.at(12).toDouble(); + xacc = values.at(10).toFloat(); + yacc = values.at(11).toFloat(); + zacc = values.at(12).toFloat(); - vx = values.at(13).toDouble(); - vy = values.at(14).toDouble(); - vz = values.at(15).toDouble(); + vx = values.at(13).toFloat(); + vy = values.at(14).toFloat(); + vz = values.at(15).toFloat(); + + true_airspeed = values.at(16).toFloat(); + + mag_variation = values.at(17).toFloat(); + mag_dip = values.at(18).toFloat(); + + temperature = values.at(19).toFloat(); + abs_pressure = values.at(20).toFloat()*1e2; //convert to Pa from hPa // Send updated state - emit hilStateChanged(QGC::groundTimeUsecs(), roll, pitch, yaw, rollspeed, + //qDebug() << "sensorHilEnabled: " << sensorHilEnabled; + if (_sensorHilEnabled) + { + quint16 fields_changed = 0xFFF; //set all 12 used bits + + //calculate differential pressure + const float air_gas_constant = 287.1f; // J/(kg * K) + const float absolute_null_celsius = -273.15f; // °C + float density = abs_pressure / (air_gas_constant * (temperature - absolute_null_celsius)); + diff_pressure = true_airspeed * true_airspeed * density / 2.0f; + //qDebug() << "diff_pressure: " << diff_pressure << "abs_pressure: " << abs_pressure; + + /* Calculate indicated airspeed */ + const float air_density_sea_level_15C = 1.225f; //kg/m^3 + if (diff_pressure > 0) + { + ind_airspeed = sqrtf((2.0f*diff_pressure) / air_density_sea_level_15C); + } else + { + ind_airspeed = -sqrtf((2.0f*fabsf(diff_pressure)) / air_density_sea_level_15C); + } + + //qDebug() << "ind_airspeed: " << ind_airspeed << "true_airspeed: " << true_airspeed; + + float pressure_alt = alt; + + xmag_ned = cosf(mag_variation); + ymag_ned = sinf(mag_variation); + zmag_ned = sinf(mag_dip); + float tempMagLength = sqrtf(xmag_ned*xmag_ned + ymag_ned*ymag_ned + zmag_ned*zmag_ned); + xmag_ned = xmag_ned / tempMagLength; + ymag_ned = ymag_ned / tempMagLength; + zmag_ned = zmag_ned / tempMagLength; + + //transform magnetic measurement to body frame coordinates + double cosPhi = cos(roll); + double sinPhi = sin(roll); + double cosThe = cos(pitch); + double sinThe = sin(pitch); + double cosPsi = cos(yaw); + double sinPsi = sin(yaw); + + float R_B_N[3][3]; + + R_B_N[0][0] = cosThe * cosPsi; + R_B_N[0][1] = -cosPhi * sinPsi + sinPhi * sinThe * cosPsi; + R_B_N[0][2] = sinPhi * sinPsi + cosPhi * sinThe * cosPsi; + + R_B_N[1][0] = cosThe * sinPsi; + R_B_N[1][1] = cosPhi * cosPsi + sinPhi * sinThe * sinPsi; + R_B_N[1][2] = -sinPhi * cosPsi + cosPhi * sinThe * sinPsi; + + R_B_N[2][0] = -sinThe; + R_B_N[2][1] = sinPhi * cosThe; + R_B_N[2][2] = cosPhi * cosThe; + + Eigen::Matrix3f R_B_N_M = Eigen::Map((float*)R_B_N).eval(); + + Eigen::Vector3f mag_ned(xmag_ned, ymag_ned, zmag_ned); + + Eigen::Vector3f mag_body = R_B_N_M * mag_ned; + + xmag_body = mag_body(0); + ymag_body = mag_body(1); + zmag_body = mag_body(2); + + emit sensorHilRawImuChanged(QGC::groundTimeUsecs(), xacc, yacc, zacc, rollspeed, pitchspeed, yawspeed, + xmag_body, ymag_body, zmag_body, abs_pressure*1e-2f, diff_pressure*1e-2f, pressure_alt, temperature, fields_changed); //Pressure in hPa for mavlink + +// qDebug() << "sensorHilRawImuChanged " << xacc << yacc << zacc << rollspeed << pitchspeed << yawspeed << xmag << ymag << zmag << abs_pressure << diff_pressure << pressure_alt << temperature; + int gps_fix_type = 3; + float eph = 0.3; + float epv = 0.6; + float vel = sqrt(vx*vx + vy*vy + vz*vz); + float cog = yaw; + int satellites = 8; + + emit sensorHilGpsChanged(QGC::groundTimeUsecs(), lat, lon, alt, gps_fix_type, eph, epv, vel, vx, vy, vz, cog, satellites); + +// qDebug() << "sensorHilGpsChanged " << lat << lon << alt << vel; + } else { + emit hilStateChanged(QGC::groundTimeUsecs(), roll, pitch, yaw, rollspeed, pitchspeed, yawspeed, lat, lon, alt, - vx, vy, vz, ind_airspeed, true_airspeed, xacc, yacc, zacc); + vx, vy, vz, + ind_airspeed, true_airspeed, + xacc, yacc, zacc); + //qDebug() << "hilStateChanged " << (int32_t)lat << (int32_t)lon << (int32_t)alt; + } // // Echo data for debugging purposes // std::cerr << __FILE__ << __LINE__ << "Received datagram:" << std::endl; @@ -303,7 +403,9 @@ bool QGCFlightGearLink::disconnectSimulation() disconnect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); disconnect(mav, SIGNAL(hilControlsChanged(uint64_t, float, float, float, float, uint8_t, uint8_t)), this, SLOT(updateControls(uint64_t,float,float,float,float,uint8_t,uint8_t))); - disconnect(this, SIGNAL(hilStateChanged(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float)), mav, SLOT(sendHilState(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float))); + disconnect(this, SIGNAL(hilStateChanged(quint64, float, float, float, float,float, float, double, double, double, float, float, float, float, float, float, float, float)), mav, SLOT(sendHilState(quint64, float, float, float, float,float, float, double, double, double, float, float, float, float, float, float, float, float))); + disconnect(this, SIGNAL(sensorHilGpsChanged(quint64, double, double, double, int, float, float, float, float, float, float, float, int)), mav, SLOT(sendHilGps(quint64, double, double, double, int, float, float, float, float, float, float, float, int))); + disconnect(this, SIGNAL(sensorHilRawImuChanged(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32)), mav, SLOT(sendHilSensors(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32))); if (process) { @@ -350,8 +452,9 @@ bool QGCFlightGearLink::connectSimulation() terraSync = new QProcess(this); connect(mav, SIGNAL(hilControlsChanged(uint64_t, float, float, float, float, uint8_t, uint8_t)), this, SLOT(updateControls(uint64_t,float,float,float,float,uint8_t,uint8_t))); - connect(this, SIGNAL(hilStateChanged(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float)), mav, SLOT(sendHilState(quint64,float,float,float,float,float,float,double,double,double,float,float,float,float,float,float,float,float))); - + connect(this, SIGNAL(hilStateChanged(quint64, float, float, float, float,float, float, double, double, double, float, float, float, float, float, float, float, float)), mav, SLOT(sendHilState(quint64, float, float, float, float,float, float, double, double, double, float, float, float, float, float, float, float, float))); + connect(this, SIGNAL(sensorHilGpsChanged(quint64, double, double, double, int, float, float, float, float, float, float, float, int)), mav, SLOT(sendHilGps(quint64, double, double, double, int, float, float, float, float, float, float, float, int))); + connect(this, SIGNAL(sensorHilRawImuChanged(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32)), mav, SLOT(sendHilSensors(quint64,float,float,float,float,float,float,float,float,float,float,float,float,float,quint32))); UAS* uas = dynamic_cast(mav); if (uas) diff --git a/src/comm/QGCFlightGearLink.h b/src/comm/QGCFlightGearLink.h index 9bdda2e5d53c32b6aa635a321675f2c0a408afe2..d043d3c63ba9c9ab60b186b3c0a7a633fe82f747 100644 --- a/src/comm/QGCFlightGearLink.h +++ b/src/comm/QGCFlightGearLink.h @@ -83,6 +83,10 @@ public: return _sensorHilEnabled; } + void sensorHilEnabled(bool sensorHilEnabled) { + _sensorHilEnabled = sensorHilEnabled; + } + void run(); public slots: diff --git a/src/comm/QGCXPlaneLink.cc b/src/comm/QGCXPlaneLink.cc index b96046b5a82ce06b0ed37635c6b6ee668b733ec7..89cf722a54ad0cfe2574811d86d1e34c9d8d31f8 100644 --- a/src/comm/QGCXPlaneLink.cc +++ b/src/comm/QGCXPlaneLink.cc @@ -292,15 +292,6 @@ void QGCXPlaneLink::updateActuators(uint64_t time, float act1, float act2, float void QGCXPlaneLink::updateControls(uint64_t time, float rollAilerons, float pitchElevator, float yawRudder, float throttle, uint8_t systemMode, uint8_t navMode) { - // Do not update this control type for - // all multirotors - if (mav->getSystemType() == MAV_TYPE_QUADROTOR || - mav->getSystemType() == MAV_TYPE_HEXAROTOR || - mav->getSystemType() == MAV_TYPE_OCTOROTOR) - { - return; - } - #pragma pack(push, 1) struct payload { char b[5]; @@ -315,7 +306,11 @@ void QGCXPlaneLink::updateControls(uint64_t time, float rollAilerons, float pitc p.b[3] = 'A'; p.b[4] = '\0'; - p.index = 12; + Q_UNUSED(time); + Q_UNUSED(systemMode); + Q_UNUSED(navMode); + + bool isFixedWing = true; if (mav->getAirframe() == UASInterface::QGC_AIRFRAME_X8 || mav->getAirframe() == UASInterface::QGC_AIRFRAME_VIPER_2_0 || @@ -329,31 +324,52 @@ void QGCXPlaneLink::updateControls(uint64_t time, float rollAilerons, float pitc // yaw p.f[2] = 0.0f; } + else if (mav->getSystemType() == MAV_TYPE_QUADROTOR) + { + qDebug() << "MAV_TYPE_QUADROTOR"; + + // Individual effort will be provided directly to the actuators on Xplane quadrotor. + p.f[0] = yawRudder; + p.f[1] = rollAilerons; + p.f[2] = throttle; + p.f[3] = pitchElevator; + + isFixedWing = false; + } else { - // direct pass-through + // direct pass-through, normal fixed-wing. p.f[0] = -pitchElevator; p.f[1] = rollAilerons; p.f[2] = yawRudder; } - Q_UNUSED(time); - Q_UNUSED(systemMode); - Q_UNUSED(navMode); + if(isFixedWing) + { + // Ail / Elevon / Rudder + p.index = 12; // XPlane, wing sweep + writeBytes((const char*)&p, sizeof(p)); + + p.index = 8; // XPlane, joystick? why? + writeBytes((const char*)&p, sizeof(p)); + + p.index = 25; // Thrust + memset(p.f, 0, sizeof(p.f)); + p.f[0] = throttle; + p.f[1] = throttle; + p.f[2] = throttle; + p.f[3] = throttle; + + // Throttle + writeBytes((const char*)&p, sizeof(p)); + } + else + { + qDebug() << "Transmitting p.index = 25"; + p.index = 25; // XPlane, throttle command. + writeBytes((const char*)&p, sizeof(p)); + } - // Ail / Elevon / Rudder - writeBytes((const char*)&p, sizeof(p)); - p.index = 8; - writeBytes((const char*)&p, sizeof(p)); - - p.index = 25; - memset(p.f, 0, sizeof(p.f)); - p.f[0] = throttle; - p.f[1] = throttle; - p.f[2] = throttle; - p.f[3] = throttle; - // Throttle - writeBytes((const char*)&p, sizeof(p)); } Eigen::Matrix3f euler_to_wRo(double yaw, double pitch, double roll) { @@ -693,7 +709,7 @@ void QGCXPlaneLink::readBytes() fields_changed |= (1 << 11); emit sensorHilRawImuChanged(QGC::groundTimeUsecs(), xacc, yacc, zacc, rollspeed, pitchspeed, yawspeed, - xmag, ymag, zmag, abs_pressure, diff_pressure, pressure_alt, temperature, fields_changed); + xmag, ymag, zmag, abs_pressure, diff_pressure / 100.0, pressure_alt, temperature, fields_changed); // XXX make these GUI-configurable and add randomness int gps_fix_type = 3; diff --git a/src/comm/SerialLink.cc b/src/comm/SerialLink.cc index 60a4ba568ad77eb850d49799f932a8a92376b357..6ae7105f59b6d00e123f77f037c61c914b083a84 100644 --- a/src/comm/SerialLink.cc +++ b/src/comm/SerialLink.cc @@ -12,370 +12,117 @@ #include #include #include +#include +#include #include "SerialLink.h" #include "LinkManager.h" #include "QGC.h" #include -#include -#ifdef _WIN32 -#include "windows.h" -#endif -#ifdef _WIN32 -#include -#endif -#if defined (__APPLE__) && defined (__MACH__) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __MWERKS__ -#define __CF_USE_FRAMEWORK_INCLUDES__ -#endif - - -#include - -#include -#include -#if defined(MAC_OS_X_VERSION_10_3) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3) -#include -#endif -#include - -// Apple internal modems default to local echo being on. If your modem has local echo disabled, -// undefine the following macro. -#define LOCAL_ECHO - -#define kATCommandString "AT\r" - -#ifdef LOCAL_ECHO -#define kOKResponseString "AT\r\r\nOK\r\n" -#else -#define kOKResponseString "\r\nOK\r\n" -#endif -#endif - - -// Some helper functions for serial port enumeration -#if defined (__APPLE__) && defined (__MACH__) - -enum { - kNumRetries = 3 -}; - -// Function prototypes -static kern_return_t FindModems(io_iterator_t *matchingServices); -static kern_return_t GetModemPath(io_iterator_t serialPortIterator, char *bsdPath, CFIndex maxPathSize); - -// Returns an iterator across all known modems. Caller is responsible for -// releasing the iterator when iteration is complete. -static kern_return_t FindModems(io_iterator_t *matchingServices) -{ - kern_return_t kernResult; - CFMutableDictionaryRef classesToMatch; - - /*! @function IOServiceMatching - @abstract Create a matching dictionary that specifies an IOService class match. - @discussion A very common matching criteria for IOService is based on its class. IOServiceMatching will create a matching dictionary that specifies any IOService of a class, or its subclasses. The class is specified by C-string name. - @param name The class name, as a const C-string. Class matching is successful on IOService's of this class or any subclass. - @result The matching dictionary created, is returned on success, or zero on failure. The dictionary is commonly passed to IOServiceGetMatchingServices or IOServiceAddNotification which will consume a reference, otherwise it should be released with CFRelease by the caller. */ - - // Serial devices are instances of class IOSerialBSDClient - classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue); - if (classesToMatch == NULL) { - printf("IOServiceMatching returned a NULL dictionary.\n"); - } else { - /*! - @function CFDictionarySetValue - Sets the value of the key in the dictionary. - @param theDict The dictionary to which the value is to be set. If this - parameter is not a valid mutable CFDictionary, the behavior is - undefined. If the dictionary is a fixed-capacity dictionary and - it is full before this operation, and the key does not exist in - the dictionary, the behavior is undefined. - @param key The key of the value to set into the dictionary. If a key - which matches this key is already present in the dictionary, only - the value is changed ("add if absent, replace if present"). If - no key matches the given key, the key-value pair is added to the - dictionary. If added, the key is retained by the dictionary, - using the retain callback provided - when the dictionary was created. If the key is not of the sort - expected by the key retain callback, the behavior is undefined. - @param value The value to add to or replace into the dictionary. The value - is retained by the dictionary using the retain callback provided - when the dictionary was created, and the previous value if any is - released. If the value is not of the sort expected by the - retain or release callbacks, the behavior is undefined. - */ - CFDictionarySetValue(classesToMatch, - CFSTR(kIOSerialBSDTypeKey), - CFSTR(kIOSerialBSDModemType)); - - // Each serial device object has a property with key - // kIOSerialBSDTypeKey and a value that is one of kIOSerialBSDAllTypes, - // kIOSerialBSDModemType, or kIOSerialBSDRS232Type. You can experiment with the - // matching by changing the last parameter in the above call to CFDictionarySetValue. - - // As shipped, this sample is only interested in modems, - // so add this property to the CFDictionary we're matching on. - // This will find devices that advertise themselves as modems, - // such as built-in and USB modems. However, this match won't find serial modems. - } - - /*! @function IOServiceGetMatchingServices - @abstract Look up registered IOService objects that match a matching dictionary. - @discussion This is the preferred method of finding IOService objects currently registered by IOKit. IOServiceAddNotification can also supply this information and install a notification of new IOServices. The matching information used in the matching dictionary may vary depending on the class of service being looked up. - @param masterPort The master port obtained from IOMasterPort(). - @param matching A CF dictionary containing matching information, of which one reference is consumed by this function. IOKitLib can contruct matching dictionaries for common criteria with helper functions such as IOServiceMatching, IOOpenFirmwarePathMatching. - @param existing An iterator handle is returned on success, and should be released by the caller when the iteration is finished. - @result A kern_return_t error code. */ - - kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatch, matchingServices); - if (KERN_SUCCESS != kernResult) { - printf("IOServiceGetMatchingServices returned %d\n", kernResult); - goto exit; - } -exit: - return kernResult; -} - -/** Given an iterator across a set of modems, return the BSD path to the first one. - * If no modems are found the path name is set to an empty string. - */ -static kern_return_t GetModemPath(io_iterator_t serialPortIterator, char *bsdPath, CFIndex maxPathSize) -{ - io_object_t modemService; - kern_return_t kernResult = KERN_FAILURE; - Boolean modemFound = false; - - // Initialize the returned path - *bsdPath = '\0'; - - // Iterate across all modems found. In this example, we bail after finding the first modem. - - while ((modemService = IOIteratorNext(serialPortIterator)) && !modemFound) { - CFTypeRef bsdPathAsCFString; - - // Get the callout device's path (/dev/cu.xxxxx). The callout device should almost always be - // used: the dialin device (/dev/tty.xxxxx) would be used when monitoring a serial port for - // incoming calls, e.g. a fax listener. - - bsdPathAsCFString = IORegistryEntryCreateCFProperty(modemService, - CFSTR(kIOCalloutDeviceKey), - kCFAllocatorDefault, - 0); - if (bsdPathAsCFString) { - Boolean result; - - // Convert the path from a CFString to a C (NUL-terminated) string for use - // with the POSIX open() call. - - result = CFStringGetCString((CFStringRef)bsdPathAsCFString, - bsdPath, - maxPathSize, - kCFStringEncodingUTF8); - CFRelease(bsdPathAsCFString); - - if (result) { - //printf("Modem found with BSD path: %s", bsdPath); - modemFound = true; - kernResult = KERN_SUCCESS; - } - } - - printf("\n"); - - // Release the io_service_t now that we are done with it. - - (void) IOObjectRelease(modemService); - } - - return kernResult; -} -#endif -using namespace TNX; SerialLink::SerialLink(QString portname, int baudRate, bool hardwareFlowControl, bool parity, int dataBits, int stopBits) : - port(NULL), - ports(new QVector()), + m_bytesRead(0), + m_port(NULL), m_stopp(false), - bytesRead(0) + m_reqReset(false) { // Setup settings - this->porthandle = portname.trimmed(); + m_portName = portname.trimmed(); - if (this->porthandle == "" && getCurrentPorts()->size() > 0) + if (m_portName == "" && getCurrentPorts().size() > 0) { - this->porthandle = getCurrentPorts()->first().trimmed(); + m_portName = m_ports.first().trimmed(); } -#ifdef _WIN32 - // Port names above 20 need the network path format - if the port name is not already in this format - // catch this special case - if (this->porthandle.size() > 0 && !this->porthandle.startsWith("\\")) { - // Append \\.\ before the port handle. Additional backslashes are used for escaping. - this->porthandle = "\\\\.\\" + this->porthandle; - } -#endif // Set unique ID and add link to the list of links - this->id = getNextLinkId(); + m_id = getNextLinkId(); + + m_baud = baudRate; - setBaudRate(baudRate); if (hardwareFlowControl) { - portSettings.setFlowControl(QPortSettings::FLOW_HARDWARE); + m_flowControl = QSerialPort::HardwareControl; } else { - portSettings.setFlowControl(QPortSettings::FLOW_OFF); + m_flowControl = QSerialPort::NoFlowControl; } if (parity) { - portSettings.setParity(QPortSettings::PAR_EVEN); + m_parity = QSerialPort::EvenParity; } else { - portSettings.setParity(QPortSettings::PAR_NONE); + m_parity = QSerialPort::NoParity; } - setDataBits(dataBits); - setStopBits(stopBits); - // Set the port name - if (porthandle == "") - { - name = tr("Serial Link ") + QString::number(getId()); - } - else - { - name = portname.trimmed(); - } + m_dataBits = dataBits; + m_stopBits = stopBits; + loadSettings(); + + qDebug() << "create SerialLink " << portname << baudRate << hardwareFlowControl + << parity << dataBits << stopBits; + qDebug() << "m_portName " << m_portName; + + LinkManager::instance()->add(this); +} +void SerialLink::requestReset() +{ + QMutexLocker locker(&this->m_stoppMutex); + m_reqReset = true; } SerialLink::~SerialLink() { disconnect(); - if(port) delete port; - port = NULL; - if (ports) delete ports; - ports = NULL; + if(m_port) delete m_port; + m_port = NULL; } -QVector* SerialLink::getCurrentPorts() +QList SerialLink::getCurrentPorts() { - ports->clear(); -#ifdef __linux - - // TODO Linux has no standard way of enumerating serial ports - // However the device files are only present when the physical - // device is connected, therefore listing the files should be - // sufficient. - - QString devdir = "/dev"; - QDir dir(devdir); - dir.setFilter(QDir::System); - - QFileInfoList list = dir.entryInfoList(); - for (int i = 0; i < list.size(); ++i) { - QFileInfo fileInfo = list.at(i); - if (fileInfo.fileName().contains(QString("ttyUSB")) || fileInfo.fileName().contains(QString("ttyS")) || fileInfo.fileName().contains(QString("ttyACM"))) - { - ports->append(fileInfo.canonicalFilePath()); - } - } -#endif - -#if defined (__APPLE__) && defined (__MACH__) - - // Enumerate serial ports - kern_return_t kernResult; // on PowerPC this is an int (4 bytes) - io_iterator_t serialPortIterator; - char bsdPath[MAXPATHLEN]; - kernResult = FindModems(&serialPortIterator); - kernResult = GetModemPath(serialPortIterator, bsdPath, sizeof(bsdPath)); - IOObjectRelease(serialPortIterator); // Release the iterator. + m_ports.clear(); - // Add found modems - if (bsdPath[0]) - { - ports->append(QString(bsdPath)); - } + QList portList = QSerialPortInfo::availablePorts(); - // Add USB serial port adapters - // TODO Strangely usb serial port adapters are not enumerated, even when connected - QString devdir = "/dev"; - QDir dir(devdir); - dir.setFilter(QDir::System); - - QFileInfoList list = dir.entryInfoList(); - for (int i = list.size() - 1; i >= 0; i--) { - QFileInfo fileInfo = list.at(i); - if (fileInfo.fileName().contains(QString("ttyUSB")) || - fileInfo.fileName().contains(QString("tty.")) || - fileInfo.fileName().contains(QString("ttyS")) || - fileInfo.fileName().contains(QString("ttyACM"))) - { - ports->append(fileInfo.canonicalFilePath()); - } + if( portList.count() == 0){ + qDebug() << "No Ports Found" << m_ports; } -#endif - -#ifdef _WIN32 - // Get the ports available on this system - QList ports = QextSerialEnumerator::getPorts(); - // Add the ports in reverse order, because we prepend them to the list - for (int i = ports.size() - 1; i >= 0; i--) + foreach (const QSerialPortInfo &info, portList) { - QextPortInfo portInfo = ports.at(i); - QString portString = QString(portInfo.portName.toLocal8Bit().constData()) + " - " + QString(ports.at(i).friendName.toLocal8Bit().constData()).split("(").first(); - // Prepend newly found port to the list - this->ports->append(portString); - } +// qDebug() << "PortName : " << info.portName() +// << "Description : " << info.description(); +// qDebug() << "Manufacturer: " << info.manufacturer(); - //printf("port name: %s\n", ports.at(i).portName.toLocal8Bit().constData()); - //printf("friendly name: %s\n", ports.at(i).friendName.toLocal8Bit().constData()); - //printf("physical name: %s\n", ports.at(i).physName.toLocal8Bit().constData()); - //printf("enumerator name: %s\n", ports.at(i).enumName.toLocal8Bit().constData()); - //printf("===================================\n\n"); -#endif - return this->ports; + m_ports.append(info.portName()); + } + return m_ports; } void SerialLink::loadSettings() { // Load defaults from settings - QSettings settings(QGC::COMPANYNAME, QGC::APPNAME); + QSettings settings(QGC::ORG_NAME, QGC::APPNAME); settings.sync(); if (settings.contains("SERIALLINK_COMM_PORT")) { - setPortName(settings.value("SERIALLINK_COMM_PORT").toString()); - setBaudRateType(settings.value("SERIALLINK_COMM_BAUD").toInt()); - setParityType(settings.value("SERIALLINK_COMM_PARITY").toInt()); - setStopBits(settings.value("SERIALLINK_COMM_STOPBITS").toInt()); - setDataBits(settings.value("SERIALLINK_COMM_DATABITS").toInt()); - setFlowType(settings.value("SERIALLINK_COMM_FLOW_CONTROL").toInt()); + m_portName = settings.value("SERIALLINK_COMM_PORT").toString(); + m_baud = settings.value("SERIALLINK_COMM_BAUD").toInt(); + m_parity = settings.value("SERIALLINK_COMM_PARITY").toInt(); + m_stopBits = settings.value("SERIALLINK_COMM_STOPBITS").toInt(); + m_dataBits = settings.value("SERIALLINK_COMM_DATABITS").toInt(); + m_flowControl = settings.value("SERIALLINK_COMM_FLOW_CONTROL").toInt(); } } void SerialLink::writeSettings() { // Store settings - QSettings settings(QGC::COMPANYNAME, QGC::APPNAME); + QSettings settings(QGC::ORG_NAME, QGC::APPNAME); settings.setValue("SERIALLINK_COMM_PORT", getPortName()); settings.setValue("SERIALLINK_COMM_BAUD", getBaudRateType()); settings.setValue("SERIALLINK_COMM_PARITY", getParityType()); @@ -393,46 +140,92 @@ void SerialLink::writeSettings() void SerialLink::run() { // Initialize the connection - if (!hardwareConnect()) - { + if (!hardwareConnect()) { //Need to error out here. - emit communicationError(getName(),"Error connecting: " + port->errorString()); + emit communicationError(getName(),"Error connecting: " + m_port->errorString()); + disconnect(); // This tidies up and sends the necessary signals + emit communicationError(tr("Serial Port %1").arg(getPortName()), tr("Cannot read / write data - check physical USB and cable connections.")); return; - } // Qt way to make clear what a while(1) loop does - quint64 msecs = QDateTime::currentMSecsSinceEpoch(); - quint64 initialmsecs = QDateTime::currentMSecsSinceEpoch(); + qint64 msecs = QDateTime::currentMSecsSinceEpoch(); + qint64 initialmsecs = QDateTime::currentMSecsSinceEpoch(); quint64 bytes = 0; bool triedreset = false; bool triedDTR = false; - int timeout = 5000; - forever - { + qint64 timeout = 5000; + int linkErrorCount = 0; + + forever { { - QMutexLocker locker(&this->m_stoppMutex); - if(this->m_stopp) - { - this->m_stopp = false; - break; + QMutexLocker locker(&this->m_stoppMutex); + if(m_stopp) { + m_stopp = false; + break; // exit the thread + } + + if (m_reqReset) { + m_reqReset = false; + emit communicationUpdate(getName(),"Reset requested via DTR signal"); + m_port->setDataTerminalReady(true); + msleep(250); + m_port->setDataTerminalReady(false); } } - // Check if new bytes have arrived, if yes, emit the notification signal - checkForBytes(); - if (bytes != bytesRead) - { - bytes = bytesRead; + + if (isConnected() && (linkErrorCount > 1000)) { + qDebug() << "linkErrorCount too high: disconnecting!"; + linkErrorCount = 0; + emit communicationUpdate(getName(), tr("Disconnecting on too many link errors")); + disconnect(); + } + + if (m_transmitBuffer.count() > 0) { + QMutexLocker writeLocker(&m_writeMutex); + int numWritten = m_port->write(m_transmitBuffer); + bool txSuccess = m_port->waitForBytesWritten(5); + if (!txSuccess || (numWritten != m_transmitBuffer.count())) { + linkErrorCount++; + qDebug() << "TX Error! wrote" << numWritten << ", asked for " << m_transmitBuffer.count() << "bytes"; + } + else { + linkErrorCount = 0; + } + m_transmitBuffer = m_transmitBuffer.remove(0, numWritten); + } + + //wait n msecs for data to be ready + //[TODO][BB] lower to SerialLink::poll_interval? + bool success = m_port->waitForReadyRead(10); + + if (success) { + QByteArray readData = m_port->readAll(); + while (m_port->waitForReadyRead(10)) + readData += m_port->readAll(); + if (readData.length() > 0) { + emit bytesReceived(this, readData); +// qDebug() << "rx of length " << QString::number(readData.length()); + + m_bytesRead += readData.length(); + m_bitsReceivedTotal += readData.length() * 8; + linkErrorCount = 0; + } + } + else { + linkErrorCount++; + //qDebug() << "Wait read response timeout" << QTime::currentTime().toString(); + } + + if (bytes != m_bytesRead) { // i.e things are good and data is being read. + bytes = m_bytesRead; msecs = QDateTime::currentMSecsSinceEpoch(); } - else - { - if (QDateTime::currentMSecsSinceEpoch() - msecs > timeout) - { + else { + if (QDateTime::currentMSecsSinceEpoch() - msecs > timeout) { //It's been 10 seconds since the last data came in. Reset and try again msecs = QDateTime::currentMSecsSinceEpoch(); - if (msecs - initialmsecs > 25000) - { + if (msecs - initialmsecs > 25000) { //After initial 25 seconds, timeouts are increased to 30 seconds. //This prevents temporary silences from things like calibration commands //from screwing things up. In all reality, timeouts should be enabled/disabled @@ -440,98 +233,60 @@ void SerialLink::run() //TODO ^^ timeout = 30000; } - if (!triedDTR && triedreset) - { + if (!triedDTR && triedreset) { triedDTR = true; - communicationUpdate(getName(),"No data to receive on COM port. Attempting to reset via DTR signal"); + emit communicationUpdate(getName(),"No data to receive on COM port. Attempting to reset via DTR signal"); qDebug() << "No data!!! Attempting reset via DTR."; - port->setDtr(true); - this->msleep(250); - port->setDtr(false); + m_port->setDataTerminalReady(true); + msleep(250); + m_port->setDataTerminalReady(false); } - else if (!triedreset) - { + else if (!triedreset) { qDebug() << "No data!!! Attempting reset via reboot command."; - communicationUpdate(getName(),"No data to receive on COM port. Assuming possible terminal mode, attempting to reset via \"reboot\" command"); - port->write("reboot\r\n",8); + emit communicationUpdate(getName(),"No data to receive on COM port. Assuming possible terminal mode, attempting to reset via \"reboot\" command"); + m_port->write("reboot\r\n",8); triedreset = true; } - else - { - communicationUpdate(getName(),"No data to receive on COM port...."); + else { + emit communicationUpdate(getName(),"No data to receive on COM port...."); qDebug() << "No data!!!"; } } } - /* Serial data isn't arriving that fast normally, this saves the thread - * from consuming too much processing time - */ MG::SLEEP::msleep(SerialLink::poll_interval); - } - if (port) { - port->flushInBuffer(); - port->flushOutBuffer(); - port->close(); - delete port; - port = NULL; - } -} - - -void SerialLink::checkForBytes() -{ - /* Check if bytes are available */ - if(port && port->isOpen() && port->isWritable()) - { - dataMutex.lock(); - qint64 available = port->bytesAvailable(); - dataMutex.unlock(); + } // end of forever + + if (m_port) { // [TODO][BB] Not sure we need to close the port here + qDebug() << "Closing Port #"<< __LINE__ << m_port->portName(); + m_port->close(); + delete m_port; + m_port = NULL; - if(available > 0) - { - readBytes(); - bytesRead += available; - } - else if (available < 0) { - /* Error, close port */ - port->close(); - emit disconnected(); - emit connected(false); - emit communicationError(this->getName(), tr("Could not send data - link %1 is disconnected!").arg(this->getName())); - } + emit disconnected(); + emit connected(false); } -// else -// { -// emit disconnected(); -// emit connected(false); -// } - } void SerialLink::writeBytes(const char* data, qint64 size) { - if(port && port->isOpen()) { - int b = port->write(data, size); - - if (b > 0) { + if(m_port && m_port->isOpen()) { +// qDebug() << "writeBytes" << m_portName << "attempting to tx " << size << "bytes."; - // qDebug() << "Serial link " << this->getName() << "transmitted" << b << "bytes:"; + QByteArray byteArray(data, size); + { + QMutexLocker writeLocker(&m_writeMutex); + m_transmitBuffer.append(byteArray); + } - // Increase write counter - bitsSentTotal += size * 8; + // Increase write counter + m_bitsSentTotal += size * 8; - // int i; - // for (i=0; igetName(), tr("Could not send data - link %1 is disconnected!").arg(this->getName())); - } + // Extra debug logging +// qDebug() << byteArray->toHex(); + } else { + disconnect(); + // Error occured + emit communicationError(getName(), tr("Could not send data - link %1 is disconnected!").arg(getName())); } } @@ -543,18 +298,18 @@ void SerialLink::writeBytes(const char* data, qint64 size) **/ void SerialLink::readBytes() { - dataMutex.lock(); - if(port && port->isOpen()) { + m_dataMutex.lock(); + if(m_port && m_port->isOpen()) { const qint64 maxLength = 2048; char data[maxLength]; - qint64 numBytes = port->bytesAvailable(); + qint64 numBytes = m_port->bytesAvailable(); //qDebug() << "numBytes: " << numBytes; if(numBytes > 0) { /* Read as much data in buffer as possible without overflow */ if(maxLength < numBytes) numBytes = maxLength; - port->read(data, numBytes); + m_port->read(data, numBytes); QByteArray b(data, numBytes); emit bytesReceived(this, b); @@ -566,10 +321,10 @@ void SerialLink::readBytes() // fprintf(stderr,"%02x ", v); // } // fprintf(stderr,"\n"); - bitsReceivedTotal += numBytes * 8; + m_bitsReceivedTotal += numBytes * 8; } } - dataMutex.unlock(); + m_dataMutex.unlock(); } @@ -580,8 +335,8 @@ void SerialLink::readBytes() **/ qint64 SerialLink::bytesAvailable() { - if (port) { - return port->bytesAvailable(); + if (m_port) { + return m_port->bytesAvailable(); } else { return 0; } @@ -594,44 +349,28 @@ qint64 SerialLink::bytesAvailable() **/ bool SerialLink::disconnect() { - if(this->isRunning()) + qDebug() << "disconnect"; + if (m_port) + qDebug() << m_port->portName(); + + if (isRunning()) { + qDebug() << "running so disconnect" << m_port->portName(); { - QMutexLocker locker(&this->m_stoppMutex); - this->m_stopp = true; + QMutexLocker locker(&m_stoppMutex); + m_stopp = true; } - this->wait(); - - // if (port) { - //#if !defined _WIN32 || !defined _WIN64 - /* Block the thread until it returns from run() */ - //#endif - // port->flushInBuffer(); - // port->flushOutBuffer(); - // port->close(); - // delete port; - // port = NULL; - - // if(this->isRunning()) this->terminate(); //stop running the thread, restart it upon connect + wait(); // This will terminate the thread and close the serial port - bool closed = true; - //port->isOpen(); - - emit disconnected(); + emit disconnected(); // [TODO] There are signals from QSerialPort we should use emit connected(false); - if (port) { - port->close(); - } - return closed; - } - else { - // not running - if (port) { - port->close(); - } return true; } + m_transmitBuffer.clear(); //clear the output buffer to avoid sending garbage at next connect + + qDebug() << "already disconnected"; + return true; } /** @@ -640,13 +379,15 @@ bool SerialLink::disconnect() * @return True if connection has been established, false if connection couldn't be established. **/ bool SerialLink::connect() -{ - if (this->isRunning()) this->disconnect(); +{ + if (isRunning()) + disconnect(); { QMutexLocker locker(&this->m_stoppMutex); - this->m_stopp = false; + m_stopp = false; } - this->start(LowPriority); + + start(LowPriority); return true; } @@ -660,36 +401,56 @@ bool SerialLink::connect() **/ bool SerialLink::hardwareConnect() { - if(port) { - port->close(); - delete port; + if(m_port) { + qDebug() << "SerialLink:" << QString::number((long)this, 16) << "closing port"; + m_port->close(); + delete m_port; + m_port = NULL; } - port = new QSerialPort(porthandle, portSettings); - QObject::connect(port,SIGNAL(aboutToClose()),this,SIGNAL(disconnected())); - port->setCommTimeouts(QSerialPort::CtScheme_NonBlockingRead); - connectionStartTime = MG::TIME::getGroundTimeNow(); + qDebug() << "SerialLink: hardwareConnect to " << m_portName; + m_port = new QSerialPort(m_portName); - if (!port->open()) - { - emit communicationUpdate(getName(),"Error opening port: " + port->errorString()); - } - else - { - emit communicationUpdate(getName(),"Opened port!"); + if (m_port == NULL) { + emit communicationUpdate(getName(),"Error opening port: " + m_port->errorString()); + return false; // couldn't create serial port. } - bool connectionUp = isConnected(); - if(connectionUp) { - emit connected(); - emit connected(true); + QObject::connect(m_port,SIGNAL(aboutToClose()),this,SIGNAL(disconnected())); + QObject::connect(m_port, SIGNAL(error(SerialLinkPortError_t)), + this, SLOT(linkError(SerialLinkPortError_t))); + +// port->setCommTimeouts(QSerialPort::CtScheme_NonBlockingRead); + m_connectionStartTime = MG::TIME::getGroundTimeNow(); + + if (!m_port->open(QIODevice::ReadWrite)) { + emit communicationUpdate(getName(),"Error opening port: " + m_port->errorString()); + m_port->close(); + return false; // couldn't open serial port } - //qDebug() << "CONNECTING LINK: " << __FILE__ << __LINE__ << "with settings" << port->portName() << getBaudRate() << getDataBits() << getParityType() << getStopBits(); + emit communicationUpdate(getName(),"Opened port!"); + + // Need to configure the port + m_port->setBaudRate(m_baud); + m_port->setDataBits(static_cast(m_dataBits)); + m_port->setFlowControl(static_cast(m_flowControl)); + m_port->setStopBits(static_cast(m_stopBits)); + m_port->setParity(static_cast(m_parity)); + emit connected(); + emit connected(true); + + qDebug() << "CONNECTING LINK: " << __FILE__ << __LINE__ << "with settings" << m_port->portName() + << getBaudRate() << getDataBits() << getParityType() << getStopBits(); writeSettings(); - return connectionUp; + return true; // successful connection +} + +void SerialLink::linkError(SerialLinkPortError_t error) +{ + qDebug() << error; } @@ -700,138 +461,82 @@ bool SerialLink::hardwareConnect() **/ bool SerialLink::isConnected() const { - if (port) { - return port->isOpen(); + + if (m_port) { + bool isConnected = m_port->isOpen(); +// qDebug() << "SerialLink #" << __LINE__ << ":"<< m_port->portName() +// << " isConnected =" << QString::number(isConnected); + return isConnected; } else { +// qDebug() << "SerialLink #" << __LINE__ << ":" << m_portName +// << " isConnected = NULL"; return false; } } int SerialLink::getId() const { - return id; + return m_id; } QString SerialLink::getName() const { - return name; + return m_portName; } -void SerialLink::setName(QString name) -{ - this->name = name; - emit nameChanged(this->name); -} - - /** * This function maps baud rate constants to numerical equivalents. * It relies on the mapping given in qportsettings.h from the QSerialPort library. */ qint64 SerialLink::getNominalDataRate() const { - qint64 dataRate = 0; - switch (portSettings.baudRate()) { - - // Baud rates supported only by POSIX systems -#if defined(Q_OS_UNIX) || defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) - case QPortSettings::BAUDR_50: - dataRate = 50; - break; - case QPortSettings::BAUDR_75: - dataRate = 75; - break; - case QPortSettings::BAUDR_134: - dataRate = 134; - break; - case QPortSettings::BAUDR_150: - dataRate = 150; - break; - case QPortSettings::BAUDR_200: - dataRate = 200; - break; - case QPortSettings::BAUDR_1800: - dataRate = 1800; - break; -#endif - - // Baud rates supported only by Windows -#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) - case QPortSettings::BAUDR_14400: - dataRate = 14400; - break; - case QPortSettings::BAUDR_56000: - dataRate = 56000; - break; - case QPortSettings::BAUDR_128000: - dataRate = 128000; - break; - case QPortSettings::BAUDR_256000: - dataRate = 256000; -#endif - - case QPortSettings::BAUDR_110: - dataRate = 110; - break; - case QPortSettings::BAUDR_300: - dataRate = 300; - break; - case QPortSettings::BAUDR_600: - dataRate = 600; - break; - case QPortSettings::BAUDR_1200: - dataRate = 1200; - break; - case QPortSettings::BAUDR_2400: - dataRate = 2400; - break; - case QPortSettings::BAUDR_4800: - dataRate = 4800; - break; - case QPortSettings::BAUDR_9600: - dataRate = 9600; - break; - case QPortSettings::BAUDR_19200: - dataRate = 19200; - break; - case QPortSettings::BAUDR_38400: - dataRate = 38400; - break; - case QPortSettings::BAUDR_57600: - dataRate = 57600; - break; - case QPortSettings::BAUDR_115200: - dataRate = 115200; - break; - case QPortSettings::BAUDR_230400: - dataRate = 230400; - break; - case QPortSettings::BAUDR_460800: - dataRate = 460800; - break; - case QPortSettings::BAUDR_500000: - dataRate = 500000; - break; - case QPortSettings::BAUDR_576000: - dataRate = 576000; - break; - case QPortSettings::BAUDR_921600: - dataRate = 921600; - break; - - // Otherwise do nothing. - case QPortSettings::BAUDR_UNKNOWN: - default: - break; + int baudRate; + if (m_port) { + baudRate = m_port->baudRate(); + } else { + baudRate = m_baud; + } + qint64 dataRate; + switch (baudRate) + { + case QSerialPort::Baud1200: + dataRate = 1200; + break; + case QSerialPort::Baud2400: + dataRate = 2400; + break; + case QSerialPort::Baud4800: + dataRate = 4800; + break; + case QSerialPort::Baud9600: + dataRate = 9600; + break; + case QSerialPort::Baud19200: + dataRate = 19200; + break; + case QSerialPort::Baud38400: + dataRate = 38400; + break; + case QSerialPort::Baud57600: + dataRate = 57600; + break; + case QSerialPort::Baud115200: + dataRate = 115200; + break; + // Otherwise do nothing. + case QSerialPort::UnknownBaud: + default: + dataRate = -1; + break; } return dataRate; } qint64 SerialLink::getTotalUpstream() { - statisticsMutex.lock(); - return bitsSentTotal / ((MG::TIME::getGroundTimeNow() - connectionStartTime) / 1000); - statisticsMutex.unlock(); + m_statisticsMutex.lock(); + return m_bitsSentTotal / ((MG::TIME::getGroundTimeNow() - m_connectionStartTime) / 1000); + m_statisticsMutex.unlock(); } qint64 SerialLink::getCurrentUpstream() @@ -846,19 +551,19 @@ qint64 SerialLink::getMaxUpstream() qint64 SerialLink::getBitsSent() const { - return bitsSentTotal; + return m_bitsSentTotal; } qint64 SerialLink::getBitsReceived() const { - return bitsReceivedTotal; + return m_bitsReceivedTotal; } qint64 SerialLink::getTotalDownstream() { - statisticsMutex.lock(); - return bitsReceivedTotal / ((MG::TIME::getGroundTimeNow() - connectionStartTime) / 1000); - statisticsMutex.unlock(); + m_statisticsMutex.lock(); + return m_bitsReceivedTotal / ((MG::TIME::getGroundTimeNow() - m_connectionStartTime) / 1000); + m_statisticsMutex.unlock(); } qint64 SerialLink::getCurrentDownstream() @@ -885,9 +590,11 @@ int SerialLink::getLinkQuality() const QString SerialLink::getPortName() const { - return porthandle; + return m_portName; } +// We should replace the accessors below with one to get the QSerialPort + int SerialLink::getBaudRate() const { return getNominalDataRate(); @@ -895,43 +602,80 @@ int SerialLink::getBaudRate() const int SerialLink::getBaudRateType() const { - return portSettings.baudRate(); + int baudRate; + if (m_port) { + baudRate = m_port->baudRate(); + } else { + baudRate = m_baud; + } + return baudRate; } int SerialLink::getFlowType() const { - return portSettings.flowControl(); + int flowControl; + if (m_port) { + flowControl = m_port->flowControl(); + } else { + flowControl = m_flowControl; + } + return flowControl; } int SerialLink::getParityType() const { - return portSettings.parity(); + int parity; + if (m_port) { + parity = m_port->parity(); + } else { + parity = m_parity; + } + return parity; } int SerialLink::getDataBitsType() const { - return portSettings.dataBits(); + int dataBits; + if (m_port) { + dataBits = m_port->dataBits(); + } else { + dataBits = m_dataBits; + } + return dataBits; } int SerialLink::getStopBitsType() const { - return portSettings.stopBits(); + int stopBits; + if (m_port) { + stopBits = m_port->stopBits(); + } else { + stopBits = m_stopBits; + } + return stopBits; } int SerialLink::getDataBits() const { - int ret = -1; - switch (portSettings.dataBits()) { - case QPortSettings::DB_5: + int ret; + int dataBits; + if (m_port) { + dataBits = m_port->dataBits(); + } else { + dataBits = m_dataBits; + } + + switch (dataBits) { + case QSerialPort::Data5: ret = 5; break; - case QPortSettings::DB_6: + case QSerialPort::Data6: ret = 6; break; - case QPortSettings::DB_7: + case QSerialPort::Data7: ret = 7; break; - case QPortSettings::DB_8: + case QSerialPort::Data8: ret = 8; break; default: @@ -943,12 +687,18 @@ int SerialLink::getDataBits() const int SerialLink::getStopBits() const { + int stopBits; + if (m_port) { + stopBits = m_port->stopBits(); + } else { + stopBits = m_stopBits; + } int ret = -1; - switch (portSettings.stopBits()) { - case QPortSettings::STOP_1: + switch (stopBits) { + case QSerialPort::OneStop: ret = 1; break; - case QPortSettings::STOP_2: + case QSerialPort::TwoStop: ret = 2; break; default: @@ -960,56 +710,40 @@ int SerialLink::getStopBits() const bool SerialLink::setPortName(QString portName) { - if(portName.trimmed().length() > 0) { - bool reconnect = false; - if (isConnected()) reconnect = true; - disconnect(); - - this->porthandle = portName.trimmed(); - setName(tr("serial port ") + portName.trimmed()); -#ifdef _WIN32 - // Port names above 20 need the network path format - if the port name is not already in this format - // catch this special case - if (!this->porthandle.startsWith("\\")) { - // Append \\.\ before the port handle. Additional backslashes are used for escaping. - this->porthandle = "\\\\.\\" + this->porthandle; - } -#endif + qDebug() << "current portName " << m_portName; + qDebug() << "setPortName to " << portName; + bool accepted = false; + if ((portName != m_portName) + && (portName.trimmed().length() > 0)) { + m_portName = portName.trimmed(); +// m_name = tr("serial port ") + portName.trimmed(); // [TODO] Do we need this? + if(m_port) + m_port->setPortName(portName); - if(reconnect) connect(); - return true; - } else { - return false; + emit nameChanged(m_portName); // [TODO] maybe we can eliminate this + emit updateLink(this); + return accepted; } + return false; } bool SerialLink::setBaudRateType(int rateIndex) { - bool reconnect = false; - bool accepted = true; // This is changed if none of the data rates matches - if(isConnected()) reconnect = true; - disconnect(); + Q_ASSERT_X(m_port != NULL, "setBaudRateType", "m_port is NULL"); + // These minimum and maximum baud rates were based on those enumerated in qserialport.h + bool result; + const int minBaud = (int)QSerialPort::Baud1200; + const int maxBaud = (int)QSerialPort::Baud115200; - // These minimum and maximum baud rates were based on those enumerated in qportsettings.h. -#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) - const int minBaud = (int)QPortSettings::BAUDR_110; - const int maxBaud = (int)QPortSettings::BAUDR_921600; -#elif defined(Q_OS_LINUX) - const int minBaud = (int)QPortSettings::BAUDR_50; - const int maxBaud = (int)QPortSettings::BAUDR_921600; -#elif defined(Q_OS_UNIX) || defined(Q_OS_DARWIN) - const int minBaud = (int)QPortSettings::BAUDR_50; - const int maxBaud = (int)QPortSettings::BAUDR_921600; -#endif - - if (rateIndex >= minBaud && rateIndex <= maxBaud) + if (m_port && (rateIndex >= minBaud && rateIndex <= maxBaud)) { - portSettings.setBaudRate((QPortSettings::BaudRate)rateIndex); + result = m_port->setBaudRate(static_cast(rateIndex)); + emit updateLink(this); + return result; } - if(reconnect) connect(); - return accepted; + return false; } bool SerialLink::setBaudRateString(const QString& rate) @@ -1022,260 +756,111 @@ bool SerialLink::setBaudRateString(const QString& rate) bool SerialLink::setBaudRate(int rate) { - bool reconnect = false; - bool accepted = true; // This is changed if none of the data rates matches - if(isConnected()) { - reconnect = true; - } - disconnect(); - - // This switch-statment relies on the mapping given in qportsettings.h from the QSerialPort library. - switch (rate) { - - // Baud rates supported only by non-Windows systems -#if defined(Q_OS_UNIX) || defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) - case 50: - portSettings.setBaudRate(QPortSettings::BAUDR_50); - break; - case 75: - portSettings.setBaudRate(QPortSettings::BAUDR_75); - break; - case 134: - portSettings.setBaudRate(QPortSettings::BAUDR_134); - break; - case 150: - portSettings.setBaudRate(QPortSettings::BAUDR_150); - break; - case 200: - portSettings.setBaudRate(QPortSettings::BAUDR_200); - break; - case 1800: - portSettings.setBaudRate(QPortSettings::BAUDR_1800); - break; -#endif - - // Baud rates supported only by windows -#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) - case 14400: - portSettings.setBaudRate(QPortSettings::BAUDR_14400); - break; - case 56000: - portSettings.setBaudRate(QPortSettings::BAUDR_56000); - break; - case 128000: - portSettings.setBaudRate(QPortSettings::BAUDR_128000); - break; - case 256000: - portSettings.setBaudRate(QPortSettings::BAUDR_256000); - break; -#endif - - // Supported by all OSes: - case 110: - portSettings.setBaudRate(QPortSettings::BAUDR_110); - break; - case 300: - portSettings.setBaudRate(QPortSettings::BAUDR_300); - break; - case 600: - portSettings.setBaudRate(QPortSettings::BAUDR_600); - break; - case 1200: - portSettings.setBaudRate(QPortSettings::BAUDR_1200); - break; - case 2400: - portSettings.setBaudRate(QPortSettings::BAUDR_2400); - break; - case 4800: - portSettings.setBaudRate(QPortSettings::BAUDR_4800); - break; - case 9600: - portSettings.setBaudRate(QPortSettings::BAUDR_9600); - break; - case 19200: - portSettings.setBaudRate(QPortSettings::BAUDR_19200); - break; - case 38400: - portSettings.setBaudRate(QPortSettings::BAUDR_38400); - break; - case 57600: - portSettings.setBaudRate(QPortSettings::BAUDR_57600); - break; - case 115200: - portSettings.setBaudRate(QPortSettings::BAUDR_115200); - break; - case 230400: - portSettings.setBaudRate(QPortSettings::BAUDR_230400); - break; - case 460800: - portSettings.setBaudRate(QPortSettings::BAUDR_460800); - break; - case 500000: - portSettings.setBaudRate(QPortSettings::BAUDR_500000); - break; - case 576000: - portSettings.setBaudRate(QPortSettings::BAUDR_576000); - break; - case 921600: - portSettings.setBaudRate(QPortSettings::BAUDR_921600); - break; - default: - // If none of the above cases matches, there must be an error - accepted = false; - break; + bool accepted = false; + if (rate != m_baud) { + m_baud = rate; + accepted = true; + if (m_port) + accepted = m_port->setBaudRate(rate); + emit updateLink(this); } - - if(reconnect) connect(); return accepted; - } bool SerialLink::setFlowType(int flow) { - bool reconnect = false; - bool accepted = true; - if(isConnected()) reconnect = true; - disconnect(); - - switch (flow) { - case (int)QPortSettings::FLOW_OFF: - portSettings.setFlowControl(QPortSettings::FLOW_OFF); - break; - case (int)QPortSettings::FLOW_HARDWARE: - portSettings.setFlowControl(QPortSettings::FLOW_HARDWARE); - break; - case (int)QPortSettings::FLOW_XONXOFF: - portSettings.setFlowControl(QPortSettings::FLOW_XONXOFF); - break; - default: - // If none of the above cases matches, there must be an error - accepted = false; - break; + bool accepted = false; + if (flow != m_flowControl) { + m_flowControl = static_cast(flow); + accepted = true; + if (m_port) + accepted = m_port->setFlowControl(static_cast(flow)); + emit updateLink(this); } - - if(reconnect) connect(); return accepted; } bool SerialLink::setParityType(int parity) { - bool reconnect = false; - bool accepted = true; - if (isConnected()) reconnect = true; - disconnect(); - - switch (parity) { - case (int)QPortSettings::PAR_NONE: - portSettings.setParity(QPortSettings::PAR_NONE); - break; - case (int)QPortSettings::PAR_ODD: - portSettings.setParity(QPortSettings::PAR_ODD); - break; - case (int)QPortSettings::PAR_EVEN: - portSettings.setParity(QPortSettings::PAR_EVEN); - break; - case (int)QPortSettings::PAR_SPACE: - portSettings.setParity(QPortSettings::PAR_SPACE); - break; - default: - // If none of the above cases matches, there must be an error - accepted = false; - break; + bool accepted = false; + if (parity != m_parity) { + m_parity = static_cast(parity); + accepted = true; + if (m_port) { + switch (parity) { + case QSerialPort::NoParity: + accepted = m_port->setParity(QSerialPort::NoParity); + break; + case 1: // Odd Parity setting for backwards compatibilty + accepted = m_port->setParity(QSerialPort::OddParity); + break; + case QSerialPort::EvenParity: + accepted = m_port->setParity(QSerialPort::EvenParity); + break; + case QSerialPort::OddParity: + accepted = m_port->setParity(QSerialPort::OddParity); + break; + default: + // If none of the above cases matches, there must be an error + accepted = false; + break; + } + emit updateLink(this); + } } - - if (reconnect) connect(); return accepted; } bool SerialLink::setDataBits(int dataBits) { - //qDebug() << "Setting" << dataBits << "data bits"; - bool reconnect = false; - if (isConnected()) reconnect = true; - bool accepted = true; - disconnect(); - - switch (dataBits) { - case 5: - portSettings.setDataBits(QPortSettings::DB_5); - break; - case 6: - portSettings.setDataBits(QPortSettings::DB_6); - break; - case 7: - portSettings.setDataBits(QPortSettings::DB_7); - break; - case 8: - portSettings.setDataBits(QPortSettings::DB_8); - break; - default: - // If none of the above cases matches, there must be an error - accepted = false; - break; + bool accepted = false; + if (dataBits != m_dataBits) { + m_dataBits = static_cast(dataBits); + accepted = true; + if (m_port) + accepted = m_port->setDataBits(static_cast(dataBits)); + emit updateLink(this); } - - if(reconnect) connect(); - return accepted; } bool SerialLink::setStopBits(int stopBits) { - bool reconnect = false; - bool accepted = true; - if(isConnected()) reconnect = true; - disconnect(); - - switch (stopBits) { - case 1: - portSettings.setStopBits(QPortSettings::STOP_1); - break; - case 2: - portSettings.setStopBits(QPortSettings::STOP_2); - break; - default: - // If none of the above cases matches, there must be an error - accepted = false; - break; + // Note 3 is OneAndAHalf stopbits. + bool accepted = false; + if (stopBits != m_stopBits) { + m_stopBits = static_cast(stopBits); + accepted = true; + if (m_port) + accepted = m_port->setStopBits(static_cast(stopBits)); + emit updateLink(this); } - - if(reconnect) connect(); return accepted; } bool SerialLink::setDataBitsType(int dataBits) { - bool reconnect = false; bool accepted = false; - - if (isConnected()) reconnect = true; - disconnect(); - - if (dataBits >= (int)QPortSettings::DB_5 && dataBits <= (int)QPortSettings::DB_8) { - portSettings.setDataBits((QPortSettings::DataBits) dataBits); - - if(reconnect) connect(); + if (dataBits != m_dataBits) { + m_dataBits = static_cast(dataBits); accepted = true; + if (m_port) + accepted = m_port->setDataBits(static_cast(dataBits)); + emit updateLink(this); } - return accepted; } bool SerialLink::setStopBitsType(int stopBits) { - bool reconnect = false; bool accepted = false; - if(isConnected()) reconnect = true; - disconnect(); - - if (stopBits >= (int)QPortSettings::STOP_1 && stopBits <= (int)QPortSettings::STOP_2) { - portSettings.setStopBits((QPortSettings::StopBits) stopBits); - - if(reconnect) connect(); + if (stopBits != m_stopBits) { + m_stopBits = static_cast(stopBits); accepted = true; + if (m_port) + accepted = m_port->setStopBits(static_cast(stopBits)); + emit updateLink(this); } - - if(reconnect) connect(); return accepted; } diff --git a/src/comm/SerialLink.h b/src/comm/SerialLink.h index 6e71b3a7ac76b1e5042ec82d18740e73fefcef7f..2bde8be22bbbfb1fd14c2feb09f36c00fdbd6607 100644 --- a/src/comm/SerialLink.h +++ b/src/comm/SerialLink.h @@ -36,13 +36,12 @@ This file is part of the QGROUNDCONTROL project #include #include #include -#include "qserialport.h" +#include #include #include "SerialLinkInterface.h" -#ifdef _WIN32 -#include "windows.h" -#endif +// convenience type for passing errors +typedef QSerialPort::SerialPortError SerialLinkPortError_t; /** * @brief The SerialLink class provides cross-platform access to serial links. @@ -57,6 +56,7 @@ class SerialLink : public SerialLinkInterface Q_OBJECT //Q_INTERFACES(SerialLinkInterface:LinkInterface) + public: SerialLink(QString portname = "", int baudrate=57600, @@ -69,7 +69,9 @@ public: static const int poll_interval = SERIAL_POLL_INTERVAL; ///< Polling interval, defined in configuration.h /** @brief Get a list of the currently available ports */ - QVector* getCurrentPorts(); + QList getCurrentPorts(); + + void requestReset(); bool isConnected() const; qint64 bytesAvailable(); @@ -108,11 +110,15 @@ public: void writeSettings(); void run(); + void run2(); int getLinkQuality() const; bool isFullDuplex() const; int getId() const; +signals: //[TODO] Refactor to Linkinterface + void updateLink(LinkInterface*); + public slots: bool setPortName(QString portName); bool setBaudRate(int rate); @@ -140,40 +146,41 @@ public slots: bool connect(); bool disconnect(); -protected slots: - void checkForBytes(); + void linkError(SerialLinkPortError_t error); protected: - quint64 bytesRead; - TNX::QSerialPort * port; - TNX::QPortSettings portSettings; -#ifdef _WIN32 - HANDLE winPort; - DCB winPortSettings; -#endif - QString porthandle; - QString name; - int timeout; - int id; - - quint64 bitsSentTotal; - quint64 bitsSentShortTerm; - quint64 bitsSentCurrent; - quint64 bitsSentMax; - quint64 bitsReceivedTotal; - quint64 bitsReceivedShortTerm; - quint64 bitsReceivedCurrent; - quint64 bitsReceivedMax; - quint64 connectionStartTime; - QMutex statisticsMutex; - QMutex dataMutex; - QVector* ports; + quint64 m_bytesRead; + QSerialPort* m_port; + int m_baud; + int m_dataBits; + int m_flowControl; + int m_stopBits; + int m_parity; + QString m_portName; +// QString m_name; + int m_timeout; + int m_id; + + quint64 m_bitsSentTotal; + quint64 m_bitsSentShortTerm; + quint64 m_bitsSentCurrent; + quint64 m_bitsSentMax; + quint64 m_bitsReceivedTotal; + quint64 m_bitsReceivedShortTerm; + quint64 m_bitsReceivedCurrent; + quint64 m_bitsReceivedMax; + quint64 m_connectionStartTime; + QMutex m_statisticsMutex; + QMutex m_dataMutex; + QMutex m_writeMutex; + QList m_ports; private: - volatile bool m_stopp; + volatile bool m_stopp; + volatile bool m_reqReset; QMutex m_stoppMutex; + QByteArray m_transmitBuffer; - void setName(QString name); bool hardwareConnect(); signals: diff --git a/src/comm/SerialLinkInterface.h b/src/comm/SerialLinkInterface.h index 5421027b1a126d49cc664fe406361d3c2261b5d1..3d80f3584a070490b40057c4bd4bed0098da553d 100644 --- a/src/comm/SerialLinkInterface.h +++ b/src/comm/SerialLinkInterface.h @@ -42,12 +42,12 @@ class SerialLinkInterface : public LinkInterface Q_OBJECT public: - virtual QVector* getCurrentPorts() = 0; + virtual QList getCurrentPorts() = 0; virtual QString getPortName() const = 0; virtual int getBaudRate() const = 0; virtual int getDataBits() const = 0; virtual int getStopBits() const = 0; - + virtual void requestReset() = 0; virtual int getBaudRateType() const = 0; virtual int getFlowType() const = 0; virtual int getParityType() const = 0; diff --git a/src/comm/TCPLink.cc b/src/comm/TCPLink.cc new file mode 100644 index 0000000000000000000000000000000000000000..f56ef84d3892df20241db3eeb7fc24d7b87bedf6 --- /dev/null +++ b/src/comm/TCPLink.cc @@ -0,0 +1,325 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2011 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL 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 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +/** + * @file + * @brief Definition of TCP connection (server) for unmanned vehicles + * @author Lorenz Meier + * + */ + +#include +#include +#include +#include +#include +#include "TCPLink.h" +#include "LinkManager.h" +#include "QGC.h" +#include + +TCPLink::TCPLink(QHostAddress hostAddress, quint16 socketPort) : + host(hostAddress), + port(socketPort), + socket(NULL), + socketIsConnected(false) + +{ + // Set unique ID and add link to the list of links + this->id = getNextLinkId(); + this->name = tr("TCP Link (port:%1)").arg(this->port); + emit nameChanged(this->name); + + qDebug() << "TCP Created " << this->name; +} + +TCPLink::~TCPLink() +{ + disconnect(); + this->deleteLater(); +} + +void TCPLink::run() +{ + exec(); +} + +void TCPLink::setAddress(const QString &text) +{ + setAddress(QHostAddress(text)); +} + +void TCPLink::setAddress(QHostAddress host) +{ + bool reconnect(false); + if (this->isConnected()) + { + disconnect(); + reconnect = true; + } + this->host = host; + if (reconnect) + { + connect(); + } +} + +void TCPLink::setPort(int port) +{ + bool reconnect(false); + if(this->isConnected()) + { + disconnect(); + reconnect = true; + } + this->port = port; + this->name = tr("TCP Link (port:%1)").arg(this->port); + emit nameChanged(this->name); + if(reconnect) + { + connect(); + } +} + +#ifdef TCPLINK_READWRITE_DEBUG +void TCPLink::writeDebugBytes(const char *data, qint16 size) +{ + QString bytes; + QString ascii; + for (int i=0; i 31 && data[i] < 127) + { + ascii.append(data[i]); + } + else + { + ascii.append(219); + } + } + qDebug() << "Sent" << size << "bytes to" << host.toString() << ":" << port << "data:"; + qDebug() << bytes; + qDebug() << "ASCII:" << ascii; +} +#endif + +void TCPLink::writeBytes(const char* data, qint64 size) +{ +#ifdef TCPLINK_READWRITE_DEBUG + writeDebugBytes(data, size); +#endif + socket->write(data, size); +} + +/** + * @brief Read a number of bytes from the interface. + * + * @param data Pointer to the data byte array to write the bytes to + * @param maxLength The maximum number of bytes to write + **/ +void TCPLink::readBytes() +{ + qint64 byteCount = socket->bytesAvailable(); + + if (byteCount) + { + QByteArray buffer; + buffer.resize(byteCount); + + socket->read(buffer.data(), buffer.size()); + + emit bytesReceived(this, buffer); + +#ifdef TCPLINK_READWRITE_DEBUG + writeDebugBytes(buffer.data(), buffer.size()); +#endif + } +} + + +/** + * @brief Get the number of bytes to read. + * + * @return The number of bytes to read + **/ +qint64 TCPLink::bytesAvailable() +{ + return socket->bytesAvailable(); +} + +/** + * @brief Disconnect the connection. + * + * @return True if connection has been disconnected, false if connection couldn't be disconnected. + **/ +bool TCPLink::disconnect() +{ + this->quit(); + this->wait(); + + if (socket) + { + socket->disconnect(); + socketIsConnected = false; + delete socket; + socket = NULL; + } + + return true; +} + +/** + * @brief Connect the connection. + * + * @return True if connection has been established, false if connection couldn't be established. + **/ +bool TCPLink::connect() +{ + if(this->isRunning()) + { + this->quit(); + this->wait(); + } + bool connected = this->hardwareConnect(); + start(HighPriority); + return connected; +} + +bool TCPLink::hardwareConnect(void) +{ + socket = new QTcpSocket(); + + socket->connectToHost(host, port); + + QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(readBytes())); + QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError))); + + // Give the socket a second to connect to the other side otherwise error out + if (!socket->waitForConnected(1000)) + { + emit communicationError(getName(), "connection failed"); + return false; + } + + socketIsConnected = true; + connectionStartTime = QGC::groundTimeUsecs()/1000; + emit connected(true); + + return true; +} + +void TCPLink::socketError(QAbstractSocket::SocketError socketError) +{ + emit communicationError(getName(), "Error on socket: " + socket->errorString()); +} + +/** + * @brief Check if connection is active. + * + * @return True if link is connected, false otherwise. + **/ +bool TCPLink::isConnected() const +{ + return socketIsConnected; +} + +int TCPLink::getId() const +{ + return id; +} + +QString TCPLink::getName() const +{ + return name; +} + +void TCPLink::setName(QString name) +{ + this->name = name; + emit nameChanged(this->name); +} + + +qint64 TCPLink::getNominalDataRate() const +{ + return 54000000; // 54 Mbit +} + +qint64 TCPLink::getTotalUpstream() +{ + statisticsMutex.lock(); + qint64 totalUpstream = bitsSentTotal / ((QGC::groundTimeUsecs()/1000 - connectionStartTime) / 1000); + statisticsMutex.unlock(); + return totalUpstream; +} + +qint64 TCPLink::getCurrentUpstream() +{ + return 0; // TODO +} + +qint64 TCPLink::getMaxUpstream() +{ + return 0; // TODO +} + +qint64 TCPLink::getBitsSent() const +{ + return bitsSentTotal; +} + +qint64 TCPLink::getBitsReceived() const +{ + return bitsReceivedTotal; +} + +qint64 TCPLink::getTotalDownstream() +{ + statisticsMutex.lock(); + qint64 totalDownstream = bitsReceivedTotal / ((QGC::groundTimeUsecs()/1000 - connectionStartTime) / 1000); + statisticsMutex.unlock(); + return totalDownstream; +} + +qint64 TCPLink::getCurrentDownstream() +{ + return 0; // TODO +} + +qint64 TCPLink::getMaxDownstream() +{ + return 0; // TODO +} + +bool TCPLink::isFullDuplex() const +{ + return true; +} + +int TCPLink::getLinkQuality() const +{ + /* This feature is not supported with this interface */ + return -1; +} diff --git a/src/comm/TCPLink.h b/src/comm/TCPLink.h new file mode 100644 index 0000000000000000000000000000000000000000..6c6131d6f4d3bdc85d2d190746e55ad1e39e6927 --- /dev/null +++ b/src/comm/TCPLink.h @@ -0,0 +1,131 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2011 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL 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 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +/** + * @file + * @brief TCP connection (server) for unmanned vehicles + * @author Lorenz Meier + * + */ + +#ifndef TCPLINK_H +#define TCPLINK_H + +#include +#include +#include +#include +#include +#include +#include +#include + +//#define TCPLINK_READWRITE_DEBUG // Use to debug data reads/writes + +class TCPLink : public LinkInterface +{ + Q_OBJECT + +public: + TCPLink(QHostAddress hostAddress = QHostAddress::LocalHost, quint16 socketPort = 5760); + ~TCPLink(); + + void requestReset() { } + + bool isConnected() const; + qint64 bytesAvailable(); + int getPort() const { + return port; + } + QHostAddress getHostAddress() const { + return host; + } + + QString getName() const; + int getBaudRate() const; + int getBaudRateType() const; + int getFlowType() const; + int getParityType() const; + int getDataBitsType() const; + int getStopBitsType() const; + + /* Extensive statistics for scientific purposes */ + qint64 getNominalDataRate() const; + qint64 getTotalUpstream(); + qint64 getCurrentUpstream(); + qint64 getMaxUpstream(); + qint64 getTotalDownstream(); + qint64 getCurrentDownstream(); + qint64 getMaxDownstream(); + qint64 getBitsSent() const; + qint64 getBitsReceived() const; + + void run(); + + int getLinkQuality() const; + bool isFullDuplex() const; + int getId() const; + +public slots: + void setAddress(QHostAddress host); + void setPort(int port); + void readBytes(); + void writeBytes(const char* data, qint64 length); + bool connect(); + bool disconnect(); + void socketError(QAbstractSocket::SocketError socketError); + void setAddress(const QString &text); + + +protected: + QString name; + QHostAddress host; + quint16 port; + int id; + QTcpSocket* socket; + bool socketIsConnected; + + quint64 bitsSentTotal; + quint64 bitsSentCurrent; + quint64 bitsSentMax; + quint64 bitsReceivedTotal; + quint64 bitsReceivedCurrent; + quint64 bitsReceivedMax; + quint64 connectionStartTime; + QMutex statisticsMutex; + QMutex dataMutex; + + void setName(QString name); + +private: + bool hardwareConnect(void); +#ifdef TCPLINK_READWRITE_DEBUG + void writeDebugBytes(const char *data, qint16 size); +#endif + +signals: + //Signals are defined by LinkInterface + +}; + +#endif // TCPLINK_H diff --git a/src/comm/UDPLink.cc b/src/comm/UDPLink.cc index 121a3755b80fccc80f24c3345fb2486ece6e9aef..2ce6e75abd51d94857221cc658ba7e779c37fbd4 100644 --- a/src/comm/UDPLink.cc +++ b/src/comm/UDPLink.cc @@ -50,6 +50,7 @@ UDPLink::UDPLink(QHostAddress host, quint16 port) this->name = tr("UDP Link (port:%1)").arg(this->port); emit nameChanged(this->name); // LinkManager::instance()->add(this); + qDebug() << "UDP Created " << name; } UDPLink::~UDPLink() @@ -104,7 +105,7 @@ void UDPLink::setPort(int port) */ void UDPLink::addHost(const QString& host) { - //qDebug() << "UDP:" << "ADDING HOST:" << host; + qDebug() << "UDP:" << "ADDING HOST:" << host; if (host.contains(":")) { //qDebug() << "HOST: " << host.split(":").first(); diff --git a/src/comm/UDPLink.h b/src/comm/UDPLink.h index d51f08c6f6f79759a9d198be84e381d7fa684ea8..4973eaf230dc41624107c65600712302bdda426f 100644 --- a/src/comm/UDPLink.h +++ b/src/comm/UDPLink.h @@ -49,6 +49,8 @@ public: //UDPLink(QHostAddress host = "239.255.76.67", quint16 port = 7667); ~UDPLink(); + void requestReset() { } + bool isConnected() const; qint64 bytesAvailable(); int getPort() const { diff --git a/src/comm/XbeeLink.h b/src/comm/XbeeLink.h index 00dfa857384aede6268ba662a8e187320569d182..4159cf959388b8636f46dfd4c3280eaac56f2c0b 100644 --- a/src/comm/XbeeLink.h +++ b/src/comm/XbeeLink.h @@ -20,8 +20,9 @@ public: ~XbeeLink(); public: // virtual functions from XbeeLinkInterface - QString getPortName() const; - int getBaudRate() const; + QString getPortName() const; + void requestReset() { } + int getBaudRate() const; public slots: // virtual functions from XbeeLinkInterface bool setPortName(QString portName); @@ -71,4 +72,4 @@ private: }; -#endif // _XBEELINK_H_ \ No newline at end of file +#endif // _XBEELINK_H_ diff --git a/src/comm/px4_custom_mode.h b/src/comm/px4_custom_mode.h new file mode 100644 index 0000000000000000000000000000000000000000..9c0c8ae91ea11ffbcd6e1d101da32c12ab207174 --- /dev/null +++ b/src/comm/px4_custom_mode.h @@ -0,0 +1,30 @@ +#ifndef PX4_CUSTOM_MODE_H +#define PX4_CUSTOM_MODE_H + +enum PX4_CUSTOM_MAIN_MODE { + PX4_CUSTOM_MAIN_MODE_MANUAL = 1, + PX4_CUSTOM_MAIN_MODE_SEATBELT, + PX4_CUSTOM_MAIN_MODE_EASY, + PX4_CUSTOM_MAIN_MODE_AUTO, +}; + +enum PX4_CUSTOM_SUB_MODE_AUTO { + PX4_CUSTOM_SUB_MODE_AUTO_READY = 1, + PX4_CUSTOM_SUB_MODE_AUTO_TAKEOFF, + PX4_CUSTOM_SUB_MODE_AUTO_LOITER, + PX4_CUSTOM_SUB_MODE_AUTO_MISSION, + PX4_CUSTOM_SUB_MODE_AUTO_RTL, + PX4_CUSTOM_SUB_MODE_AUTO_LAND, +}; + +union px4_custom_mode { + struct { + uint16_t reserved; + uint8_t main_mode; + uint8_t sub_mode; + }; + uint32_t data; + float data_float; +}; + +#endif // PX4_CUSTOM_MODE_H diff --git a/src/configuration.h b/src/configuration.h index 028bb0a5bedaff9907691c27bbcd4e4ec15c0660..2f0434812374cb13e4f1a93fa99e3ca496a015a9 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -11,14 +11,15 @@ #define WITH_TEXT_TO_SPEECH 1 #define QGC_APPLICATION_NAME "QGroundControl" -#define QGC_APPLICATION_VERSION "v. 1.1.0 (beta)" +#define QGC_APPLICATION_VERSION "v. 2.0.0 (beta)" namespace QGC { const QString APPNAME = "QGROUNDCONTROL"; -const QString COMPANYNAME = "QGROUNDCONTROL"; -const int APPLICATIONVERSION = 110; // 1.1.0 +const QString ORG_NAME = "QGROUNDCONTROL.ORG"; //can be customized by forks to e.g. mycompany.com to maintain separate Settings for customized apps +const QString ORG_DOMAIN = "org.qgroundcontrol";//can be customized by forks +const int APPLICATIONVERSION = 200; // 2.0.0 } #endif // QGC_CONFIGURATION_H diff --git a/src/uas/ArduPilotMegaMAV.cc b/src/uas/ArduPilotMegaMAV.cc index c3c34c5e859e140618e3567c0e2039a351e99895..cb972df4e85558b934199b217f554d91776d3db3 100644 --- a/src/uas/ArduPilotMegaMAV.cc +++ b/src/uas/ArduPilotMegaMAV.cc @@ -53,11 +53,17 @@ ArduPilotMegaMAV::ArduPilotMegaMAV(MAVLinkProtocol* mavlink, int id) : void ArduPilotMegaMAV::sendTxRequests() { enableExtendedSystemStatusTransmission(2); + QGC::SLEEP::msleep(250); enablePositionTransmission(3); + QGC::SLEEP::msleep(250); enableExtra1Transmission(10); + QGC::SLEEP::msleep(250); enableExtra2Transmission(10); + QGC::SLEEP::msleep(250); enableExtra3Transmission(2); + QGC::SLEEP::msleep(250); enableRawSensorDataTransmission(2); + QGC::SLEEP::msleep(250); enableRCChannelDataTransmission(2); } diff --git a/src/uas/QGCUASParamManager.cc b/src/uas/QGCUASParamManager.cc index 6e137b6329d77c5c902c3e89f9e8550649e94042..5a3442b5ab22f799c77d1a4800a3b70eeaa8264c 100644 --- a/src/uas/QGCUASParamManager.cc +++ b/src/uas/QGCUASParamManager.cc @@ -1,26 +1,219 @@ #include "QGCUASParamManager.h" + +#include +#include +#include + #include "UASInterface.h" +#include "UASParameterCommsMgr.h" + +QGCUASParamManager::QGCUASParamManager(QObject *parent) : + QObject(parent), + mav(NULL), + paramDataModel(this), + paramCommsMgr(NULL) +{ + + +} + +QGCUASParamManager* QGCUASParamManager::initWithUAS(UASInterface* uas) +{ + mav = uas; + + // Load default values and tooltips for data model + loadParamMetaInfoCSV(); + + paramDataModel.setUASID(mav->getUASID()); + paramCommsMgr = new UASParameterCommsMgr(this); + paramCommsMgr->initWithUAS(uas); + + connectToModelAndComms(); + + return this; +} + +void QGCUASParamManager::connectToModelAndComms() +{ + // Pass along comms mgr status msgs + connect(paramCommsMgr, SIGNAL(parameterStatusMsgUpdated(QString,int)), + this, SIGNAL(parameterStatusMsgUpdated(QString,int))); + + connect(paramCommsMgr, SIGNAL(parameterListUpToDate()), + this, SIGNAL(parameterListUpToDate())); + + // Pass along data model updates + connect(¶mDataModel, SIGNAL(parameterUpdated(int, QString , QVariant )), + this, SIGNAL(parameterUpdated(int, QString , QVariant ))); + + connect(¶mDataModel, SIGNAL(pendingParamUpdate(int , const QString& , QVariant , bool )), + this, SIGNAL(pendingParamUpdate(int , const QString& , QVariant , bool ))); + + +} + + +void QGCUASParamManager::clearAllPendingParams() +{ + paramDataModel.clearAllPendingParams(); + emit parameterStatusMsgUpdated(tr("Cleared all pending params"), UASParameterCommsMgr::ParamCommsStatusLevel_OK); + +} + + +int QGCUASParamManager::getDefaultComponentId() +{ + return paramDataModel.getDefaultComponentId(); +} + +QList QGCUASParamManager::getComponentForParam(const QString& parameter) const +{ + return paramDataModel.getComponentForOnboardParam(parameter); +} + + +bool QGCUASParamManager::getParameterValue(int component, const QString& parameter, QVariant& value) const +{ + return paramDataModel.getOnboardParamValue(component,parameter,value); +} + -QGCUASParamManager::QGCUASParamManager(UASInterface* uas, QWidget *parent) : - QWidget(parent), - mav(uas), - transmissionListMode(false), - transmissionActive(false), - transmissionTimeout(0), - retransmissionTimeout(350), - rewriteTimeout(500), - retransmissionBurstRequestSize(5) +void QGCUASParamManager::requestParameterUpdate(int component, const QString& parameter) { - uas->setParamManager(this); + if (mav) { + paramCommsMgr->requestParameterUpdate(component,parameter); + } } + /** - * The .. signal is emitted + * Send a request to deliver the list of onboard parameters + * to the MAV. */ -void QGCUASParamManager::requestParameterListUpdate(int component) +void QGCUASParamManager::requestParameterList() +{ + if (mav) { + emit parameterStatusMsgUpdated(tr("Requested param list.. waiting"), UASParameterCommsMgr::ParamCommsStatusLevel_OK); + paramCommsMgr->requestParameterList(); + } +} + +void QGCUASParamManager::requestParameterListIfEmpty() { - Q_UNUSED(component); + if (mav) { + int totalOnboard = paramDataModel.countOnboardParams(); + if (totalOnboard < 2) { //TODO arbitrary constant, maybe 0 is OK? + requestParameterList(); + } + } +} + + +void QGCUASParamManager::setParamDescriptions(const QMap& paramInfo) { + paramDataModel.setParamDescriptions(paramInfo); } +void QGCUASParamManager::setParameter(int compId, QString paramName, QVariant value) +{ + if ((0 == compId) || (-1 == compId)) { + //attempt to get an actual component ID + compId = paramDataModel.getDefaultComponentId(); + } + paramDataModel.updatePendingParamWithValue(compId,paramName,value); +} + +void QGCUASParamManager::sendPendingParameters(bool persistAfterSend, bool forceSend) +{ + paramCommsMgr->sendPendingParameters(persistAfterSend, forceSend); +} + + + + +void QGCUASParamManager::setPendingParam(int compId, const QString& paramName, const QVariant& value, bool forceSend) +{ + if ((0 == compId) || (-1 == compId)) { + //attempt to get an actual component ID + compId = paramDataModel.getDefaultComponentId(); + } + paramDataModel.updatePendingParamWithValue(compId,paramName,value, forceSend); +} + + + +void QGCUASParamManager::loadParamMetaInfoCSV() +{ + // Load default values and tooltips + QString autopilot(mav->getAutopilotTypeName()); + + QDir appDir = QApplication::applicationDirPath(); + appDir.cd("files"); + QString fileName = QString("%1/%2/parameter_tooltips/tooltips.txt").arg(appDir.canonicalPath()).arg(autopilot.toLower()); + QFile paramMetaFile(fileName); + + qDebug() << "loadParamMetaInfoCSV for autopilot: " << autopilot << " from file: " << fileName; + + if (!paramMetaFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning() << "loadParamMetaInfoCSV couldn't open:" << fileName; + return; + } + + QTextStream in(¶mMetaFile); + paramDataModel.loadParamMetaInfoFromStream(in); + paramMetaFile.close(); + +} + + +UASInterface* QGCUASParamManager::getUAS() +{ + return mav; +} + +UASParameterDataModel* QGCUASParamManager::dataModel() +{ + return ¶mDataModel; +} + + + +void QGCUASParamManager::writeOnboardParamsToStream(QTextStream &stream, const QString& uasName) +{ + paramDataModel.writeOnboardParamsToStream(stream,uasName); +} + +void QGCUASParamManager::readPendingParamsFromStream(QTextStream &stream) +{ + paramDataModel.readUpdateParamsFromStream(stream); +} + + + +void QGCUASParamManager::copyVolatileParamsToPersistent() +{ + int changedParamCount = paramDataModel.countPendingParams(); + + if (changedParamCount > 0) { + QMessageBox msgBox; + msgBox.setText(tr("There are locally changed parameters. Please transmit them first () or update them with the onboard values () before storing onboard from RAM to ROM.")); + msgBox.exec(); + } + else { + paramCommsMgr->writeParamsToPersistentStorage(); + } +} + + +void QGCUASParamManager::copyPersistentParamsToVolatile() +{ + if (mav) { + mav->readParametersFromStorage(); //TODO use comms mgr instead? + } +} + + +void QGCUASParamManager::requestRcCalibrationParamsUpdate() { + paramCommsMgr->requestRcCalibrationParamsUpdate(); +} diff --git a/src/uas/QGCUASParamManager.h b/src/uas/QGCUASParamManager.h index 69dee9eb444e6253cee3f3cc80b718b6ea1c938c..4fd05aa3411298d112be7931ac7c6a3af6bd89a5 100644 --- a/src/uas/QGCUASParamManager.h +++ b/src/uas/QGCUASParamManager.h @@ -6,76 +6,125 @@ #include #include +#include "UASParameterDataModel.h" + +//forward declarations +class QTextStream; class UASInterface; +class UASParameterCommsMgr; -class QGCUASParamManager : public QWidget +class QGCUASParamManager : public QObject { Q_OBJECT public: - QGCUASParamManager(UASInterface* uas, QWidget *parent = 0); + QGCUASParamManager(QObject* parent = 0); + QGCUASParamManager* initWithUAS(UASInterface* uas); + + /** @brief Get the known, confirmed value of a parameter */ + virtual bool getParameterValue(int component, const QString& parameter, QVariant& value) const; + + /** @brief determine which component is the root component for the UAS and return its ID or 0 if unknown */ + virtual int getDefaultComponentId(); + + /** + * @brief Get a list of all component IDs using this parameter name + * @param parameter The string encoding the parameter name + * @return A list with all components using this parameter name. Can be empty. + */ + virtual QList getComponentForParam(const QString& parameter) const; - QList getParameterNames(int component) const { - return parameters.value(component)->keys(); + /** @brief Provide tooltips / user-visible descriptions for parameters */ + virtual void setParamDescriptions(const QMap& paramDescs); + + /** + * @brief Count the pending parameters in the current transmission + * @return The number of pending parameters + */ + virtual int countPendingParams() { + return paramDataModel.countPendingParams(); } - QList getParameterValues(int component) const { - return parameters.value(component)->values(); + + /** + * @brief Count the number of onboard parameters + * @return The number of onboard parameters + */ + virtual int countOnboardParams() { + return paramDataModel.countOnboardParams(); } - bool getParameterValue(int component, const QString& parameter, QVariant& value) const { - if (!parameters.contains(component)) - { - return false; - } - if (!parameters.value(component)->contains(parameter)) - { - return false; - } + /** @brief Get the UAS of this widget + * @return The MAV of this mgr. Unless the MAV object has been destroyed, this is never null. + */ + UASInterface* getUAS(); - value = parameters.value(component)->value(parameter); + /** @return The data model managed by this class */ + virtual UASParameterDataModel* dataModel(); - return true; - } +protected: + + /** @brief Load parameter meta information from appropriate CSV file */ + virtual void loadParamMetaInfoCSV(); - virtual bool isParamMinKnown(const QString& param) = 0; - virtual bool isParamMaxKnown(const QString& param) = 0; - virtual bool isParamDefaultKnown(const QString& param) = 0; - virtual double getParamMin(const QString& param) = 0; - virtual double getParamMax(const QString& param) = 0; - virtual double getParamDefault(const QString& param) = 0; - virtual QString getParamInfo(const QString& param) = 0; - virtual void setParamInfo(const QMap& param) = 0; + void connectToModelAndComms(); - /** @brief Request an update for the parameter list */ - void requestParameterListUpdate(int component = 0); - /** @brief Request an update for this specific parameter */ - virtual void requestParameterUpdate(int component, const QString& parameter) = 0; signals: - void parameterChanged(int component, QString parameter, QVariant value); - void parameterChanged(int component, int parameterIndex, QVariant value); - void parameterListUpToDate(int component); + + /** @brief We updated the parameter status message */ + void parameterStatusMsgUpdated(QString msg, int level); + /** @brief We have received a complete list of all parameters onboard the MAV */ + void parameterListUpToDate(); + + /** @brief We've received an update of a parameter's value */ + void parameterUpdated(int compId, QString paramName, QVariant value); + + /** @brief Notifies listeners that a param was added to or removed from the pending list */ + void pendingParamUpdate(int compId, const QString& paramName, QVariant value, bool isPending); + + public slots: - /** @brief Write one parameter to the MAV */ - virtual void setParameter(int component, QString parameterName, QVariant value) = 0; + /** @brief Send one parameter to the MAV: changes value in transient memory of MAV */ + virtual void setParameter(int component, QString parameterName, QVariant value); + + /** @brief Send all pending parameters to the MAV, for storage in transient (RAM) memory + * @param persistAfterSend If true, all parameters will be written to persistent storage as well + */ + virtual void sendPendingParameters(bool persistAfterSend = false, bool forceSend = false); + + /** @brief Request list of parameters from MAV */ - virtual void requestParameterList() = 0; + virtual void requestParameterList(); + + /** @brief Request a list of params onboard the MAV if the onboard param list we have is empty */ + virtual void requestParameterListIfEmpty(); + + /** @brief queue a pending parameter for sending to the MAV */ + virtual void setPendingParam(int componentId, const QString& key, const QVariant& value, bool forceSend = false); + + /** @brief remove all params from the pending list */ + virtual void clearAllPendingParams(); + + /** @brief Request a single parameter by name from the MAV */ + virtual void requestParameterUpdate(int component, const QString& parameter); + + + virtual void writeOnboardParamsToStream(QTextStream &stream, const QString& uasName); + virtual void readPendingParamsFromStream(QTextStream &stream); + + virtual void requestRcCalibrationParamsUpdate(); + + /** @brief Copy the current parameters in volatile RAM to persistent storage (EEPROM/HDD) */ + virtual void copyVolatileParamsToPersistent(); + /** @brief Copy the parameters from persistent storage to volatile RAM */ + virtual void copyPersistentParamsToVolatile(); protected: - UASInterface* mav; ///< The MAV this widget is controlling - QMap* > changedValues; ///< Changed values - QMap* > parameters; ///< All parameters - QVector received; ///< Successfully received parameters - QMap* > transmissionMissingPackets; ///< Missing packets - QMap* > transmissionMissingWriteAckPackets; ///< Missing write ACK packets - bool transmissionListMode; ///< Currently requesting list - QMap transmissionListSizeKnown; ///< List size initialized? - bool transmissionActive; ///< Missing packets, working on list? - quint64 transmissionTimeout; ///< Timeout - QTimer retransmissionTimer; ///< Timer handling parameter retransmission - int retransmissionTimeout; ///< Retransmission request timeout, in milliseconds - int rewriteTimeout; ///< Write request timeout, in milliseconds - int retransmissionBurstRequestSize; ///< Number of packets requested for retransmission per burst + + // Parameter data model + UASInterface* mav; ///< The MAV this manager is controlling + UASParameterDataModel paramDataModel;///< Shared data model of parameters + UASParameterCommsMgr* paramCommsMgr; ///< Shared comms mgr for parameters }; diff --git a/src/uas/UAS.cc b/src/uas/UAS.cc index 142e53b20f0ad443f67dcb71dcb42bc02d47f673..8d5be0668ecbeba3ae3fcf56f13b41f0b20552bc 100644 --- a/src/uas/UAS.cc +++ b/src/uas/UAS.cc @@ -26,7 +26,9 @@ #include "QGCMAVLink.h" #include "LinkManager.h" #include "SerialLink.h" +#include "UASParameterCommsMgr.h" #include +#include #ifdef QGC_PROTOBUF_ENABLED #include @@ -56,9 +58,9 @@ UAS::UAS(MAVLinkProtocol* protocol, int id) : UASInterface(), airframe(QGC_AIRFRAME_GENERIC), autopilot(-1), systemIsArmed(false), - mode(-1), + base_mode(0), + custom_mode(0), // custom_mode not initialized - navMode(-1), status(-1), // shortModeText not initialized // shortStateText not initialized @@ -83,7 +85,7 @@ UAS::UAS(MAVLinkProtocol* protocol, int id) : UASInterface(), currentVoltage(12.6f), lpVoltage(12.0f), currentCurrent(0.4f), - batteryRemainingEstimateEnabled(true), + batteryRemainingEstimateEnabled(false), // chargeLevel not initialized // timeRemaining not initialized lowBattAlarm(false), @@ -114,8 +116,8 @@ UAS::UAS(MAVLinkProtocol* protocol, int id) : UASInterface(), nedPosGlobalOffset(0,0,0), nedAttGlobalOffset(0,0,0), - waypointManager(this), + paramMgr(this), #if defined(QGC_PROTOBUF_ENABLED) && defined(QGC_USE_PIXHAWK_MESSAGES) receivedOverlayTimestamp(0.0), @@ -130,8 +132,6 @@ UAS::UAS(MAVLinkProtocol* protocol, int id) : UASInterface(), lastAttitude(0), paramsOnceRequested(false), - paramManager(NULL), - simulation(0), // The protected members. @@ -143,7 +143,8 @@ UAS::UAS(MAVLinkProtocol* protocol, int id) : UASInterface(), sensorHil(false), lastSendTimeGPS(0), lastSendTimeSensors(0), - blockHomePositionChanges(false) + blockHomePositionChanges(false), + receivedMode(false) { for (unsigned int i = 0; i<255;++i) { @@ -151,6 +152,7 @@ UAS::UAS(MAVLinkProtocol* protocol, int id) : UASInterface(), componentMulti[i] = false; } + // Store a list of available actions for this UAS. // Basically everything exposted as a SLOT with no return value or arguments. @@ -210,11 +212,13 @@ UAS::UAS(MAVLinkProtocol* protocol, int id) : UASInterface(), actions.append(newAction); color = UASInterface::getNextColor(); - setBatterySpecs(QString("9V,9.5V,12.6V")); + setBatterySpecs(QString("")); connect(statusTimeout, SIGNAL(timeout()), this, SLOT(updateState())); connect(this, SIGNAL(systemSpecsChanged(int)), this, SLOT(writeSettings())); statusTimeout->start(500); readSettings(); + //need to init paramMgr after readSettings have been loaded, to properly set autopilot and so forth + paramMgr.initWithUAS(this); // Initial signals emit disarmed(); emit armingChanged(false); @@ -306,6 +310,7 @@ void UAS::updateState() if (!connectionLost && (heartbeatInterval > timeoutIntervalHeartbeat)) { connectionLost = true; + receivedMode = false; QString audiostring = QString("Link lost to system %1").arg(this->getUASID()); GAudioOutput::instance()->say(audiostring.toLower()); } @@ -335,7 +340,7 @@ void UAS::updateState() } else { - if (((mode&MAV_MODE_FLAG_DECODE_POSITION_AUTO) || (mode&MAV_MODE_FLAG_DECODE_POSITION_GUIDED)) && positionLock) + if (((base_mode & MAV_MODE_FLAG_DECODE_POSITION_AUTO) || (base_mode & MAV_MODE_FLAG_DECODE_POSITION_GUIDED)) && positionLock) { GAudioOutput::instance()->notifyNegative(); } @@ -566,24 +571,19 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message) stateAudio = uasState; } - if (this->mode != static_cast(state.base_mode)) + if (this->base_mode != state.base_mode || this->custom_mode != state.custom_mode) { modechanged = true; - this->mode = static_cast(state.base_mode); - shortModeText = getShortModeTextFor(this->mode); + receivedMode = true; + this->base_mode = state.base_mode; + this->custom_mode = state.custom_mode; + shortModeText = getShortModeTextFor(this->base_mode, this->custom_mode, this->autopilot); emit modeChanged(this->getUASID(), shortModeText, ""); modeAudio = " is now in " + audiomodeText; } - if (navMode != state.custom_mode) - { - emit navModeChanged(uasId, state.custom_mode, getNavModeText(state.custom_mode)); - navMode = state.custom_mode; - //navModeAudio = tr(" changed nav mode to ") + tr("FIXME"); - } - // AUDIO if (modechanged && statechanged) { @@ -593,7 +593,7 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message) else if (modechanged || statechanged) { // Output the one message - audiostring += modeAudio + stateAudio + navModeAudio; + audiostring += modeAudio + stateAudio; } if (statechanged && ((int)state.system_status == (int)MAV_STATE_CRITICAL || state.system_status == (int)MAV_STATE_EMERGENCY)) @@ -1026,147 +1026,19 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message) break; case MAVLINK_MSG_ID_PARAM_VALUE: { - mavlink_param_value_t value; - mavlink_msg_param_value_decode(&message, &value); - QByteArray bytes(value.param_id, MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN); + mavlink_param_value_t rawValue; + mavlink_msg_param_value_decode(&message, &rawValue); + QByteArray bytes(rawValue.param_id, MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN); // Construct a string stopping at the first NUL (0) character, else copy the whole // byte array (max MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN, so safe) QString parameterName(bytes); - int component = message.compid; - mavlink_param_union_t val; - val.param_float = value.param_value; - val.type = value.param_type; + mavlink_param_union_t paramVal; + paramVal.param_float = rawValue.param_value; + paramVal.type = rawValue.param_type; - // Insert component if necessary - if (!parameters.contains(component)) - { - parameters.insert(component, new QMap()); - } + processParamValueMsg(message, parameterName,rawValue,paramVal); - // Insert parameter into registry - if (parameters.value(component)->contains(parameterName)) parameters.value(component)->remove(parameterName); - - // Insert with correct type - // TODO: This is a hack for MAV_AUTOPILOT_ARDUPILOTMEGA until the new version of MAVLink and a fix for their param handling. - switch (value.param_type) - { - case MAV_PARAM_TYPE_REAL32: - { - // Variant - QVariant param; - if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) - { - param = QVariant(val.param_float); - } - else - { - param = QVariant(val.param_float); - } - parameters.value(component)->insert(parameterName, param); - // Emit change - emit parameterChanged(uasId, message.compid, parameterName, param); - emit parameterChanged(uasId, message.compid, value.param_count, value.param_index, parameterName, param); -// qDebug() << "RECEIVED PARAM:" << param; - } - break; - case MAV_PARAM_TYPE_UINT8: - { - // Variant - QVariant param; - if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) - { - param = QVariant(QChar((unsigned char)val.param_float)); - } - else - { - param = QVariant(QChar((unsigned char)val.param_uint8)); - } - parameters.value(component)->insert(parameterName, param); - // Emit change - emit parameterChanged(uasId, message.compid, parameterName, param); - emit parameterChanged(uasId, message.compid, value.param_count, value.param_index, parameterName, param); - //qDebug() << "RECEIVED PARAM:" << param; - } - break; - case MAV_PARAM_TYPE_INT8: - { - // Variant - QVariant param; - if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) - { - param = QVariant(QChar((char)val.param_float)); - } - else - { - param = QVariant(QChar((char)val.param_int8)); - } - parameters.value(component)->insert(parameterName, param); - // Emit change - emit parameterChanged(uasId, message.compid, parameterName, param); - emit parameterChanged(uasId, message.compid, value.param_count, value.param_index, parameterName, param); - //qDebug() << "RECEIVED PARAM:" << param; - } - break; - case MAV_PARAM_TYPE_INT16: - { - // Variant - QVariant param; - if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) - { - param = QVariant((short)val.param_float); - } - else - { - param = QVariant(val.param_int16); - } - parameters.value(component)->insert(parameterName, param); - // Emit change - emit parameterChanged(uasId, message.compid, parameterName, param); - emit parameterChanged(uasId, message.compid, value.param_count, value.param_index, parameterName, param); - //qDebug() << "RECEIVED PARAM:" << param; - } - break; - case MAV_PARAM_TYPE_UINT32: - { - // Variant - QVariant param; - if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) - { - param = QVariant((unsigned int)val.param_float); - } - else - { - param = QVariant(val.param_uint32); - } - parameters.value(component)->insert(parameterName, param); - // Emit change - emit parameterChanged(uasId, message.compid, parameterName, param); - emit parameterChanged(uasId, message.compid, value.param_count, value.param_index, parameterName, param); - } - break; - case MAV_PARAM_TYPE_INT32: - { - // Variant - QVariant param; - if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) - { - param = QVariant((int)val.param_float); - } - else - { - param = QVariant(val.param_int32); - } - parameters.value(component)->insert(parameterName, param); - // Emit change - emit parameterChanged(uasId, message.compid, parameterName, param); - emit parameterChanged(uasId, message.compid, value.param_count, value.param_index, parameterName, param); -// qDebug() << "RECEIVED PARAM:" << param; - } - break; - default: - qCritical() << "INVALID DATA TYPE USED AS PARAMETER VALUE: " << value.param_type; - } //switch (value.param_type) - } + } break; case MAVLINK_MSG_ID_COMMAND_ACK: { @@ -1326,6 +1198,7 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message) } } break; +#if 0 case MAVLINK_MSG_ID_SERVO_OUTPUT_RAW: { mavlink_servo_output_raw_t raw; @@ -1340,6 +1213,7 @@ void UAS::receiveMessage(LinkInterface* link, mavlink_message_t message) } } break; +#endif #ifdef MAVLINK_ENABLED_PIXHAWK case MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE: { @@ -1651,9 +1525,13 @@ void UAS::setHomePosition(double lat, double lon, double alt) if (blockHomePositionChanges) return; + QString uasName = (getUASName() == "")? + tr("UAS") + QString::number(getUASID()) + : getUASName(); + QMessageBox msgBox; msgBox.setIcon(QMessageBox::Warning); - msgBox.setText(tr("Set a new home position for vehicle %s").arg(getUASName())); + msgBox.setText(tr("Set a new home position for vehicle %1").arg(uasName)); msgBox.setInformativeText("Do you want to set a new origin? Waypoints defined in the local frame will be shifted in their physical location"); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Cancel); @@ -1946,27 +1824,51 @@ QList UAS::getComponentIds() } /** -* @param mode that UAS is to be set to. +* @param newBaseMode that UAS is to be set to. +* @param newCustomMode that UAS is to be set to. */ -void UAS::setMode(int mode) +void UAS::setMode(uint8_t newBaseMode, uint32_t newCustomMode) { - //this->mode = mode; //no call assignament, update receive message from UAS + if (receivedMode) + { + //this->mode = mode; //no call assignament, update receive message from UAS - // Strip armed / disarmed call, this is not relevant for setting the mode - uint8_t newMode = mode; - newMode &= (~(uint8_t)MAV_MODE_FLAG_SAFETY_ARMED); - // Now set current state (request no change) - newMode |= (uint8_t)(this->mode) & (uint8_t)(MAV_MODE_FLAG_SAFETY_ARMED); + // Strip armed / disarmed call for safety reasons, this is not relevant for setting the mode + newBaseMode &= ~MAV_MODE_FLAG_SAFETY_ARMED; + // Now set current state (request no change) + newBaseMode |= this->base_mode & MAV_MODE_FLAG_SAFETY_ARMED; - // Strip HIL part, replace it with current system state - newMode &= (~(uint8_t)MAV_MODE_FLAG_HIL_ENABLED); - // Now set current state (request no change) - newMode |= (uint8_t)(this->mode) & (uint8_t)(MAV_MODE_FLAG_HIL_ENABLED); +// // Strip HIL part, replace it with current system state +// newBaseMode &= (~MAV_MODE_FLAG_HIL_ENABLED); +// // Now set current state (request no change) +// newBaseMode |= this->base_mode & MAV_MODE_FLAG_HIL_ENABLED; - mavlink_message_t msg; - mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, (uint8_t)uasId, newMode, (uint16_t)navMode); - sendMessage(msg); - qDebug() << "SENDING REQUEST TO SET MODE TO SYSTEM" << uasId << ", REQUEST TO SET MODE " << newMode; + setModeArm(newBaseMode, newCustomMode); + } + else + { + qDebug() << "WARNING: setMode called before base_mode bitmask was received from UAS, new mode was not sent to system"; + } +} + +/** +* @param newBaseMode that UAS is to be set to. +* @param newCustomMode that UAS is to be set to. +*/ +void UAS::setModeArm(uint8_t newBaseMode, uint32_t newCustomMode) +{ + if (receivedMode) + { + mavlink_message_t msg; + mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, (uint8_t)uasId, newBaseMode, newCustomMode); + qDebug() << "mavlink_msg_set_mode_pack 1"; + sendMessage(msg); + qDebug() << "SENDING REQUEST TO SET MODE TO SYSTEM" << uasId << ", MODE " << newBaseMode << " " << newCustomMode; + } + else + { + qDebug() << "WARNING: setModeArm called before base_mode bitmask was received from UAS, new mode was not sent to system"; + } } /** @@ -1975,13 +1877,23 @@ void UAS::setMode(int mode) */ void UAS::sendMessage(mavlink_message_t message) { - if (!LinkManager::instance()) return; + if (!LinkManager::instance()) + { + qWarning() << "LINKMANAGER NOT AVAILABLE!"; + return; + } + + if (links->count() < 1) { + qDebug() << "NO LINK AVAILABLE TO SEND!"; + } + // Emit message on all links that are currently connected foreach (LinkInterface* link, *links) { if (LinkManager::instance()->getLinks().contains(link)) { - sendMessage(link, message); + if (link->isConnected()) + sendMessage(link, message); } else { @@ -2011,8 +1923,10 @@ void UAS::forwardMessage(mavlink_message_t message) { if(serial != links->at(i)) { - qDebug()<<"Antenna tracking: Forwarding Over link: "<getName()<<" "<isConnected()) { + qDebug()<<"Antenna tracking: Forwarding Over link: "<getName()<<" "<getSystemId(), mavlink->getComponentId(), link->getId(), message.len, messageKeys[message.msgid]); + // If link is connected if (link->isConnected()) { // Send the portion of the buffer now occupied by the message link->writeBytes((const char*)buffer, len); } + else + { + qDebug() << "LINK NOT CONNECTED, NOT SENDING!"; + } } /** @@ -2050,35 +1969,6 @@ float UAS::filterVoltage(float value) const return lpVoltage * 0.7f + value * 0.3f; } -/** -* The mode can be preflight or unknown. -* @Return the mode of the autopilot -*/ -QString UAS::getNavModeText(int mode) -{ - if (autopilot == MAV_AUTOPILOT_PIXHAWK) - { - switch (mode) - { - case 0: - return QString("PREFLIGHT"); - break; - default: - return QString("UNKNOWN"); - } - } - else if (autopilot == MAV_AUTOPILOT_ARDUPILOTMEGA) - { - return QString("UNKNOWN"); - } - else if (autopilot == MAV_AUTOPILOT_OPENPILOT) - { - return QString("UNKNOWN"); - } - // If nothing matches, return unknown - return QString("UNKNOWN"); -} - /** * Get the status of the code and a description of the status. * Status can be unitialized, booting up, calibrating sensors, active @@ -2232,7 +2122,9 @@ void UAS::requestParameters() mavlink_message_t msg; mavlink_msg_param_request_list_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), MAV_COMP_ID_ALL); sendMessage(msg); - qDebug() << __FILE__ << __LINE__ << "LOADING PARAM LIST"; + + QDateTime time = QDateTime::currentDateTime(); + qDebug() << __FILE__ << ":" << __LINE__ << time.toString() << "LOADING PARAM LIST"; } void UAS::writeParametersToStorage() @@ -2506,9 +2398,9 @@ void UAS::enableExtra3Transmission(int rate) * @param component The component to set the parameter * @param id Name of the parameter */ -void UAS::setParameter(const int component, const QString& id, const QVariant& value) +void UAS::setParameter(const int compId, const QString& paramId, const QVariant& value) { - if (!id.isNull()) + if (!paramId.isNull()) { mavlink_message_t msg; mavlink_param_set_t p; @@ -2518,7 +2410,7 @@ void UAS::setParameter(const int component, const QString& id, const QVariant& v // TODO: This is a hack for MAV_AUTOPILOT_ARDUPILOTMEGA until the new version of MAVLink and a fix for their param handling. if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { - switch (value.type()) + switch ((int)value.type()) { case QVariant::Char: union_value.param_float = (unsigned char)value.toChar().toAscii(); @@ -2543,7 +2435,7 @@ void UAS::setParameter(const int component, const QString& id, const QVariant& v } else { - switch (value.type()) + switch ((int)value.type()) { case QVariant::Char: union_value.param_int8 = (unsigned char)value.toChar().toAscii(); @@ -2569,7 +2461,7 @@ void UAS::setParameter(const int component, const QString& id, const QVariant& v p.param_value = union_value.param_float; p.target_system = (uint8_t)uasId; - p.target_component = (uint8_t)component; + p.target_component = (uint8_t)compId; //qDebug() << "SENT PARAM:" << value; @@ -2577,9 +2469,9 @@ void UAS::setParameter(const int component, const QString& id, const QVariant& v for (unsigned int i = 0; i < sizeof(p.param_id); i++) { // String characters - if ((int)i < id.length()) + if ((int)i < paramId.length()) { - p.param_id[i] = id.toAscii()[i]; + p.param_id[i] = paramId.toAscii()[i]; } else { @@ -2587,11 +2479,130 @@ void UAS::setParameter(const int component, const QString& id, const QVariant& v p.param_id[i] = 0; } } - mavlink_msg_param_set_encode(mavlink->getSystemId(), mavlink->getComponentId(), &msg, &p); + mavlink_msg_param_set_encode(mavlink->getSystemId(), compId, &msg, &p); sendMessage(msg); } } + + + +//TODO update this to use the parameter manager / param data model instead +void UAS::processParamValueMsg(mavlink_message_t& msg, const QString& paramName, const mavlink_param_value_t& rawValue, mavlink_param_union_t& paramValue) +{ + int compId = msg.compid; + + // Insert component if necessary + if (!parameters.contains(compId)) { + parameters.insert(compId, new QMap()); + } + + // Insert parameter into registry + if (parameters.value(compId)->contains(paramName)) { + parameters.value(compId)->remove(paramName); + } + + QVariant param; + + // Insert with correct type + // TODO: This is a hack for MAV_AUTOPILOT_ARDUPILOTMEGA until the new version of MAVLink and a fix for their param handling. + switch (rawValue.param_type) + { + case MAV_PARAM_TYPE_REAL32: + { + if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { + param = QVariant(paramValue.param_float); + } + else { + param = QVariant(paramValue.param_float); + } + parameters.value(compId)->insert(paramName, param); + // Emit change + emit parameterChanged(uasId, compId, paramName, param); + emit parameterChanged(uasId, compId, rawValue.param_count, rawValue.param_index, paramName, param); +// qDebug() << "RECEIVED PARAM:" << param; + } + break; + case MAV_PARAM_TYPE_UINT8: + { + if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { + param = QVariant(QChar((unsigned char)paramValue.param_float)); + } + else { + param = QVariant(QChar((unsigned char)paramValue.param_uint8)); + } + parameters.value(compId)->insert(paramName, param); + // Emit change + emit parameterChanged(uasId, compId, paramName, param); + emit parameterChanged(uasId, compId, rawValue.param_count, rawValue.param_index, paramName, param); + //qDebug() << "RECEIVED PARAM:" << param; + } + break; + case MAV_PARAM_TYPE_INT8: + { + if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { + param = QVariant(QChar((char)paramValue.param_float)); + } + else { + param = QVariant(QChar((char)paramValue.param_int8)); + } + parameters.value(compId)->insert(paramName, param); + // Emit change + emit parameterChanged(uasId, compId, paramName, param); + emit parameterChanged(uasId, compId, rawValue.param_count, rawValue.param_index, paramName, param); + //qDebug() << "RECEIVED PARAM:" << param; + } + break; + case MAV_PARAM_TYPE_INT16: + { + if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { + param = QVariant((short)paramValue.param_float); + } + else { + param = QVariant(paramValue.param_int16); + } + parameters.value(compId)->insert(paramName, param); + // Emit change + emit parameterChanged(uasId, compId, paramName, param); + emit parameterChanged(uasId, compId, rawValue.param_count, rawValue.param_index, paramName, param); + //qDebug() << "RECEIVED PARAM:" << param; + } + break; + case MAV_PARAM_TYPE_UINT32: + { + if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { + param = QVariant((unsigned int)paramValue.param_float); + } + else { + param = QVariant(paramValue.param_uint32); + } + parameters.value(compId)->insert(paramName, param); + // Emit change + emit parameterChanged(uasId, compId, paramName, param); + emit parameterChanged(uasId, compId, rawValue.param_count, rawValue.param_index, paramName, param); + } + break; + case MAV_PARAM_TYPE_INT32: + { + if (getAutopilotType() == MAV_AUTOPILOT_ARDUPILOTMEGA) { + param = QVariant((int)paramValue.param_float); + } + else { + param = QVariant(paramValue.param_int32); + } + parameters.value(compId)->insert(paramName, param); + // Emit change + emit parameterChanged(uasId, compId, paramName, param); + emit parameterChanged(uasId, compId, rawValue.param_count, rawValue.param_index, paramName, param); +// qDebug() << "RECEIVED PARAM:" << param; + } + break; + default: + qCritical() << "INVALID DATA TYPE USED AS PARAMETER VALUE: " << rawValue.param_type; + } //switch (value.param_type) + +} + /** * Request parameter, use parameter name to request it. */ @@ -2629,7 +2640,7 @@ void UAS::requestParameter(int component, const QString& parameter) read.target_component = component; mavlink_msg_param_request_read_encode(mavlink->getSystemId(), mavlink->getComponentId(), &msg, &read); sendMessage(msg); - qDebug() << __FILE__ << __LINE__ << "REQUESTING PARAM RETRANSMISSION FROM COMPONENT" << component << "FOR PARAM NAME" << parameter; + //qDebug() << __FILE__ << __LINE__ << "REQUESTING PARAM RETRANSMISSION FROM COMPONENT" << component << "FOR PARAM NAME" << parameter; } /** @@ -2733,9 +2744,7 @@ void UAS::launch() */ void UAS::armSystem() { - mavlink_message_t msg; - mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), mode | MAV_MODE_FLAG_SAFETY_ARMED, navMode); - sendMessage(msg); + setModeArm(base_mode | MAV_MODE_FLAG_SAFETY_ARMED, custom_mode); } /** @@ -2744,37 +2753,27 @@ void UAS::armSystem() */ void UAS::disarmSystem() { - mavlink_message_t msg; - mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), mode & ~MAV_MODE_FLAG_SAFETY_ARMED, navMode); - sendMessage(msg); + setModeArm(base_mode & ~MAV_MODE_FLAG_SAFETY_ARMED, custom_mode); } void UAS::toggleArmedState() { - mavlink_message_t msg; - mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), mode ^ MAV_MODE_FLAG_SAFETY_ARMED, navMode); - sendMessage(msg); + setModeArm(base_mode ^ MAV_MODE_FLAG_SAFETY_ARMED, custom_mode); } void UAS::goAutonomous() { - mavlink_message_t msg; - mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), mode & MAV_MODE_FLAG_AUTO_ENABLED & ~MAV_MODE_FLAG_MANUAL_INPUT_ENABLED, navMode); - sendMessage(msg); + setMode((base_mode & ~MAV_MODE_FLAG_MANUAL_INPUT_ENABLED) | (MAV_MODE_FLAG_AUTO_ENABLED | MAV_MODE_FLAG_STABILIZE_ENABLED | MAV_MODE_FLAG_GUIDED_ENABLED), 0); } void UAS::goManual() { - mavlink_message_t msg; - mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), mode & ~MAV_MODE_FLAG_AUTO_ENABLED & MAV_MODE_FLAG_MANUAL_INPUT_ENABLED, navMode); - sendMessage(msg); + setMode((base_mode & ~(MAV_MODE_FLAG_AUTO_ENABLED | MAV_MODE_FLAG_STABILIZE_ENABLED | MAV_MODE_FLAG_GUIDED_ENABLED)) | MAV_MODE_FLAG_MANUAL_INPUT_ENABLED, 0); } void UAS::toggleAutonomy() { - mavlink_message_t msg; - mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), mode ^ MAV_MODE_FLAG_AUTO_ENABLED ^ MAV_MODE_FLAG_MANUAL_INPUT_ENABLED, navMode); - sendMessage(msg); + setMode(base_mode ^ MAV_MODE_FLAG_AUTO_ENABLED ^ MAV_MODE_FLAG_MANUAL_INPUT_ENABLED ^ MAV_MODE_FLAG_GUIDED_ENABLED ^ MAV_MODE_FLAG_STABILIZE_ENABLED, 0); } /** @@ -2797,7 +2796,7 @@ void UAS::setManualControlCommands(double roll, double pitch, double yaw, double manualThrust = thrust * thrustScaling; // If system has manual inputs enabled and is armed - if(((mode & MAV_MODE_FLAG_DECODE_POSITION_MANUAL) && (mode & MAV_MODE_FLAG_DECODE_POSITION_SAFETY)) || (mode & MAV_MODE_FLAG_HIL_ENABLED)) + if(((base_mode & MAV_MODE_FLAG_DECODE_POSITION_MANUAL) && (base_mode & MAV_MODE_FLAG_DECODE_POSITION_SAFETY)) || (base_mode & MAV_MODE_FLAG_HIL_ENABLED)) { mavlink_message_t message; mavlink_msg_manual_control_pack(mavlink->getSystemId(), mavlink->getComponentId(), &message, this->uasId, (float)manualPitchAngle, (float)manualRollAngle, (float)manualThrust, (float)manualYawAngle, buttons); @@ -2815,7 +2814,7 @@ void UAS::setManualControlCommands(double roll, double pitch, double yaw, double void UAS::setManual6DOFControlCommands(double x, double y, double z, double roll, double pitch, double yaw) { // If system has manual inputs enabled and is armed - if(((mode & MAV_MODE_FLAG_DECODE_POSITION_MANUAL) && (mode & MAV_MODE_FLAG_DECODE_POSITION_SAFETY)) || (mode & MAV_MODE_FLAG_HIL_ENABLED)) + if(((base_mode & MAV_MODE_FLAG_DECODE_POSITION_MANUAL) && (base_mode & MAV_MODE_FLAG_DECODE_POSITION_SAFETY)) || (base_mode & MAV_MODE_FLAG_HIL_ENABLED)) { mavlink_message_t message; mavlink_msg_setpoint_6dof_pack(mavlink->getSystemId(), mavlink->getComponentId(), &message, this->uasId, (float)x, (float)y, (float)z, (float)roll, (float)pitch, (float)yaw); @@ -2885,6 +2884,17 @@ void UAS::land() sendMessage(msg); } +/** +* Order the robot to start receiver pairing +*/ +void UAS::pairRX(int rxType, int rxSubType) +{ + mavlink_message_t msg; + + mavlink_msg_command_long_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, uasId, MAV_COMP_ID_ALL, MAV_CMD_START_RX_PAIR, 0, rxType, rxSubType, 0, 0, 0, 0, 0); + sendMessage(msg); +} + /** * The MAV starts the emergency landing procedure. The behaviour depends on the onboard implementation * and might differ between systems. @@ -2936,7 +2946,7 @@ bool UAS::emergencyKILL() /** * If enabled, connect the flight gear link. */ -void UAS::enableHilFlightGear(bool enable, QString options) +void UAS::enableHilFlightGear(bool enable, QString options, bool sensorHil) { QGCFlightGearLink* link = dynamic_cast(simulation); if (!link || !simulation) { @@ -2950,6 +2960,7 @@ void UAS::enableHilFlightGear(bool enable, QString options) // Connect Flight Gear Link link = dynamic_cast(simulation); link->setStartupArguments(options); + link->sensorHilEnabled(sensorHil); if (enable) { startHil(); @@ -3094,7 +3105,7 @@ void UAS::sendHilState(quint64 time_us, float roll, float pitch, float yaw, floa float pitchspeed, float yawspeed, double lat, double lon, double alt, float vx, float vy, float vz, float ind_airspeed, float true_airspeed, float xacc, float yacc, float zacc) { - if (this->mode & MAV_MODE_FLAG_HIL_ENABLED) + if (this->base_mode & MAV_MODE_FLAG_HIL_ENABLED) { float q[4]; @@ -3122,17 +3133,19 @@ void UAS::sendHilState(quint64 time_us, float roll, float pitch, float yaw, floa else { // Attempt to set HIL mode - mavlink_message_t msg; - mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), mode | MAV_MODE_FLAG_HIL_ENABLED, navMode); - sendMessage(msg); + setMode(base_mode | MAV_MODE_FLAG_HIL_ENABLED, custom_mode); qDebug() << __FILE__ << __LINE__ << "HIL is onboard not enabled, trying to enable."; } } +/* +* @param abs_pressure Absolute Pressure (hPa) +* @param diff_pressure Differential Pressure (hPa) +*/ void UAS::sendHilSensors(quint64 time_us, float xacc, float yacc, float zacc, float rollspeed, float pitchspeed, float yawspeed, float xmag, float ymag, float zmag, float abs_pressure, float diff_pressure, float pressure_alt, float temperature, quint32 fields_changed) { - if (this->mode & MAV_MODE_FLAG_HIL_ENABLED) + if (this->base_mode & MAV_MODE_FLAG_HIL_ENABLED) { mavlink_message_t msg; mavlink_msg_hil_sensor_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, @@ -3145,9 +3158,7 @@ void UAS::sendHilSensors(quint64 time_us, float xacc, float yacc, float zacc, fl else { // Attempt to set HIL mode - mavlink_message_t msg; - mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), mode | MAV_MODE_FLAG_HIL_ENABLED, navMode); - sendMessage(msg); + setMode(base_mode | MAV_MODE_FLAG_HIL_ENABLED, custom_mode); qDebug() << __FILE__ << __LINE__ << "HIL is onboard not enabled, trying to enable."; } } @@ -3158,7 +3169,7 @@ void UAS::sendHilGps(quint64 time_us, double lat, double lon, double alt, int fi if (QGC::groundTimeMilliseconds() - lastSendTimeGPS < 100) return; - if (this->mode & MAV_MODE_FLAG_HIL_ENABLED) + if (this->base_mode & MAV_MODE_FLAG_HIL_ENABLED) { float course = cog; // map to 0..2pi @@ -3176,9 +3187,7 @@ void UAS::sendHilGps(quint64 time_us, double lat, double lon, double alt, int fi else { // Attempt to set HIL mode - mavlink_message_t msg; - mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), mode | MAV_MODE_FLAG_HIL_ENABLED, navMode); - sendMessage(msg); + setMode(base_mode | MAV_MODE_FLAG_HIL_ENABLED, custom_mode); qDebug() << __FILE__ << __LINE__ << "HIL is onboard not enabled, trying to enable."; } } @@ -3192,9 +3201,7 @@ void UAS::startHil() if (hilEnabled) return; hilEnabled = true; sensorHil = false; - mavlink_message_t msg; - mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), mode | MAV_MODE_FLAG_HIL_ENABLED, navMode); - sendMessage(msg); + setMode(base_mode | MAV_MODE_FLAG_HIL_ENABLED, custom_mode); // Connect HIL simulation link simulation->connectSimulation(); } @@ -3205,9 +3212,7 @@ void UAS::startHil() void UAS::stopHil() { if (simulation) simulation->disconnectSimulation(); - mavlink_message_t msg; - mavlink_msg_set_mode_pack(mavlink->getSystemId(), mavlink->getComponentId(), &msg, this->getUASID(), mode & !MAV_MODE_FLAG_HIL_ENABLED, navMode); - sendMessage(msg); + setMode(base_mode & ~MAV_MODE_FLAG_HIL_ENABLED, custom_mode); hilEnabled = false; sensorHil = false; } @@ -3334,51 +3339,65 @@ QString UAS::getAudioModeTextFor(int id) * The mode returned can be auto, stabilized, test, manual, preflight or unknown. * @return the short text of the mode for the id given. */ -QString UAS::getShortModeTextFor(int id) +QString UAS::getShortModeTextFor(uint8_t base_mode, uint32_t custom_mode, int autopilot) { QString mode = ""; - uint8_t modeid = id; - - - // BASE MODE DECODING - if (modeid == 0) - { - mode = "|PREFLIGHT"; - } - else { - if (modeid & (uint8_t)MAV_MODE_FLAG_DECODE_POSITION_AUTO){ - mode += "|AUTO"; + if (base_mode & MAV_MODE_FLAG_CUSTOM_MODE_ENABLED) { + // use custom_mode - autopilot-specific + if (autopilot == MAV_AUTOPILOT_PX4) { + union px4_custom_mode px4_mode; + px4_mode.data = custom_mode; + if (px4_mode.main_mode == PX4_CUSTOM_MAIN_MODE_MANUAL) { + mode += "|MANUAL"; + } else if (px4_mode.main_mode == PX4_CUSTOM_MAIN_MODE_SEATBELT) { + mode += "|SEATBELT"; + } else if (px4_mode.main_mode == PX4_CUSTOM_MAIN_MODE_EASY) { + mode += "|EASY"; + } else if (px4_mode.main_mode == PX4_CUSTOM_MAIN_MODE_AUTO) { + mode += "|AUTO"; + if (px4_mode.sub_mode == PX4_CUSTOM_SUB_MODE_AUTO_READY) { + mode += "|READY"; + } else if (px4_mode.sub_mode == PX4_CUSTOM_SUB_MODE_AUTO_TAKEOFF) { + mode += "|TAKEOFF"; + } else if (px4_mode.sub_mode == PX4_CUSTOM_SUB_MODE_AUTO_LOITER) { + mode += "|LOITER"; + } else if (px4_mode.sub_mode == PX4_CUSTOM_SUB_MODE_AUTO_MISSION) { + mode += "|MISSION"; + } else if (px4_mode.sub_mode == PX4_CUSTOM_SUB_MODE_AUTO_RTL) { + mode += "|RTL"; + } else if (px4_mode.sub_mode == PX4_CUSTOM_SUB_MODE_AUTO_LAND) { + mode += "|LAND"; + } + } } + } - if (modeid & (uint8_t)MAV_MODE_FLAG_DECODE_POSITION_MANUAL){ + // fallback to using base_mode + if (mode.length() == 0) { + // use base_mode - not autopilot-specific + if (base_mode == 0) { + mode += "|PREFLIGHT"; + } else if (base_mode & MAV_MODE_FLAG_DECODE_POSITION_AUTO) { + mode += "|AUTO"; + } else if (base_mode & MAV_MODE_FLAG_DECODE_POSITION_MANUAL) { mode += "|MANUAL"; + if (base_mode & MAV_MODE_FLAG_DECODE_POSITION_GUIDED) { + mode += "|GUIDED"; + } else if (base_mode & MAV_MODE_FLAG_DECODE_POSITION_STABILIZE) { + mode += "|STABILIZED"; + } } - - if (modeid & (uint8_t)MAV_MODE_FLAG_DECODE_POSITION_GUIDED){ - mode += "|VECTOR"; - } - - if (modeid & (uint8_t)MAV_MODE_FLAG_DECODE_POSITION_STABILIZE){ - mode += "|STABILIZED"; - } - - - if (modeid & (uint8_t)MAV_MODE_FLAG_DECODE_POSITION_TEST){ - mode += "|TEST"; - } - - } if (mode.length() == 0) { mode = "|UNKNOWN"; - qDebug() << __FILE__ << __LINE__ << " Unknown modeid: " << modeid; + qDebug() << __FILE__ << __LINE__ << " Unknown mode: base_mode=" << base_mode << " custom_mode=" << custom_mode << " autopilot=" << autopilot; } // ARMED STATE DECODING - if (modeid & (uint8_t)MAV_MODE_FLAG_DECODE_POSITION_SAFETY) + if (base_mode & MAV_MODE_FLAG_DECODE_POSITION_SAFETY) { mode.prepend("A"); } @@ -3388,12 +3407,12 @@ QString UAS::getShortModeTextFor(int id) } // HARDWARE IN THE LOOP DECODING - if (modeid & (uint8_t)MAV_MODE_FLAG_DECODE_POSITION_HIL) + if (base_mode & MAV_MODE_FLAG_DECODE_POSITION_HIL) { mode.prepend("HIL:"); } - qDebug() << "MODE: " << modeid << " " << mode; + //qDebug() << "base_mode=" << base_mode << " custom_mode=" << custom_mode << " autopilot=" << autopilot << ": " << mode; return mode; } diff --git a/src/uas/UAS.h b/src/uas/UAS.h index b1c027bd1f55cb9039a0c0351322702ff0237d38..25b8ffc944b29e662b76d2d4629de9c59cf7a935 100644 --- a/src/uas/UAS.h +++ b/src/uas/UAS.h @@ -41,6 +41,7 @@ This file is part of the QGROUNDCONTROL project #include "QGCJSBSimLink.h" #include "QGCXPlaneLink.h" + /** * @brief A generic MAVLINK-connected MAV/UAV * @@ -68,7 +69,7 @@ public: /** @brief Get short mode */ const QString& getShortMode() const; /** @brief Translate from mode id to text */ - static QString getShortModeTextFor(int id); + static QString getShortModeTextFor(uint8_t base_mode, uint32_t custom_mode, int autopilot); /** @brief Translate from mode id to audio text */ static QString getAudioModeTextFor(int id); /** @brief Get the unique system id */ @@ -361,9 +362,8 @@ protected: //COMMENTS FOR TEST UNIT int airframe; ///< The airframe type int autopilot; ///< Type of the Autopilot: -1: None, 0: Generic, 1: PIXHAWK, 2: SLUGS, 3: Ardupilot (up to 15 types), defined in MAV_AUTOPILOT_TYPE ENUM bool systemIsArmed; ///< If the system is armed - uint8_t mode; ///< The current mode of the MAV + uint8_t base_mode; ///< The current mode of the MAV uint32_t custom_mode; ///< The current mode of the MAV - uint32_t navMode; ///< The current navigation mode of the MAV int status; ///< The current status of the MAV QString shortModeText; ///< Short textual mode description QString shortStateText; ///< Short textual state description @@ -465,6 +465,7 @@ protected: //COMMENTS FOR TEST UNIT QImage image; ///< Image data of last completely transmitted image quint64 imageStart; bool blockHomePositionChanges; ///< Block changes to the home position + bool receivedMode; ///< True if mode was retrieved from current conenction to UAS #if defined(QGC_PROTOBUF_ENABLED) && defined(QGC_USE_PIXHAWK_MESSAGES) px::GLOverlay overlay; @@ -491,7 +492,7 @@ protected: //COMMENTS FOR TEST UNIT /// PARAMETERS QMap* > parameters; ///< All parameters bool paramsOnceRequested; ///< If the parameter list has been read at least once - QGCUASParamManager* paramManager; ///< Parameter manager class + QGCUASParamManager paramMgr; ///< Parameter manager for this UAS /// SIMULATION QGCHilLink* simulation; ///< Hardware in the loop simulation link @@ -505,29 +506,27 @@ public: float getChargeLevel(); /** @brief Get the human-readable status message for this code */ void getStatusForCode(int statusCode, QString& uasState, QString& stateDescription); - /** @brief Get the human-readable navigation mode translation for this mode */ - QString getNavModeText(int mode); /** @brief Check if vehicle is in autonomous mode */ bool isAuto(); /** @brief Check if vehicle is armed */ bool isArmed() const { return systemIsArmed; } + /** @brief Get reference to the waypoint manager **/ UASWaypointManager* getWaypointManager() { return &waypointManager; } + /** @brief Get reference to the param manager **/ - QGCUASParamManager* getParamManager() const { - return paramManager; + virtual QGCUASParamManager* getParamManager() { + return ¶mMgr; } + /** @brief Get the HIL simulation */ QGCHilLink* getHILSimulation() const { return simulation; } - // TODO Will be removed - /** @brief Set reference to the param manager **/ - void setParamManager(QGCUASParamManager* manager) { - paramManager = manager; - } + + int getSystemType(); /** @@ -725,11 +724,14 @@ public slots: void home(); /** @brief Order the robot to land **/ void land(); + /** @brief Order the robot to pair its receiver **/ + void pairRX(int rxType, int rxSubType); + void halt(); void go(); /** @brief Enable / disable HIL */ - void enableHilFlightGear(bool enable, QString options); + void enableHilFlightGear(bool enable, QString options, bool sensorHil); void enableHilJSBSim(bool enable, QString options); void enableHilXPlane(bool enable); @@ -832,8 +834,11 @@ public slots: /** @brief Set this UAS as the system currently in focus, e.g. in the main display widgets */ void setSelected(); - /** @brief Set current mode of operation, e.g. auto or manual */ - void setMode(int mode); + /** @brief Set current mode of operation, e.g. auto or manual, always uses the current arming status for safety reason */ + void setMode(uint8_t newBaseMode, uint32_t newCustomMode); + + /** @brief Set current mode of operation, e.g. auto or manual, does not check the arming status, for anything else than arming/disarming operations use setMode instead */ + void setModeArm(uint8_t newBaseMode, uint32_t newCustomMode); /** @brief Request all parameters */ void requestParameters(); @@ -844,7 +849,7 @@ public slots: void requestParameter(int component, int id); /** @brief Set a system parameter */ - void setParameter(const int component, const QString& id, const QVariant& value); + void setParameter(const int compId, const QString& paramId, const QVariant& value); /** @brief Write parameters to permanent storage */ void writeParametersToStorage(); @@ -936,6 +941,8 @@ protected: /** @brief Get the UNIX timestamp in milliseconds, ignore attitudeStamped mode */ quint64 getUnixReferenceTime(quint64 time); + virtual void processParamValueMsg(mavlink_message_t& msg, const QString& paramName,const mavlink_param_value_t& rawValue, mavlink_param_union_t& paramValue); + int componentID[256]; bool componentMulti[256]; bool connectionLost; ///< Flag indicates a timed out connection @@ -949,6 +956,7 @@ protected: quint64 lastSendTimeSensors; QList actions; ///< A list of actions that this UAS can perform. + protected slots: /** @brief Write settings to disk */ void writeSettings(); diff --git a/src/uas/UASInterface.h b/src/uas/UASInterface.h index 37382e3eb4197f0e077298bace9698f52549d6a1..fba940b3b23b80676899cb152c54d95b8fa48fba 100644 --- a/src/uas/UASInterface.h +++ b/src/uas/UASInterface.h @@ -40,6 +40,7 @@ This file is part of the QGROUNDCONTROL project #include "LinkInterface.h" #include "ProtocolInterface.h" +#include "UASParameterDataModel.h" #include "UASWaypointManager.h" #include "QGCUASParamManager.h" #include "RadioCalibration/RadioCalibrationData.h" @@ -152,11 +153,9 @@ public: /** @brief Get reference to the waypoint manager **/ virtual UASWaypointManager* getWaypointManager(void) = 0; + /** @brief Get reference to the param manager **/ - virtual QGCUASParamManager* getParamManager() const = 0; - // TODO Will be removed - /** @brief Set reference to the param manager **/ - virtual void setParamManager(QGCUASParamManager* manager) = 0; + virtual QGCUASParamManager* getParamManager() = 0; /* COMMUNICATION FLAGS */ @@ -291,12 +290,14 @@ public slots: virtual void home() = 0; /** @brief Order the robot to land **/ virtual void land() = 0; + /** @brief Order the robot to pair its receiver **/ + virtual void pairRX(int rxType, int rxSubType) = 0; /** @brief Halt the system */ virtual void halt() = 0; /** @brief Start/continue the current robot action */ virtual void go() = 0; /** @brief Set the current mode of operation */ - virtual void setMode(int mode) = 0; + virtual void setMode(uint8_t newBaseMode, uint32_t newCustomMode) = 0; /** Stops the robot system. If it is an MAV, the robot starts the emergency landing procedure **/ virtual void emergencySTOP() = 0; /** Kills the robot. All systems are immediately shut down (e.g. the main power line is cut). This might lead to a crash **/ @@ -487,16 +488,7 @@ signals: * @param value the value that changed * @param msec the timestamp of the message, in milliseconds */ - void valueChanged(const int uasId, const QString& name, const QString& unit, const quint8 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const qint8 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const quint16 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const qint16 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const quint32 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const qint32 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const quint64 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const qint64 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const double value, const quint64 msec); - void valueChanged(const int uasid, const QString& name, const QString& unit, const QVariant value,const quint64 msecs); + void valueChanged(const int uasid, const QString& name, const QString& unit, const QVariant &value,const quint64 msecs); void voltageChanged(int uasId, double voltage); void waypointUpdated(int uasId, int id, double x, double y, double z, double yaw, bool autocontinue, bool active); diff --git a/src/uas/UASManager.cc b/src/uas/UASManager.cc index c03cec06edb21bffd54897d5718e056cb68fc350..8ee92242db1ba16a988521e72f80416b33d8a940 100644 --- a/src/uas/UASManager.cc +++ b/src/uas/UASManager.cc @@ -244,11 +244,11 @@ void UASManager::uavChangedHomePosition(int uav, double lat, double lon, double **/ UASManager::UASManager() : activeUAS(NULL), + offlineUASWaypointManager(NULL), homeLat(47.3769), homeLon(8.549444), homeAlt(470.0), - homeFrame(MAV_FRAME_GLOBAL), - offlineUASWaypointManager(NULL) + homeFrame(MAV_FRAME_GLOBAL) { loadSettings(); setLocalNEDSafetyBorders(1, -1, 0, -1, 1, -1); @@ -280,6 +280,7 @@ void UASManager::addUAS(UASInterface* uas) // Only execute if there is no UAS at this index if (!systems.contains(uas)) { + qDebug() << "Add new UAS: " << uas->getUASID(); systems.append(uas); // Set home position on UAV if set in UI // - this is done on a per-UAV basis diff --git a/src/uas/UASParameterCommsMgr.cc b/src/uas/UASParameterCommsMgr.cc new file mode 100644 index 0000000000000000000000000000000000000000..fe7383d9a9725c38e0b75b7b3264cd91f7b9062a --- /dev/null +++ b/src/uas/UASParameterCommsMgr.cc @@ -0,0 +1,549 @@ +#include "UASParameterCommsMgr.h" + +#include + +#include "QGCUASParamManager.h" +#include "UASInterface.h" + + + +#define RC_CAL_CHAN_MAX 8 + +UASParameterCommsMgr::UASParameterCommsMgr(QObject *parent) : + QObject(parent), + lastReceiveTime(0), + mav(NULL), + maxSilenceTimeout(30000), + paramDataModel(NULL), + retransmitBurstLimit(5), + silenceTimeout(1000), + transmissionListMode(false) +{ + + +} + +UASParameterCommsMgr* UASParameterCommsMgr::initWithUAS(UASInterface* uas) +{ + mav = uas; + paramDataModel = mav->getParamManager()->dataModel(); + loadParamCommsSettings(); + + //Requesting parameters one-by-one from mav + connect(this, SIGNAL(parameterUpdateRequestedById(int,int)), + mav, SLOT(requestParameter(int,int))); + + // Sending params to the UAS + connect(this, SIGNAL(commitPendingParameter(int,QString,QVariant)), + mav, SLOT(setParameter(int,QString,QVariant))); + + // Received parameter updates from UAS + connect(mav, SIGNAL(parameterChanged(int,int,int,int,QString,QVariant)), + this, SLOT(receivedParameterUpdate(int,int,int,int,QString,QVariant))); + + connect(&silenceTimer, SIGNAL(timeout()), + this,SLOT(silenceTimerExpired())); + + return this; +} + + + + +void UASParameterCommsMgr::loadParamCommsSettings() +{ + QSettings settings; + //TODO these are duplicates of MAVLinkProtocol settings...seems wrong to use them in two places + settings.beginGroup("QGC_MAVLINK_PROTOCOL"); + bool ok; + int val = settings.value("PARAMETER_RETRANSMISSION_TIMEOUT", 1000).toInt(&ok); + if (ok) { + silenceTimeout = val; + qDebug() << "silenceTimeout" << silenceTimeout; + } + + settings.endGroup(); +} + + + +/** + * Send a request to deliver the list of onboard parameters + * from the MAV. + */ +void UASParameterCommsMgr::requestParameterList() +{ + if (!mav) { + return; + } + + if (!transmissionListMode) { + transmissionListMode = true;//TODO eliminate? + //we use (compId 0, paramId 0) as indicating all params for the system + markReadParamWaiting(0,0); + mav->requestParameters(); + updateSilenceTimer(); + } + else { + qDebug() << __FILE__ << __LINE__ << "Ignoring requestParameterList because we're receiving params list"; + } + +} + + +void UASParameterCommsMgr::markReadParamWaiting(int compId, int paramId) +{ + if (!readsWaiting.contains(compId)) { + readsWaiting.insert(compId, new QSet()); + } + + readsWaiting.value(compId)->insert(paramId); +} + +void UASParameterCommsMgr::markWriteParamWaiting(int compId, QString paramName, QVariant value) +{ + //ensure we have a map for this compId + if (!writesWaiting.contains(compId)) { + writesWaiting.insert(compId, new QMap()); + } + + // Insert it in missing write ACK list + writesWaiting.value(compId)->insert(paramName, value); +} + +/* + Empty read retransmission list + Empty write retransmission list +*/ +void UASParameterCommsMgr::clearRetransmissionLists(int& missingReadCount, int& missingWriteCount ) +{ + qDebug() << __FILE__ << __LINE__ << "clearRetransmissionLists"; + + missingReadCount = 0; + QList compIds = readsWaiting.keys(); + foreach (int compId, compIds) { + missingReadCount += readsWaiting.value(compId)->count(); + readsWaiting.value(compId)->clear(); + } + + missingWriteCount = 0; + compIds = writesWaiting.keys(); + foreach (int compId, compIds) { + missingWriteCount += writesWaiting.value(compId)->count(); + writesWaiting.value(compId)->clear(); + } + +} + + +void UASParameterCommsMgr::emitPendingParameterCommit(int compId, const QString& key, QVariant& value) +{ + int paramType = (int)value.type(); + switch (paramType) + { + case QVariant::Char: + { + QVariant fixedValue(QChar((unsigned char)value.toInt())); + emit commitPendingParameter(compId, key, fixedValue); + } + break; + case QVariant::Int: + { + QVariant fixedValue(value.toInt()); + emit commitPendingParameter(compId, key, fixedValue); + } + break; + case QVariant::UInt: + { + QVariant fixedValue(value.toUInt()); + emit commitPendingParameter(compId, key, fixedValue); + } + break; + case QMetaType::Float: + { + QVariant fixedValue(value.toFloat()); + emit commitPendingParameter(compId, key, fixedValue); + } + break; + default: + qCritical() << "ABORTED PARAM SEND, INVALID QVARIANT TYPE" << paramType; + return; + } + + setParameterStatusMsg(tr("Writing %1: %2 for comp. %3").arg(key).arg(value.toDouble()).arg(compId)); + +} + + +void UASParameterCommsMgr::resendReadWriteRequests() +{ + int compId; + QList compIds; + + // Re-request at maximum retransmitBurstLimit parameters at once + // to prevent link flooding' + int requestedReadCount = 0; + compIds = readsWaiting.keys(); + foreach (compId, compIds) { + // Request n parameters from this component (at maximum) + QSet* missingReadParams = readsWaiting.value(compId, NULL); + qDebug() << "compId " << compId << "readsWaiting:" << missingReadParams->count(); + foreach (int paramId, *missingReadParams) { + if (0 == paramId && 0 == compId) { + mav->requestParameters(); + //don't request any other params individually for this component + break; + } + if (requestedReadCount < retransmitBurstLimit) { + //qDebug() << __FILE__ << __LINE__ << "RETRANSMISSION GUARD REQUESTS RETRANSMISSION OF PARAM #" << paramId << "FROM COMPONENT #" << compId; + emit parameterUpdateRequestedById(compId, paramId); + setParameterStatusMsg(tr("Requested retransmission of #%1").arg(paramId+1)); + requestedReadCount++; + } + else { + qDebug() << "Throttling read retransmit requests at" << requestedReadCount; + break; + } + } + } + + // Re-request at maximum retransmitBurstLimit parameters at once + // to prevent write-request link flooding + int requestedWriteCount = 0; + compIds = writesWaiting.keys(); + foreach (compId, compIds) { + QMap * missingWriteParams = writesWaiting.value(compId); + foreach (QString key, missingWriteParams->keys()) { + if (requestedWriteCount < retransmitBurstLimit) { + // Re-request write operation + QVariant value = missingWriteParams->value(key); + emitPendingParameterCommit(compId, key, value); + requestedWriteCount++; + } + else { + qDebug() << "Throttling write retransmit requests at" << requestedWriteCount; + break; + } + } + } + + updateSilenceTimer(); + +} + +void UASParameterCommsMgr::resetAfterListReceive() +{ + transmissionListMode = false; + knownParamListSize.clear(); +} + +void UASParameterCommsMgr::silenceTimerExpired() +{ + quint64 curTime = QGC::groundTimeMilliseconds(); + int elapsed = (int)(curTime - lastSilenceTimerReset); + qDebug() << "silenceTimerExpired elapsed:" << elapsed; + + if (elapsed < silenceTimeout) { + //reset the guard timer: it fired prematurely + updateSilenceTimer(); + return; + } + + int totalElapsed = (int)(curTime - lastReceiveTime); + if (totalElapsed > maxSilenceTimeout) { + qDebug() << "maxSilenceTimeout exceeded: " << totalElapsed; + int missingReads, missingWrites; + clearRetransmissionLists(missingReads,missingWrites); + silenceTimer.stop(); + lastReceiveTime = 0; + lastSilenceTimerReset = curTime; + setParameterStatusMsg(tr("TIMEOUT: Abandoning %1 reads %2 writes after %3 seconds").arg(missingReads).arg(missingWrites).arg(totalElapsed/1000)); + } + else { + resendReadWriteRequests(); + } +} + + +void UASParameterCommsMgr::requestParameterUpdate(int compId, const QString& paramName) +{ + if (mav) { + mav->requestParameter(compId, paramName); + //TODO track these read requests with a paramName but no param ID : use index in getOnboardParamsForComponent? + //ensure we keep track of every single read request + } +} + +void UASParameterCommsMgr::requestRcCalibrationParamsUpdate() +{ + if (!transmissionListMode) { + QString minTpl("RC%1_MIN"); + QString maxTpl("RC%1_MAX"); + QString trimTpl("RC%1_TRIM"); + QString revTpl("RC%1_REV"); + + // Do not request the RC type, as these values depend on this + // active onboard parameter + + + int defCompId = paramDataModel->getDefaultComponentId(); + for (unsigned int i = 1; i < (RC_CAL_CHAN_MAX+1); ++i) { + qDebug() << "Request RC " << i; + requestParameterUpdate(defCompId, minTpl.arg(i)); + requestParameterUpdate(defCompId, trimTpl.arg(i)); + requestParameterUpdate(defCompId, maxTpl.arg(i)); + requestParameterUpdate(defCompId, revTpl.arg(i)); + QGC::SLEEP::usleep(5000); + } + } + else { + qDebug() << __FILE__ << __LINE__ << "Ignoring requestRcCalibrationParamsUpdate because we're receiving params list"; + } +} + + +/** + * @param component the subsystem which has the parameter + * @param parameterName name of the parameter, as delivered by the system + * @param value value of the parameter + */ +void UASParameterCommsMgr::setParameter(int compId, QString paramName, QVariant value, bool forceSend) +{ + if (paramName.isEmpty()) { + return; + } + + double dblValue = value.toDouble(); + + if (paramDataModel->isValueLessThanParamMin(paramName,dblValue)) { + setParameterStatusMsg(tr("REJ. %1, %2 < min").arg(paramName).arg(dblValue), + ParamCommsStatusLevel_Error + ); + return; + } + if (paramDataModel->isValueGreaterThanParamMax(paramName,dblValue)) { + setParameterStatusMsg(tr("REJ. %1, %2 > max").arg(paramName).arg(dblValue), + ParamCommsStatusLevel_Error + ); + return; + } + + if (!forceSend) { + QVariant onboardVal; + paramDataModel->getOnboardParamValue(compId,paramName,onboardVal); + if (onboardVal == value) { + setParameterStatusMsg(tr("REJ. %1 already %2").arg(paramName).arg(dblValue), + ParamCommsStatusLevel_Warning + ); + return; + } + } + + emitPendingParameterCommit(compId, paramName, value); + + //Add this request to list of writes not yet ack'd + + markWriteParamWaiting( compId, paramName, value); + updateSilenceTimer(); + + +} + +void UASParameterCommsMgr::updateSilenceTimer() +{ + //if there are pending reads or writes, ensure we timeout in a little while + //if we hear nothing but silence from our partner + + int missReadCount = 0; + foreach (int key, readsWaiting.keys()) { + missReadCount += readsWaiting.value(key)->count(); + } + + int missWriteCount = 0; + foreach (int key, writesWaiting.keys()) { + missWriteCount += writesWaiting.value(key)->count(); + } + + + if (missReadCount > 0 || missWriteCount > 0) { + lastSilenceTimerReset = QGC::groundTimeMilliseconds(); + if (0 == lastReceiveTime) { + lastReceiveTime = lastSilenceTimerReset; + } + silenceTimer.start(silenceTimeout); + } + else { + //all parameters have been received, broadcast to UI + emit parameterListUpToDate(); + resetAfterListReceive(); + silenceTimer.stop(); + lastReceiveTime = 0; + } + + + +} + + +void UASParameterCommsMgr::setParameterStatusMsg(const QString& msg, ParamCommsStatusLevel_t level) +{ + //qDebug() << "parameterStatusMsg: " << msg; + emit parameterStatusMsgUpdated(msg,level); +} + +void UASParameterCommsMgr::receivedParameterUpdate(int uas, int compId, int paramCount, int paramId, QString paramName, QVariant value) +{ + Q_UNUSED(uas); //this object is assigned to one UAS only + lastReceiveTime = QGC::groundTimeMilliseconds(); + // qDebug() << "compId" << compId << "receivedParameterUpdate:" << paramName; + + //notify the data model that we have an updated param + paramDataModel->handleParamUpdate(compId,paramName,value); + + + // Ensure we have missing read/write lists for this compId + if (!readsWaiting.contains(compId)) { + readsWaiting.insert(compId, new QSet()); + } + if (!writesWaiting.contains(compId) ) { + writesWaiting.insert(compId,new QMap()); + } + + QSet* compMissingReads = readsWaiting.value(compId); + // List mode is different from single parameter transfers + if (transmissionListMode) { + // Only accept the list size once on the first packet from each component + if (!knownParamListSize.contains(compId)) { + // Mark list size as known + knownParamListSize.insert(compId,paramCount); + + //remove our placeholder read request for all params + readsWaiting.value(0)->remove(0); + + qDebug() << "Mark all parameters as missing: " << paramCount; + for (int i = 1; i < paramCount; ++i) { //param Id 0 is "all parameters" and not valid + compMissingReads->insert(i); + } + } + } + + + // Mark this parameter as received in read list + compMissingReads->remove(paramId); + + + bool justWritten = false; + bool writeMismatch = false; + + // Mark this parameter as received in write ACK list + QMap* compMissingWrites = writesWaiting.value(compId); + if (!compMissingWrites) { + //we sometimes send a write request on compId 0 and get a response on a nonzero compId eg 50 + compMissingWrites = writesWaiting.value(0); + } + if (compMissingWrites && compMissingWrites->contains(paramName)) { + justWritten = true; + if (compMissingWrites->value(paramName) != value) { + writeMismatch = true; + } + compMissingWrites->remove(paramName); + } + + + if (justWritten) { + int waitingWritesCount = compMissingWrites->count(); + if (!writeMismatch) { + setParameterStatusMsg(tr("SUCCESS: Wrote %2 (#%1): %3").arg(paramId+1).arg(paramName).arg(value.toDouble())); + } + + if (!writeMismatch) { + if (0 == waitingWritesCount) { + setParameterStatusMsg(tr("SUCCESS: Wrote all params for component %1").arg(compId)); + if (persistParamsAfterSend) { + writeParamsToPersistentStorage(); + persistParamsAfterSend = false; + } + } + } + else { + // Mismatch, tell user + setParameterStatusMsg(tr("FAILURE: Wrote %1: sent %2 != onboard %3").arg(paramName).arg(compMissingWrites->value(paramName).toDouble()).arg(value.toDouble()), + ParamCommsStatusLevel_Warning); + } + } + else { + int waitingReadsCount = compMissingReads->count(); + + if (0 == waitingReadsCount) { + // Transmission done + QTime time = QTime::currentTime(); + QString timeString = time.toString(); + setParameterStatusMsg(tr("All received. (updated at %1)").arg(timeString)); + } + else { + // Waiting to receive more + QString val = QString("%1").arg(value.toFloat(), 5, 'f', 1, QChar(' ')); + setParameterStatusMsg(tr("OK: %1 %2 (%3/%4)").arg(paramName).arg(val).arg(paramCount-waitingReadsCount).arg(paramCount), + ParamCommsStatusLevel_OK); + } + } + + updateSilenceTimer(); + + +} + + +void UASParameterCommsMgr::writeParamsToPersistentStorage() +{ + if (mav) { + mav->writeParametersToStorage(); //TODO track timeout, retransmit etc? + persistParamsAfterSend = false; //done + } +} + + +void UASParameterCommsMgr::sendPendingParameters(bool copyToPersistent, bool forceSend) +{ + persistParamsAfterSend |= copyToPersistent; + + // Iterate through all components, through all pending parameters and send them to UAS + int parametersSent = 0; + QMap*>* changedValues = paramDataModel->getAllPendingParams(); + QMap*>::iterator i; + for (i = changedValues->begin(); i != changedValues->end(); ++i) { + // Iterate through the parameters of the component + int compId = i.key(); + QMap* paramList = i.value(); + QMap::iterator j; + setParameterStatusMsg(tr("%1 pending params for component %2").arg(paramList->count()).arg(compId)); + + for (j = paramList->begin(); j != paramList->end(); ++j) { + setParameter(compId, j.key(), j.value(), forceSend); + parametersSent++; + } + } + + // Change transmission status if necessary + if (0 == parametersSent) { + setParameterStatusMsg(tr("No transmission: No changed values."),ParamCommsStatusLevel_Warning); + } + else { + setParameterStatusMsg(tr("Transmitting %1 parameters.").arg(parametersSent)); + qDebug() << "Pending parameters now:" << paramDataModel->countPendingParams(); + } + + + updateSilenceTimer(); +} + +UASParameterCommsMgr::~UASParameterCommsMgr() +{ + silenceTimer.stop(); + + QString ptrStr; + ptrStr.sprintf("%8p", this); + qDebug() << "UASParameterCommsMgr destructor: " << ptrStr ; + +} + diff --git a/src/uas/UASParameterCommsMgr.h b/src/uas/UASParameterCommsMgr.h new file mode 100644 index 0000000000000000000000000000000000000000..ef313761547352399e0fb23dce851994df8a25f4 --- /dev/null +++ b/src/uas/UASParameterCommsMgr.h @@ -0,0 +1,120 @@ +#ifndef UASPARAMETERCOMMSMGR_H +#define UASPARAMETERCOMMSMGR_H + +#include +#include +#include +#include +#include + +class UASInterface; +class UASParameterDataModel; + + + +class UASParameterCommsMgr : public QObject +{ + Q_OBJECT + + +public: + explicit UASParameterCommsMgr(QObject *parent = 0); + UASParameterCommsMgr* initWithUAS(UASInterface* model);///< Two-stage constructor + + ~UASParameterCommsMgr(); + + typedef enum ParamCommsStatusLevel { + ParamCommsStatusLevel_OK = 0, + ParamCommsStatusLevel_Warning = 2, + ParamCommsStatusLevel_Error = 4, + ParamCommsStatusLevel_Count + } ParamCommsStatusLevel_t; + + +protected: + + /** @brief activate the silence timer if there are unack'd reads or writes */ + virtual void updateSilenceTimer(); + + virtual void setParameterStatusMsg(const QString& msg, ParamCommsStatusLevel_t level=ParamCommsStatusLevel_OK); + + /** @brief Load settings that control eg retransmission timeouts */ + void loadParamCommsSettings(); + + /** @brief clear transmissionMissingPackets and transmissionMissingWriteAckPackets */ + void clearRetransmissionLists(int& missingReadCount, int& missingWriteCount ); + + /** @brief we are waiting for a response to this read param request */ + virtual void markReadParamWaiting(int compId, int paramId); + + /** @brief we are waiting for a response to this write param request */ + void markWriteParamWaiting(int compId, QString paramName, QVariant value); + + void resendReadWriteRequests(); + void resetAfterListReceive(); + + void emitPendingParameterCommit(int compId, const QString& key, QVariant& value); + +signals: + void commitPendingParameter(int component, QString parameter, QVariant value); + void parameterChanged(int component, int parameterIndex, QVariant value); + void parameterValueConfirmed(int uas, int component,int paramCount, int paramId, QString parameter, QVariant value); + + /** @brief We have received a complete list of all parameters onboard the MAV */ + void parameterListUpToDate(); + + void parameterUpdateRequested(int component, const QString& parameter); + void parameterUpdateRequestedById(int componentId, int paramId); + + /** @brief We updated the parameter status message */ + void parameterStatusMsgUpdated(QString msg, int level); + +public slots: + /** @brief Iterate through all components, through all pending parameters and send them to UAS */ + virtual void sendPendingParameters(bool copyToPersistent = false, bool forceSend = false); + + /** @brief Write the current onboard parameters from transient RAM into persistent storage, e.g. EEPROM or harddisk */ + virtual void writeParamsToPersistentStorage(); + + /** @brief Write one parameter to the MAV */ + virtual void setParameter(int component, QString parameterName, QVariant value, bool forceSend = false); + + /** @brief Request list of parameters from MAV */ + virtual void requestParameterList(); + + /** @brief The max silence time expired */ + virtual void silenceTimerExpired(); + + /** @brief Request a single parameter update by name */ + virtual void requestParameterUpdate(int component, const QString& parameter); + + /** @brief Request an update of RC parameters */ + virtual void requestRcCalibrationParamsUpdate(); + + virtual void receivedParameterUpdate(int uas, int compId, int paramCount, int paramId, QString paramName, QVariant value); + +protected: + + + QMap knownParamListSize;///< The known param list size for each component, by component ID + quint64 lastReceiveTime; ///< The last time we received anything from our partner + quint64 lastSilenceTimerReset; + UASInterface* mav; ///< The MAV we're talking to + + int maxSilenceTimeout; ///< If nothing received within this period of time, abandon resends + + UASParameterDataModel* paramDataModel; + + bool persistParamsAfterSend; ///< Copy all parameters to persistent storage after sending + QMap*> readsWaiting; ///< All reads that have not yet been received, by component ID + int retransmitBurstLimit; ///< Number of packets requested for retransmission per burst + int silenceTimeout; ///< If nothing received within this period of time, start resends + QTimer silenceTimer; ///< Timer handling parameter retransmission + bool transmissionListMode; ///< Currently requesting list + QMap* > writesWaiting; ///< All writes that have not yet been ack'd, by component ID + + +}; + + +#endif // UASPARAMETERCOMMSMGR_H diff --git a/src/uas/UASParameterDataModel.cc b/src/uas/UASParameterDataModel.cc new file mode 100644 index 0000000000000000000000000000000000000000..b4f916dd64d572ca2470ba61f9063b6f7f3e96b9 --- /dev/null +++ b/src/uas/UASParameterDataModel.cc @@ -0,0 +1,507 @@ +#include "UASParameterDataModel.h" + +#include + +#include +#include +#include + +#include "QGCMAVLink.h" + +UASParameterDataModel::UASParameterDataModel(QObject *parent) : + QObject(parent), + defaultComponentId(-1) +{ + onboardParameters.clear(); + pendingParameters.clear(); + +} + + + +int UASParameterDataModel::countPendingParams() +{ + int total = 0; + QMap*>::iterator i; + for (i = pendingParameters.begin(); i != pendingParameters.end(); ++i) { + // Iterate through the parameters of the component + QMap* paramList = i.value(); + total += paramList->count(); + } + + return total; +} + +int UASParameterDataModel::countOnboardParams() +{ + int total = 0; + QMap*>::iterator i; + for (i = onboardParameters.begin(); i != onboardParameters.end(); ++i) { + // Iterate through the parameters of the component + QMap* paramList = i.value(); + total += paramList->count(); + } + + return total; +} + + +bool UASParameterDataModel::updatePendingParamWithValue(int compId, const QString& key, const QVariant& value, bool forceSend) +{ + bool pending = true; + //ensure we have this component in our onboard and pending lists already + addComponent(compId); + + if (!forceSend) { + QMap* existParams = getOnboardParamsForComponent(compId); + if (existParams->contains(key)) { + QVariant existValue = existParams->value(key); + if (existValue == value) { + pending = false; + } + } + } + + if (pending) { + setPendingParam(compId,key,value); + } + else { + removePendingParam(compId,key); + } + + return pending; +} + + +bool UASParameterDataModel::isParamChangePending(int compId, const QString& key) +{ + QMap* pendingParms = getPendingParamsForComponent(compId); + return ((NULL != pendingParms) && pendingParms->contains(key)); +} + +void UASParameterDataModel::setPendingParam(int compId, const QString& key, const QVariant &value) +{ + //ensure we have a placeholder map for this component + addComponent(compId); + setParamWithTypeInMap(compId,key,value,pendingParameters); + emit pendingParamUpdate(compId, key, value, true); +} + +void UASParameterDataModel::removePendingParam(int compId, const QString& key) +{ + qDebug() << "removePendingParam:" << key; + + QMap *pendParams = getPendingParamsForComponent(compId); + if (pendParams) { + pendParams->remove(key); + //broadcast the existing value + QVariant existVal; + getOnboardParamValue(compId,key,existVal); + emit pendingParamUpdate(compId, key,existVal, false); + } +} + +void UASParameterDataModel::setOnboardParam(int compId, const QString &key, const QVariant& value) +{ + //ensure we have a placeholder map for this component + addComponent(compId); + //TODO use setParamWithTypeInMap instead and verify + QMap *params = getOnboardParamsForComponent(compId); + params->insert(key,value); +} + +void UASParameterDataModel::setParamWithTypeInMap(int compId, const QString& key, const QVariant &value, QMap* >& map) +{ + + switch ((int)value.type()) + { + case QVariant::Int: + { + QVariant fixedValue(value.toInt()); + map.value(compId)->insert(key, fixedValue); + } + break; + case QVariant::UInt: + { + QVariant fixedValue(value.toUInt()); + map.value(compId)->insert(key, fixedValue); + } + break; + case QMetaType::Float: + { + QVariant fixedValue(value.toFloat()); + map.value(compId)->insert(key, fixedValue); + } + break; + case QMetaType::QChar: + { + QVariant fixedValue(QChar((unsigned char)value.toUInt())); + map.value(compId)->insert(key, fixedValue); + } + break; + case QMetaType::QString: + { + QString strVal = value.toString(); + float floatVal = strVal.toFloat(); + QVariant fixedValue( floatVal ); + //TODO track down WHY we're getting unexpected QString values here...this is a workaround + qDebug() << "Unexpected string QVariant:" << key << " val:" << value << "fixedVal:" << fixedValue; + map.value(compId)->insert(key, fixedValue); + } + break; + default: + qCritical() << "ABORTED PARAM UPDATE, NO VALID QVARIANT TYPE"; + return; + } +} + +void UASParameterDataModel::addComponent(int compId) +{ + if (!onboardParameters.contains(compId)) { + onboardParameters.insert(compId, new QMap()); + } + if (!pendingParameters.contains(compId)) { + pendingParameters.insert(compId, new QMap()); + } +} + + +void UASParameterDataModel::handleParamUpdate(int compId, const QString ¶mName, const QVariant &value) +{ + //verify that the value requested by the user matches the set value + //if it doesn't match, leave the pending parameter in the pending list! + if (pendingParameters.contains(compId)) { + QMap *pendingParams = pendingParameters.value(compId); + if ((NULL != pendingParams) && pendingParams->contains(paramName)) { + QVariant reqVal = pendingParams->value(paramName); + if (reqVal == value) { + //notify everyone that this item is being removed from the pending parameters list since it's now confirmed + removePendingParam(compId,paramName); + } + else { + qDebug() << "Pending commit for " << paramName << " want: " << reqVal << " got: " << value; + } + } + } + + emit parameterUpdated(compId,paramName,value); + setOnboardParam(compId,paramName,value); + +} + +bool UASParameterDataModel::getOnboardParamValue(int componentId, const QString& key, QVariant& value) const +{ + + if (onboardParameters.contains(componentId)) { + if (onboardParameters.value(componentId)->contains(key)) { + value = onboardParameters.value(componentId)->value(key); + return true; + } + } + + return false; +} + +int UASParameterDataModel::getDefaultComponentId() +{ + int result = 0; + + if (-1 != defaultComponentId) + return defaultComponentId; + + QList components = getComponentForOnboardParam("SYS_AUTOSTART");//TODO is this the best way to find the right component? + + // Guard against multiple components responding - this will never show in practice + if (1 == components.count()) { + result = components.first(); + defaultComponentId = result; + } + + qDebug() << "Default compId: " << result; + + return result; +} + +QList UASParameterDataModel::getComponentForOnboardParam(const QString& parameter) const +{ + QList components; + // Iterate through all components + foreach (int comp, onboardParameters.keys()) + { + if (onboardParameters.value(comp)->contains(parameter)) + components.append(comp); + } + + return components; +} + +void UASParameterDataModel::forgetAllOnboardParams() +{ + onboardParameters.clear(); +} + +void UASParameterDataModel::clearAllPendingParams() +{ + QList compIds = pendingParameters.keys(); + foreach (int compId , compIds) { + QMap* compParams = pendingParameters.value(compId); + QList paramNames = compParams->keys(); + foreach (QString paramName, paramNames) { + //remove this item from pending status and broadcast update + removePendingParam(compId,paramName); + } + } + +} + +void UASParameterDataModel::readUpdateParamsFromStream( QTextStream& stream) +{ + bool userWarned = false; + + while (!stream.atEnd()) { + QString line = stream.readLine(); + if (!line.startsWith("#")) { + QStringList wpParams = line.split("\t"); + int lineMavId = wpParams.at(0).toInt(); + if (wpParams.size() == 5) { + // Only load parameters for right mav + if (!userWarned && (uasId != lineMavId)) { + //TODO warn the user somehow ?? Appears these are saved currently with mav ID 0 but mav ID is often nonzero? + QString msg = tr("The parameters in the stream have been saved from system %1, but the currently selected system has the ID %2.").arg(lineMavId).arg(uasId); + qWarning() << msg ; + //MainWindow::instance()->showCriticalMessage( + // tr("Parameter loading warning"), + // tr("The parameters from the file %1 have been saved from system %2, but the currently selected system has the ID %3. If this is unintentional, please click on to revert to the parameters that are currently onboard").arg(fileName).arg(wpParams.at(0).toInt()).arg(mav->getUASID())); + userWarned = true; + } + + bool changed = false; + int componentId = wpParams.at(1).toInt(); + QString key = wpParams.at(2); + QString valStr = wpParams.at(3); + double dblVal = wpParams.at(3).toDouble(); + uint paramType = wpParams.at(4).toUInt(); + + + if (!onboardParameters.contains(componentId)) { + addComponent(componentId); + changed = true; + } + else { + QMap* compParams = onboardParameters.value(componentId); + if (!compParams->contains(key) || + (fabs((static_cast(compParams->value(key).toDouble())) - (dblVal)) > 2.0f * FLT_EPSILON)) { + changed = true; + qDebug() << "Changed" << key << "VAL" << dblVal; + } + } + + + if (changed) { + switch (paramType) + { + case MAV_PARAM_TYPE_REAL32: + updatePendingParamWithValue(componentId,key,QVariant(valStr.toFloat())); + break; + case MAV_PARAM_TYPE_UINT32: + updatePendingParamWithValue(componentId,key, QVariant(valStr.toUInt())); + break; + case MAV_PARAM_TYPE_INT32: + updatePendingParamWithValue(componentId,key,QVariant(valStr.toInt())); + break; + default: + qDebug() << "FAILED LOADING PARAM" << key << "UNKNOWN DATA TYPE"; + } + } + + + } + } + } + +} + +void UASParameterDataModel::writeOnboardParamsToStream( QTextStream &stream, const QString& name) +{ + stream << "# Onboard parameters for system " << name << "\n"; + stream << "#\n"; + stream << "# MAV ID COMPONENT ID PARAM NAME VALUE (FLOAT)\n"; + + // Iterate through all components, through all parameters and emit them + QMap*>::iterator i; + for (i = onboardParameters.begin(); i != onboardParameters.end(); ++i) { + // Iterate through the parameters of the component + int compid = i.key(); + QMap* comp = i.value(); + { + QMap::iterator j; + for (j = comp->begin(); j != comp->end(); ++j) + { + QString paramValue("%1"); + QString paramType("%1"); + switch ((int)j.value().type()) + { + case QVariant::Int: + paramValue = paramValue.arg(j.value().toInt()); + paramType = paramType.arg(MAV_PARAM_TYPE_INT32); + break; + case QVariant::UInt: + paramValue = paramValue.arg(j.value().toUInt()); + paramType = paramType.arg(MAV_PARAM_TYPE_UINT32); + break; + case QMetaType::Float: + // We store parameters as floats, with only 6 digits of precision guaranteed for decimal string conversion + // (see IEEE 754, 32 bit single-precision) + paramValue = paramValue.arg((double)j.value().toFloat(), 25, 'g', 6); + paramType = paramType.arg(MAV_PARAM_TYPE_REAL32); + break; + default: + qCritical() << "ABORTED PARAM WRITE TO FILE, NO VALID QVARIANT TYPE" << j.value(); + return; + } + stream << this->uasId << "\t" << compid << "\t" << j.key() << "\t" << paramValue << "\t" << paramType << "\n"; + stream.flush(); + } + } + } +} + + +void UASParameterDataModel::loadParamMetaInfoFromStream(QTextStream& stream) +{ + + // First line is header + // there might be more lines, but the first + // line is assumed to be at least header + QString header = stream.readLine(); + + // Ignore top-level comment lines + while (header.startsWith('#') || header.startsWith('/') + || header.startsWith('=') || header.startsWith('^')) + { + header = stream.readLine(); + } + + bool charRead = false; + QString separator = ""; + QList sepCandidates; + sepCandidates << '\t'; + sepCandidates << ','; + sepCandidates << ';'; + //sepCandidates << ' '; + sepCandidates << '~'; + sepCandidates << '|'; + + // Iterate until separator is found + // or full header is parsed + for (int i = 0; i < header.length(); i++) + { + if (sepCandidates.contains(header.at(i))) + { + // Separator found + if (charRead) + { + separator += header[i]; + } + } + else + { + // Char found + charRead = true; + // If the separator is not empty, this char + // has been read after a separator, so detection + // is now complete + if (separator != "") break; + } + } + + bool stripFirstSeparator = false; + bool stripLastSeparator = false; + + // Figure out if the lines start with the separator (e.g. wiki syntax) + if (header.startsWith(separator)) stripFirstSeparator = true; + + // Figure out if the lines end with the separator (e.g. wiki syntax) + if (header.endsWith(separator)) stripLastSeparator = true; + + QString out = separator; + out.replace("\t", ""); + //qDebug() << " Separator: \"" << out << "\""; + //qDebug() << "READING CSV:" << header; + + + // Read data + while (!stream.atEnd()) + { + QString line = stream.readLine(); + + //qDebug() << "LINE PRE-STRIP" << line; + + // Strip separtors if necessary + if (stripFirstSeparator) line.remove(0, separator.length()); + if (stripLastSeparator) line.remove(line.length()-separator.length(), line.length()-1); + + //qDebug() << "LINE POST-STRIP" << line; + + // Keep empty parts here - we still have to act on them + QStringList parts = line.split(separator, QString::KeepEmptyParts); + + // Each line is: + // variable name, Min, Max, Default, Multiplier, Enabled (0 = no, 1 = yes), Comment + + + // Fill in min, max and default values + if (parts.count() > 1) + { + // min + paramMin.insert(parts.at(0).trimmed(), parts.at(1).toDouble()); + } + if (parts.count() > 2) + { + // max + paramMax.insert(parts.at(0).trimmed(), parts.at(2).toDouble()); + } + if (parts.count() > 3) + { + // default + paramDefault.insert(parts.at(0).trimmed(), parts.at(3).toDouble()); + } + // IGNORING 4 and 5 for now + if (parts.count() > 6) + { + // tooltip + paramDescriptions.insert(parts.at(0).trimmed(), parts.at(6).trimmed()); + qDebug() << "PARAM META:" << parts.at(0).trimmed(); + } + } +} + + void UASParameterDataModel::setParamDescriptions(const QMap& paramInfo) +{ + if (paramInfo.isEmpty()) { + qDebug() << __FILE__ << ":" << __LINE__ << "setParamDescriptions with empty"; + } + + paramDescriptions = paramInfo; +} + +bool UASParameterDataModel::isValueGreaterThanParamMax(const QString& paramName, double dblVal) +{ + if (paramMax.contains(paramName)) { + if (dblVal > paramMax.value(paramName)) + return true; + } + + return false; +} + +bool UASParameterDataModel::isValueLessThanParamMin(const QString& paramName, double dblVal) +{ + if (paramMin.contains(paramName)) { + if (dblVal < paramMin.value(paramName)) + return true; + } + + return false; + } + diff --git a/src/uas/UASParameterDataModel.h b/src/uas/UASParameterDataModel.h new file mode 100644 index 0000000000000000000000000000000000000000..c0b5b76379ce2185252310ae74b761c834dac60e --- /dev/null +++ b/src/uas/UASParameterDataModel.h @@ -0,0 +1,136 @@ +#ifndef UASPARAMETERDATAMODEL_H +#define UASPARAMETERDATAMODEL_H + +#include +#include +#include + +class QTextStream; + +class UASParameterDataModel : public QObject +{ + Q_OBJECT +public: + explicit UASParameterDataModel(QObject *parent = 0); + + + //Parameter meta info + bool isParamMinKnown(const QString& param) { return paramMin.contains(param); } + virtual bool isValueLessThanParamMin(const QString& param, double dblVal); + + bool isParamMaxKnown(const QString& param) { return paramMax.contains(param); } + virtual bool isValueGreaterThanParamMax(const QString& param, double dblVal); + + bool isParamDefaultKnown(const QString& param) { return paramDefault.contains(param); } + double getParamMin(const QString& param) { return paramMin.value(param, 0.0f); } + double getParamMax(const QString& param) { return paramMax.value(param, 0.0f); } + double getParamDefault(const QString& param) { return paramDefault.value(param, 0.0f); } + virtual QString getParamDescription(const QString& param) { return paramDescriptions.value(param, ""); } + virtual void setParamDescriptions(const QMap& paramInfo); + + /** @brief Get the default component ID for the UAS */ + virtual int getDefaultComponentId(); + + //TODO make this method protected? + /** @brief Ensure that the data model is aware of this component + * @param compId Id of the component + */ + virtual void addComponent(int compId); + + /** + * @brief Return a list of all components for this parameter name + * @param parameter The parameter string to search for + * @return A list with all components, can be potentially empty + */ + virtual QList getComponentForOnboardParam(const QString& parameter) const; + + + /** @brief clears every parameter for every loaded component */ + virtual void forgetAllOnboardParams(); + + + + /** @brief add this parameter to pending list iff it has changed from onboard value + * @return true if the parameter is now pending + */ + virtual bool updatePendingParamWithValue(int componentId, const QString &key, const QVariant &value, bool forceSend = false); + virtual void handleParamUpdate(int componentId, const QString& key, const QVariant& value); + virtual bool getOnboardParamValue(int componentId, const QString& key, QVariant& value) const; + + virtual bool isParamChangePending(int componentId,const QString& key); + + QMap* getPendingParamsForComponent(int componentId) { + return pendingParameters.value(componentId); + } + + QMap* getOnboardParamsForComponent(int componentId) { + return onboardParameters.value(componentId); + } + + QMap* >* getAllPendingParams() { + return &pendingParameters; + } + + QMap* >* getAllOnboardParams() { + return &onboardParameters; + } + + /** @brief return a count of all pending parameters */ + virtual int countPendingParams(); + + /** @brief return a count of all onboard parameters we've received */ + virtual int countOnboardParams(); + + virtual void writeOnboardParamsToStream(QTextStream &stream, const QString& uasName); + virtual void readUpdateParamsFromStream(QTextStream &stream); + + virtual void loadParamMetaInfoFromStream(QTextStream& stream); + + void setUASID(int anId) { this->uasId = anId; } + +protected: + /** @brief set the confirmed value of a parameter in the onboard params list */ + virtual void setOnboardParam(int componentId, const QString& key, const QVariant& value); + + /** @brief Save the parameter with a the type specified in the QVariant as fixed */ + void setParamWithTypeInMap(int compId, const QString& key, const QVariant &value, QMap* >& map); + + /** @brief Write a new pending parameter value that may be eventually sent to the UAS */ + virtual void setPendingParam(int componentId, const QString &key, const QVariant& value); + /** @brief remove a parameter from the pending list */ + virtual void removePendingParam(int compId, const QString &key); + + +signals: + + /** @brief We've received an update of a parameter's value */ + void parameterUpdated(int compId, QString paramName, QVariant value); + + /** @brief Notifies listeners that a param was added to or removed from the pending list */ + void pendingParamUpdate(int compId, const QString& paramName, QVariant value, bool isPending); + + void allPendingParamsCommitted(); ///< All pending params have been committed to the MAV + +public slots: + + virtual void clearAllPendingParams(); + +protected: + int defaultComponentId; ///< Cached default component ID + + int uasId; ///< The UAS / MAV to which this data model pertains + QMap* > pendingParameters; ///< Changed values that have not yet been transmitted to the UAS, by component ID + QMap* > onboardParameters; ///< All parameters confirmed to be stored onboard the UAS, by component ID + + // Tooltip data structures + QMap paramDescriptions; ///< Tooltip values + + // Min / Default / Max data structures + QMap paramMin; ///< Minimum param values + QMap paramDefault; ///< Default param values + QMap paramMax; ///< Minimum param values + + +}; + +#endif // UASPARAMETERDATAMODEL_H diff --git a/src/uas/UASWaypointManager.cc b/src/uas/UASWaypointManager.cc index d6bdb29b866bca719a20fd27ab2e6ea1bc86debe..888a548e707cf80f7f696e12be379991bccefcb9 100644 --- a/src/uas/UASWaypointManager.cc +++ b/src/uas/UASWaypointManager.cc @@ -975,7 +975,9 @@ void UASWaypointManager::sendWaypointRequestList() wprl.target_system = uasid; wprl.target_component = MAV_COMP_ID_MISSIONPLANNER; - emit updateStatusString(QString("Requesting waypoint list...")); + QString statusMsg(tr("Requesting waypoint list...")); + qDebug() << __FILE__ << __LINE__ << statusMsg; + emit updateStatusString(statusMsg); mavlink_msg_mission_request_list_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, &wprl); uas->sendMessage(message); diff --git a/src/uas/senseSoarMAV.cpp b/src/uas/senseSoarMAV.cpp index fc1ad320310d8d65e609c08e9c8b6f9a8ee9edc7..fee48386293e4b015bfd3ebee84f1a968cddb3ad 100644 --- a/src/uas/senseSoarMAV.cpp +++ b/src/uas/senseSoarMAV.cpp @@ -1,4 +1,5 @@ #include "senseSoarMAV.h" +#include #include senseSoarMAV::senseSoarMAV(MAVLinkProtocol* mavlink, int id) @@ -207,8 +208,8 @@ void senseSoarMAV::receiveMessage(LinkInterface *link, mavlink_message_t message void senseSoarMAV::quat2euler(const double *quat, double &roll, double &pitch, double &yaw) { - roll = std::atan2(2*(quat[0]*quat[1] + quat[2]*quat[3]),quat[0]*quat[0] - quat[1]*quat[1] - quat[2]*quat[2] + quat[3]*quat[3]); - pitch = std::asin(qMax(-1.0,qMin(1.0,2*(quat[0]*quat[2] - quat[1]*quat[3])))); - yaw = std::atan2(2*(quat[1]*quat[2] + quat[0]*quat[3]),quat[0]*quat[0] + quat[1]*quat[1] - quat[2]*quat[2] - quat[3]*quat[3]); + roll = atan2(2*(quat[0]*quat[1] + quat[2]*quat[3]),quat[0]*quat[0] - quat[1]*quat[1] - quat[2]*quat[2] + quat[3]*quat[3]); + pitch = asin(qMax(-1.0,qMin(1.0,2*(quat[0]*quat[2] - quat[1]*quat[3])))); + yaw = atan2(2*(quat[1]*quat[2] + quat[0]*quat[3]),quat[0]*quat[0] + quat[1]*quat[1] - quat[2]*quat[2] - quat[3]*quat[3]); return; } diff --git a/src/ui/CommConfigurationWindow.cc b/src/ui/CommConfigurationWindow.cc index b1fbac86e5ebe36232ded67f319358698c4573c9..5da03235691c3a64da884ff50ed0ee5702c664d5 100644 --- a/src/ui/CommConfigurationWindow.cc +++ b/src/ui/CommConfigurationWindow.cc @@ -40,6 +40,7 @@ This file is part of the QGROUNDCONTROL project #include "SerialConfigurationWindow.h" #include "SerialLink.h" #include "UDPLink.h" +#include "TCPLink.h" #include "MAVLinkSimulationLink.h" #ifdef XBEELINK #include "XbeeLink.h" @@ -52,38 +53,46 @@ This file is part of the QGROUNDCONTROL project #include "MAVLinkProtocol.h" #include "MAVLinkSettingsWidget.h" #include "QGCUDPLinkConfiguration.h" +#include "QGCTCPLinkConfiguration.h" #include "LinkManager.h" #include "MainWindow.h" -CommConfigurationWindow::CommConfigurationWindow(LinkInterface* link, ProtocolInterface* protocol, QWidget *parent) : QWidget(NULL) +CommConfigurationWindow::CommConfigurationWindow(LinkInterface* link, ProtocolInterface* protocol, QWidget *parent) : QDialog(parent) { this->link = link; // Setup the user interface according to link type ui.setupUi(this); - // Center the window on the screen. - QRect position = frameGeometry(); - position.moveCenter(QDesktopWidget().availableGeometry().center()); - move(position.topLeft()); - // Initialize basic ui state // Do not allow changes here unless advanced is checked ui.connectionType->setEnabled(false); - ui.linkType->setEnabled(false); ui.protocolGroupBox->setVisible(false); + ui.protocolTypeGroupBox->setVisible(false); // Connect UI element visibility to checkbox - connect(ui.advancedOptionsCheckBox, SIGNAL(clicked(bool)), ui.connectionType, SLOT(setEnabled(bool))); - connect(ui.advancedOptionsCheckBox, SIGNAL(clicked(bool)), ui.linkType, SLOT(setEnabled(bool))); - connect(ui.advancedOptionsCheckBox, SIGNAL(clicked(bool)), ui.protocolGroupBox, SLOT(setVisible(bool))); + //connect(ui.advancedOptionsCheckBox, SIGNAL(clicked(bool)), ui.connectionType, SLOT(setEnabled(bool))); + //connect(ui.advancedOptionsCheckBox, SIGNAL(clicked(bool)), ui.linkType, SLOT(setEnabled(bool))); + //connect(ui.advancedOptionsCheckBox, SIGNAL(clicked(bool)), ui.protocolGroupBox, SLOT(setVisible(bool))); + ui.advancedOptionsCheckBox->setVisible(false); + //connect(ui.advCheckBox,SIGNAL(clicked(bool)),ui.advancedOptionsCheckBox,SLOT(setChecked(bool))); + connect(ui.advCheckBox,SIGNAL(clicked(bool)),ui.protocolTypeGroupBox,SLOT(setVisible(bool))); + connect(ui.advCheckBox, SIGNAL(clicked(bool)), ui.connectionType, SLOT(setEnabled(bool))); + connect(ui.advCheckBox, SIGNAL(clicked(bool)), ui.protocolGroupBox, SLOT(setVisible(bool))); // add link types ui.linkType->addItem(tr("Serial"), QGC_LINK_SERIAL); ui.linkType->addItem(tr("UDP"), QGC_LINK_UDP); - ui.linkType->addItem(tr("Simulation"), QGC_LINK_SIMULATION); + ui.linkType->addItem(tr("TCP"), QGC_LINK_TCP); + if(dynamic_cast(link)) { + //Only show simulation option if already setup elsewhere as a simulation + ui.linkType->addItem(tr("Simulation"), QGC_LINK_SIMULATION); + } + +#ifdef OPAL_RT ui.linkType->addItem(tr("Opal-RT Link"), QGC_LINK_OPAL); +#endif #ifdef XBEELINK ui.linkType->addItem(tr("Xbee API"),QGC_LINK_XBEE); #endif // XBEELINK @@ -133,18 +142,26 @@ CommConfigurationWindow::CommConfigurationWindow(LinkInterface* link, ProtocolIn QWidget* conf = new SerialConfigurationWindow(serial, this); ui.linkScrollArea->setWidget(conf); ui.linkGroupBox->setTitle(tr("Serial Link")); - ui.linkType->setCurrentIndex(0); + ui.linkType->setCurrentIndex(ui.linkType->findData(QGC_LINK_SERIAL)); } UDPLink* udp = dynamic_cast(link); if (udp != 0) { QWidget* conf = new QGCUDPLinkConfiguration(udp, this); ui.linkScrollArea->setWidget(conf); ui.linkGroupBox->setTitle(tr("UDP Link")); - ui.linkType->setCurrentIndex(1); + ui.linkType->setCurrentIndex(ui.linkType->findData(QGC_LINK_UDP)); + } + TCPLink* tcp = dynamic_cast(link); + if (tcp != 0) { + QWidget* conf = new QGCTCPLinkConfiguration(tcp, this); + ui.linkScrollArea->setWidget(conf); + ui.linkGroupBox->setTitle(tr("TCP Link")); + ui.linkType->setCurrentIndex(ui.linkType->findData(QGC_LINK_TCP)); } MAVLinkSimulationLink* sim = dynamic_cast(link); if (sim != 0) { - ui.linkType->setCurrentIndex(2); + ui.linkType->setCurrentIndex(ui.linkType->findData(QGC_LINK_SIMULATION)); + ui.linkType->setEnabled(false); //Don't allow the user to change to a non-simulation ui.linkGroupBox->setTitle(tr("MAVLink Simulation Link")); } #ifdef OPAL_RT @@ -154,7 +171,7 @@ CommConfigurationWindow::CommConfigurationWindow(LinkInterface* link, ProtocolIn QBoxLayout* layout = new QBoxLayout(QBoxLayout::LeftToRight, ui.linkGroupBox); layout->addWidget(conf); ui.linkGroupBox->setLayout(layout); - ui.linkType->setCurrentIndex(3); + ui.linkType->setCurrentIndex(ui.linkType->findData(QGC_LINK_OPAL)); ui.linkGroupBox->setTitle(tr("Opal-RT Link")); } #endif @@ -165,12 +182,12 @@ CommConfigurationWindow::CommConfigurationWindow(LinkInterface* link, ProtocolIn QWidget* conf = new XbeeConfigurationWindow(xbee,this); ui.linkScrollArea->setWidget(conf); ui.linkGroupBox->setTitle(tr("Xbee Link")); - ui.linkType->setCurrentIndex(4); + ui.linkType->setCurrentIndex(ui.linkType->findData(QGC_LINK_XBEE)); connect(xbee,SIGNAL(tryConnectBegin(bool)),ui.actionConnect,SLOT(setDisabled(bool))); connect(xbee,SIGNAL(tryConnectEnd(bool)),ui.actionConnect,SLOT(setEnabled(bool))); } #endif // XBEELINK - if (serial == 0 && udp == 0 && sim == 0 + if (serial == 0 && udp == 0 && sim == 0 && tcp == 0 #ifdef OPAL_RT && opal == 0 #endif @@ -181,9 +198,7 @@ CommConfigurationWindow::CommConfigurationWindow(LinkInterface* link, ProtocolIn qDebug() << "Link is NOT a known link, can't open configuration window"; } -#ifdef XBEELINK - connect(ui.linkType,SIGNAL(currentIndexChanged(int)),this,SLOT(setLinkType(int))); -#endif // XBEELINK + connect(ui.linkType,SIGNAL(currentIndexChanged(int)),this,SLOT(linkCurrentIndexChanged(int))); // Open details pane for MAVLink if necessary MAVLinkProtocol* mavlink = dynamic_cast(protocol); @@ -213,7 +228,12 @@ QAction* CommConfigurationWindow::getAction() return action; } -void CommConfigurationWindow::setLinkType(int linktype) +void CommConfigurationWindow::linkCurrentIndexChanged(int currentIndex) +{ + setLinkType(static_cast(ui.linkType->itemData(currentIndex).toInt())); +} + +void CommConfigurationWindow::setLinkType(qgc_link_t linktype) { if(link->isConnected()) { @@ -230,7 +250,7 @@ void CommConfigurationWindow::setLinkType(int linktype) switch(linktype) { #ifdef XBEELINK - case 4: + case QGC_LINK_XBEE: { XbeeLink *xbee = new XbeeLink(); tmpLink = xbee; @@ -238,7 +258,7 @@ void CommConfigurationWindow::setLinkType(int linktype) break; } #endif // XBEELINK - case 1: + case QGC_LINK_UDP: { UDPLink *udp = new UDPLink(); tmpLink = udp; @@ -246,8 +266,16 @@ void CommConfigurationWindow::setLinkType(int linktype) break; } + case QGC_LINK_TCP: + { + TCPLink *tcp = new TCPLink(); + tmpLink = tcp; + MainWindow::instance()->addLink(tmpLink); + break; + } + #ifdef OPAL_RT - case 3: + case QGC_LINK_OPAL: { OpalLink* opal = new OpalLink(); tmpLink = opal; @@ -258,7 +286,7 @@ void CommConfigurationWindow::setLinkType(int linktype) default: { } - case 0: + case QGC_LINK_SERIAL: { SerialLink *serial = new SerialLink(); tmpLink = serial; diff --git a/src/ui/CommConfigurationWindow.h b/src/ui/CommConfigurationWindow.h index 4333e5ad622c3864f976bd3c0f524e6246660370..406331604cd9720c38418a8299ec196365e18e3d 100644 --- a/src/ui/CommConfigurationWindow.h +++ b/src/ui/CommConfigurationWindow.h @@ -33,7 +33,7 @@ This file is part of the QGROUNDCONTROL project #define _COMMCONFIGURATIONWINDOW_H_ #include -#include +#include #include #include "LinkInterface.h" #include "ProtocolInterface.h" @@ -42,12 +42,15 @@ This file is part of the QGROUNDCONTROL project enum qgc_link_t { QGC_LINK_SERIAL, QGC_LINK_UDP, + QGC_LINK_TCP, QGC_LINK_SIMULATION, QGC_LINK_FORWARDING, #ifdef XBEELINK QGC_LINK_XBEE, #endif +#ifdef OPAL_RT QGC_LINK_OPAL +#endif }; enum qgc_protocol_t { @@ -62,7 +65,7 @@ enum qgc_protocol_t { /** * @brief Configuration window for communication links */ -class CommConfigurationWindow : public QWidget +class CommConfigurationWindow : public QDialog { Q_OBJECT @@ -71,9 +74,12 @@ public: ~CommConfigurationWindow(); QAction* getAction(); + void setLinkType(qgc_link_t linktype); + +private slots: + void linkCurrentIndexChanged(int currentIndex); public slots: - void setLinkType(int linktype); /** @brief Set the protocol for this link */ void setProtocol(int protocol); void setConnection(); diff --git a/src/ui/CommSettings.ui b/src/ui/CommSettings.ui index ec9c2436d99bfdb0a861deba0832be704a3fba66..e04678c17aa92ae77e776d74776813402c00bbbb 100644 --- a/src/ui/CommSettings.ui +++ b/src/ui/CommSettings.ui @@ -6,85 +6,32 @@ 0 0 - 413 - 373 + 324 + 475 Form - - - 6 - - - 6 - - - 6 - - - 6 - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 5 - 5 - - - - - - - + + + + - Link Type + Link &Type: - - - - - - - - - Protocol - - - - - - - -1 + + linkType - - - - Advanced Options - - + + - - - - Qt::Horizontal - - - - + Link @@ -115,8 +62,8 @@ 0 0 - 391 - 85 + 298 + 90 @@ -125,7 +72,58 @@ - + + + + &Show Advanced Protocol Options + + + + + + + GroupBox + + + + + + + + -1 + + + + + + + &Protocol: + + + connectionType + + + + + + + &Advanced Options + + + + + + + + + + + + Qt::Horizontal + + + + Protocol @@ -156,8 +154,8 @@ 0 0 - 391 - 84 + 298 + 90 @@ -166,20 +164,7 @@ - - - - - 0 - 0 - - - - Disconnected - - - - + 12 @@ -193,7 +178,7 @@ Connect - true + false @@ -216,6 +201,19 @@ + + + + + 0 + 0 + + + + Disconnected + + + @@ -241,7 +239,26 @@ Close the configuration window + line + linkGroupBox + protocolGroupBox + connectionStatusLabel + advCheckBox + protocolTypeGroupBox + linkType + label + + linkType + linkScrollArea + advCheckBox + connectionType + advancedOptionsCheckBox + protocolScrollArea + connectButton + deleteButton + closeButton + diff --git a/src/ui/DebugConsole.cc b/src/ui/DebugConsole.cc index c89fc3811428bf224c11b8e75b01ea8688717575..311a87f140ec4a8190618e0632043682e4130e01 100644 --- a/src/ui/DebugConsole.cc +++ b/src/ui/DebugConsole.cc @@ -30,6 +30,7 @@ This file is part of the QGROUNDCONTROL project */ #include #include +#include #include "DebugConsole.h" #include "ui_DebugConsole.h" @@ -217,6 +218,7 @@ void DebugConsole::removeLink(LinkInterface* const linkInterface) } void DebugConsole::linkStatusUpdate(const QString& name,const QString& text) { + Q_UNUSED(name); m_ui->receiveText->appendPlainText(text); // Ensure text area scrolls correctly m_ui->receiveText->ensureCursorVisible(); @@ -312,9 +314,15 @@ void DebugConsole::receiveTextMessage(int id, int component, int severity, QStri break; } + //turn off updates while we're appending content to avoid breaking the autoscroll behavior + m_ui->receiveText->setUpdatesEnabled(false); + QScrollBar *scroller = m_ui->receiveText->verticalScrollBar(); + m_ui->receiveText->appendHtml(QString("(%2:%3) %4\n").arg(UASManager::instance()->getUASForId(id)->getColor().name(), name, comp, text)); + // Ensure text area scrolls correctly - m_ui->receiveText->ensureCursorVisible(); + scroller->setValue(scroller->maximum()); + m_ui->receiveText->setUpdatesEnabled(true); } } @@ -579,7 +587,7 @@ QString DebugConsole::bytesToSymbolNames(const QByteArray& b) } else if (b.contains(0x09)) { text = ""; } else if (b.contains((char)0x00)) { - text == ""; + text = ""; } else if (b.contains(0x1B)) { text = ""; } else if (b.contains(0x7E)) { @@ -688,7 +696,7 @@ void DebugConsole::sendBytes() str.append(specialSymbol); str.remove(' '); str.remove("0x"); - str.simplified(); + str = str.simplified(); int bufferIndex = 0; if ((str.size() % 2) == 0) { for (int i = 0; i < str.size(); i=i+2) { diff --git a/src/ui/HDDisplay.cc b/src/ui/HDDisplay.cc index fe6f2809339b0c46ad8731fdb58e40121dd03939..d3c12290aacc01b6db03377f51cc1f29d95e76aa 100644 --- a/src/ui/HDDisplay.cc +++ b/src/ui/HDDisplay.cc @@ -27,7 +27,7 @@ #include "MainWindow.h" #include -HDDisplay::HDDisplay(QStringList* plotList, QString title, QWidget *parent) : +HDDisplay::HDDisplay(const QStringList &plotList, QString title, QWidget *parent) : QGraphicsView(parent), uas(NULL), xCenterOffset(0.0f), @@ -60,11 +60,8 @@ HDDisplay::HDDisplay(QStringList* plotList, QString title, QWidget *parent) : setAutoFillBackground(true); // Add all items in accept list to gauge - if (plotList) { - for(int i = 0; i < plotList->length(); ++i) { - addGauge(plotList->at(i)); - } - } + for(int i = 0; i < plotList.length(); ++i) + addGauge(plotList.at(i)); restoreState(); // Set preferred size @@ -865,93 +862,36 @@ float HDDisplay::refLineWidthToPen(float line) // Connect a generic source void HDDisplay::addSource(QObject* obj) { - //genericSources.append(obj); - // FIXME XXX HACK -// if (plots.size() > 0) -// { - connect(obj, SIGNAL(valueChanged(int,QString,QString,qint8,quint64)), this, SLOT(updateValue(int,QString,QString,qint8,quint64))); - connect(obj, SIGNAL(valueChanged(int,QString,QString,quint8,quint64)), this, SLOT(updateValue(int,QString,QString,quint8,quint64))); - connect(obj, SIGNAL(valueChanged(int,QString,QString,qint16,quint64)), this, SLOT(updateValue(int,QString,QString,qint16,quint64))); - connect(obj, SIGNAL(valueChanged(int,QString,QString,quint16,quint64)), this, SLOT(updateValue(int,QString,QString,quint16,quint64))); - connect(obj, SIGNAL(valueChanged(int,QString,QString,qint32,quint64)), this, SLOT(updateValue(int,QString,QString,qint32,quint64))); - connect(obj, SIGNAL(valueChanged(int,QString,QString,quint32,quint64)), this, SLOT(updateValue(int,QString,QString,quint32,quint64))); - connect(obj, SIGNAL(valueChanged(int,QString,QString,quint64,quint64)), this, SLOT(updateValue(int,QString,QString,quint64,quint64))); - connect(obj, SIGNAL(valueChanged(int,QString,QString,qint64,quint64)), this, SLOT(updateValue(int,QString,QString,qint64,quint64))); - connect(obj, SIGNAL(valueChanged(int,QString,QString,double,quint64)), this, SLOT(updateValue(int,QString,QString,double,quint64))); -// } + connect(obj, SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)), this, SLOT(updateValue(int,QString,QString,QVariant,quint64))); } // Disconnect a generic source void HDDisplay::removeSource(QObject* obj) { - //genericSources.append(obj); - // FIXME XXX HACK -// if (plots.size() > 0) -// { - disconnect(obj, SIGNAL(valueChanged(int,QString,QString,qint8,quint64)), this, SLOT(updateValue(int,QString,QString,qint8,quint64))); - disconnect(obj, SIGNAL(valueChanged(int,QString,QString,quint8,quint64)), this, SLOT(updateValue(int,QString,QString,quint8,quint64))); - disconnect(obj, SIGNAL(valueChanged(int,QString,QString,qint16,quint64)), this, SLOT(updateValue(int,QString,QString,qint16,quint64))); - disconnect(obj, SIGNAL(valueChanged(int,QString,QString,quint16,quint64)), this, SLOT(updateValue(int,QString,QString,quint16,quint64))); - disconnect(obj, SIGNAL(valueChanged(int,QString,QString,qint32,quint64)), this, SLOT(updateValue(int,QString,QString,qint32,quint64))); - disconnect(obj, SIGNAL(valueChanged(int,QString,QString,quint32,quint64)), this, SLOT(updateValue(int,QString,QString,quint32,quint64))); - disconnect(obj, SIGNAL(valueChanged(int,QString,QString,quint64,quint64)), this, SLOT(updateValue(int,QString,QString,quint64,quint64))); - disconnect(obj, SIGNAL(valueChanged(int,QString,QString,qint64,quint64)), this, SLOT(updateValue(int,QString,QString,qint64,quint64))); - disconnect(obj, SIGNAL(valueChanged(int,QString,QString,double,quint64)), this, SLOT(updateValue(int,QString,QString,double,quint64))); -// } -} - -void HDDisplay::updateValue(const int uasId, const QString& name, const QString& unit, const qint8 value, const quint64 msec) -{ - if (!intValues.contains(name)) intValues.insert(name, true); - updateValue(uasId, name, unit, (double)value, msec); -} - -void HDDisplay::updateValue(const int uasId, const QString& name, const QString& unit, const quint8 value, const quint64 msec) -{ - if (!intValues.contains(name)) intValues.insert(name, true); - updateValue(uasId, name, unit, (double)value, msec); -} - -void HDDisplay::updateValue(const int uasId, const QString& name, const QString& unit, const qint16 value, const quint64 msec) -{ - if (!intValues.contains(name)) intValues.insert(name, true); - updateValue(uasId, name, unit, (double)value, msec); -} - -void HDDisplay::updateValue(const int uasId, const QString& name, const QString& unit, const quint16 value, const quint64 msec) -{ - if (!intValues.contains(name)) intValues.insert(name, true); - updateValue(uasId, name, unit, (double)value, msec); + disconnect(obj, SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)), this, SLOT(updateValue(int,QString,QString,QVariant,quint64))); } -void HDDisplay::updateValue(const int uasId, const QString& name, const QString& unit, const qint32 value, const quint64 msec) +void HDDisplay::updateValue(const int uasId, const QString& name, const QString& unit, const QVariant &variant, const quint64 msec) { - if (!intValues.contains(name)) intValues.insert(name, true); - updateValue(uasId, name, unit, (double)value, msec); -} + Q_UNUSED(uasId); + Q_UNUSED(unit); -void HDDisplay::updateValue(const int uasId, const QString& name, const QString& unit, const quint32 value, const quint64 msec) -{ - if (!intValues.contains(name)) intValues.insert(name, true); - updateValue(uasId, name, unit, (double)value, msec); -} + QMetaType::Type type = static_cast< QMetaType::Type>(variant.type()); + if(type == QMetaType::QByteArray || type == QMetaType::QString) + return; -void HDDisplay::updateValue(const int uasId, const QString& name, const QString& unit, const qint64 value, const quint64 msec) -{ - if (!intValues.contains(name)) intValues.insert(name, true); - updateValue(uasId, name, unit, (double)value, msec); -} + bool ok; + double value = variant.toDouble(&ok); + if(!ok) + return; -void HDDisplay::updateValue(const int uasId, const QString& name, const QString& unit, const quint64 value, const quint64 msec) -{ - if (!intValues.contains(name)) intValues.insert(name, true); - updateValue(uasId, name, unit, (double)value, msec); -} + if(type == QMetaType::Int || type == QMetaType::UInt || type == QMetaType::Long || type == QMetaType::LongLong + || type == QMetaType::Short || type == QMetaType::Char || type == QMetaType::ULong || type == QMetaType::ULongLong + || type == QMetaType::UShort || type == QMetaType::UChar || type == QMetaType::Bool ) { + if (!intValues.contains(name)) + intValues.insert(name, true); + } -void HDDisplay::updateValue(const int uasId, const QString& name, const QString& unit, const double value, const quint64 msec) -{ - Q_UNUSED(uasId); - Q_UNUSED(unit); // Update mean const float oldMean = valuesMean.value(name, 0.0f); const int meanCount = valuesCount.value(name, 0); diff --git a/src/ui/HDDisplay.h b/src/ui/HDDisplay.h index 39934957facc05078e65effc3a2593f6e8d296ad..e39090d7c499d1ee674345dfdf6adba954fea5e0 100644 --- a/src/ui/HDDisplay.h +++ b/src/ui/HDDisplay.h @@ -60,28 +60,12 @@ class HDDisplay : public QGraphicsView { Q_OBJECT public: - HDDisplay(QStringList* plotList, QString title="", QWidget *parent = 0); + HDDisplay(const QStringList& plotList, QString title="", QWidget *parent = 0); ~HDDisplay(); public slots: - /** @brief Update the HDD with new int8 data */ - void updateValue(const int uasId, const QString& name, const QString& unit, const qint8 value, const quint64 msec); - /** @brief Update the HDD with new uint8 data */ - void updateValue(const int uasId, const QString& name, const QString& unit, const quint8 value, const quint64 msec); - /** @brief Update the HDD with new int16 data */ - void updateValue(const int uasId, const QString& name, const QString& unit, const qint16 value, const quint64 msec); - /** @brief Update the HDD with new uint16 data */ - void updateValue(const int uasId, const QString& name, const QString& unit, const quint16 value, const quint64 msec); - /** @brief Update the HDD with new int32 data */ - void updateValue(const int uasId, const QString& name, const QString& unit, const qint32 value, const quint64 msec); - /** @brief Update the HDD with new uint32 data */ - void updateValue(const int uasId, const QString& name, const QString& unit, const quint32 value, const quint64 msec); - /** @brief Update the HDD with new int64 data */ - void updateValue(const int uasId, const QString& name, const QString& unit, const qint64 value, const quint64 msec); - /** @brief Update the HDD with new uint64 data */ - void updateValue(const int uasId, const QString& name, const QString& unit, const quint64 value, const quint64 msec); - /** @brief Update the HDD with new double data */ - void updateValue(const int uasId, const QString& name, const QString& unit, const double value, const quint64 msec); + /** @brief Update the HDD with new data */ + void updateValue(const int uasId, const QString& name, const QString& unit, const QVariant &value, const quint64 msec); virtual void setActiveUAS(UASInterface* uas); diff --git a/src/ui/HSIDisplay.cc b/src/ui/HSIDisplay.cc index d3a2a9d2a3ec2a0c749ec06a99a47d36eec66f42..4e05a479a6068578c6d521f623216e916f81289f 100644 --- a/src/ui/HSIDisplay.cc +++ b/src/ui/HSIDisplay.cc @@ -49,7 +49,7 @@ This file is part of the QGROUNDCONTROL project HSIDisplay::HSIDisplay(QWidget *parent) : - HDDisplay(NULL, "HSI", parent), + HDDisplay(QStringList(), "HSI", parent), dragStarted(false), leftDragStarted(false), mouseHasMoved(false), @@ -176,7 +176,8 @@ HSIDisplay::HSIDisplay(QWidget *parent) : setToolTip(tr("View from top in body frame. Scroll with mouse wheel to change the horizontal field of view of the widget.")); setStatusTip(tr("View from top in body frame. Scroll with mouse wheel to change the horizontal field of view of the widget.")); - connect(&statusClearTimer, SIGNAL(timeout()), this, SLOT(clearStatusMessage())); + // XXX this looks a potential recursive issue + //connect(&statusClearTimer, SIGNAL(timeout()), this, SLOT(clearStatusMessage())); if (UASManager::instance()->getActiveUAS()) { @@ -950,35 +951,60 @@ void HSIDisplay::setActiveUAS(UASInterface* uas) if (uas) { - connect(uas, SIGNAL(gpsSatelliteStatusChanged(int,int,float,float,float,bool)), this, SLOT(updateSatellite(int,int,float,float,float,bool))); - connect(uas, SIGNAL(localPositionChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateLocalPosition(UASInterface*,double,double,double,quint64))); - connect(uas, SIGNAL(globalPositionChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateGlobalPosition(UASInterface*,double,double,double,quint64))); - connect(uas, SIGNAL(attitudeThrustSetPointChanged(UASInterface*,double,double,double,double,quint64)), this, SLOT(updateAttitudeSetpoints(UASInterface*,double,double,double,double,quint64))); - connect(uas, SIGNAL(positionSetPointsChanged(int,float,float,float,float,quint64)), this, SLOT(updatePositionSetpoints(int,float,float,float,float,quint64))); - connect(uas, SIGNAL(userPositionSetPointsChanged(int,float,float,float,float)), this, SLOT(updateUserPositionSetpoints(int,float,float,float,float))); - connect(uas, SIGNAL(speedChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateSpeed(UASInterface*,double,double,double,quint64))); - connect(uas, SIGNAL(attitudeChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateAttitude(UASInterface*,double,double,double,quint64))); - - connect(uas, SIGNAL(attitudeControlEnabled(bool)), this, SLOT(updateAttitudeControllerEnabled(bool))); - connect(uas, SIGNAL(positionXYControlEnabled(bool)), this, SLOT(updatePositionXYControllerEnabled(bool))); - connect(uas, SIGNAL(positionZControlEnabled(bool)), this, SLOT(updatePositionZControllerEnabled(bool))); - connect(uas, SIGNAL(positionYawControlEnabled(bool)), this, SLOT(updatePositionYawControllerEnabled(bool))); - - connect(uas, SIGNAL(localizationChanged(UASInterface*,int)), this, SLOT(updateLocalization(UASInterface*,int))); - connect(uas, SIGNAL(visionLocalizationChanged(UASInterface*,int)), this, SLOT(updateVisionLocalization(UASInterface*,int))); - connect(uas, SIGNAL(gpsLocalizationChanged(UASInterface*,int)), this, SLOT(updateGpsLocalization(UASInterface*,int))); - connect(uas, SIGNAL(irUltraSoundLocalizationChanged(UASInterface*,int)), this, SLOT(updateInfraredUltrasoundLocalization(UASInterface*,int))); - connect(uas, SIGNAL(objectDetected(uint,int,int,QString,int,float,float)), this, SLOT(updateObjectPosition(uint,int,int,QString,int,float,float))); - - connect(uas, SIGNAL(gyroStatusChanged(bool,bool,bool)), this, SLOT(updateGyroStatus(bool,bool,bool))); - connect(uas, SIGNAL(accelStatusChanged(bool,bool,bool)), this, SLOT(updateAccelStatus(bool,bool,bool))); - connect(uas, SIGNAL(magSensorStatusChanged(bool,bool,bool)), this, SLOT(updateMagSensorStatus(bool,bool,bool))); - connect(uas, SIGNAL(baroStatusChanged(bool,bool,bool)), this, SLOT(updateBaroStatus(bool,bool,bool))); - connect(uas, SIGNAL(airspeedStatusChanged(bool,bool,bool)), this, SLOT(updateAirspeedStatus(bool,bool,bool))); - connect(uas, SIGNAL(opticalFlowStatusChanged(bool,bool,bool)), this, SLOT(updateOpticalFlowStatus(bool,bool,bool))); - connect(uas, SIGNAL(laserStatusChanged(bool,bool,bool)), this, SLOT(updateLaserStatus(bool,bool,bool))); - connect(uas, SIGNAL(groundTruthSensorStatusChanged(bool,bool,bool)), this, SLOT(updateGroundTruthSensorStatus(bool,bool,bool))); - connect(uas, SIGNAL(actuatorStatusChanged(bool,bool,bool)), this, SLOT(updateActuatorStatus(bool,bool,bool))); + connect(uas, SIGNAL(gpsSatelliteStatusChanged(int,int,float,float,float,bool)), + this, SLOT(updateSatellite(int,int,float,float,float,bool))); + connect(uas, SIGNAL(localPositionChanged(UASInterface*,double,double,double,quint64)), + this, SLOT(updateLocalPosition(UASInterface*,double,double,double,quint64))); + connect(uas, SIGNAL(globalPositionChanged(UASInterface*,double,double,double,quint64)), + this, SLOT(updateGlobalPosition(UASInterface*,double,double,double,quint64))); + connect(uas, SIGNAL(attitudeThrustSetPointChanged(UASInterface*,double,double,double,double,quint64)), + this, SLOT(updateAttitudeSetpoints(UASInterface*,double,double,double,double,quint64))); + connect(uas, SIGNAL(positionSetPointsChanged(int,float,float,float,float,quint64)), + this, SLOT(updatePositionSetpoints(int,float,float,float,float,quint64))); + connect(uas, SIGNAL(userPositionSetPointsChanged(int,float,float,float,float)), + this, SLOT(updateUserPositionSetpoints(int,float,float,float,float))); + connect(uas, SIGNAL(velocityChanged_NED(UASInterface*,double,double,double,quint64)), + this, SLOT(updateSpeed(UASInterface*,double,double,double,quint64))); + connect(uas, SIGNAL(attitudeChanged(UASInterface*,double,double,double,quint64)), + this, SLOT(updateAttitude(UASInterface*,double,double,double,quint64))); + connect(uas, SIGNAL(attitudeControlEnabled(bool)), + this, SLOT(updateAttitudeControllerEnabled(bool))); + connect(uas, SIGNAL(positionXYControlEnabled(bool)), + this, SLOT(updatePositionXYControllerEnabled(bool))); + connect(uas, SIGNAL(positionZControlEnabled(bool)), + this, SLOT(updatePositionZControllerEnabled(bool))); + connect(uas, SIGNAL(positionYawControlEnabled(bool)), + this, SLOT(updatePositionYawControllerEnabled(bool))); + + connect(uas, SIGNAL(localizationChanged(UASInterface*,int)), + this, SLOT(updateLocalization(UASInterface*,int))); + connect(uas, SIGNAL(visionLocalizationChanged(UASInterface*,int)), + this, SLOT(updateVisionLocalization(UASInterface*,int))); + connect(uas, SIGNAL(gpsLocalizationChanged(UASInterface*,int)), + this, SLOT(updateGpsLocalization(UASInterface*,int))); + connect(uas, SIGNAL(irUltraSoundLocalizationChanged(UASInterface*,int)), + this, SLOT(updateInfraredUltrasoundLocalization(UASInterface*,int))); + connect(uas, SIGNAL(objectDetected(uint,int,int,QString,int,float,float)), + this, SLOT(updateObjectPosition(uint,int,int,QString,int,float,float))); + + connect(uas, SIGNAL(gyroStatusChanged(bool,bool,bool)), + this, SLOT(updateGyroStatus(bool,bool,bool))); + connect(uas, SIGNAL(accelStatusChanged(bool,bool,bool)), + this, SLOT(updateAccelStatus(bool,bool,bool))); + connect(uas, SIGNAL(magSensorStatusChanged(bool,bool,bool)), + this, SLOT(updateMagSensorStatus(bool,bool,bool))); + connect(uas, SIGNAL(baroStatusChanged(bool,bool,bool)), + this, SLOT(updateBaroStatus(bool,bool,bool))); + connect(uas, SIGNAL(airspeedStatusChanged(bool,bool,bool)), + this, SLOT(updateAirspeedStatus(bool,bool,bool))); + connect(uas, SIGNAL(opticalFlowStatusChanged(bool,bool,bool)), + this, SLOT(updateOpticalFlowStatus(bool,bool,bool))); + connect(uas, SIGNAL(laserStatusChanged(bool,bool,bool)), + this, SLOT(updateLaserStatus(bool,bool,bool))); + connect(uas, SIGNAL(groundTruthSensorStatusChanged(bool,bool,bool)), + this, SLOT(updateGroundTruthSensorStatus(bool,bool,bool))); + connect(uas, SIGNAL(actuatorStatusChanged(bool,bool,bool)), + this, SLOT(updateActuatorStatus(bool,bool,bool))); statusClearTimer.start(3000); } else diff --git a/src/ui/Linechart.ui b/src/ui/Linechart.ui index 4a6a23e5ce399224210169f2f170d8d88ce67aa6..a46a5069117d415631d0e562afbe0a9999bc2e36 100644 --- a/src/ui/Linechart.ui +++ b/src/ui/Linechart.ui @@ -47,7 +47,7 @@ 10 - + 6 @@ -110,11 +110,18 @@ - + 2 + + + + Filter... (Ctrl+F) + + + diff --git a/src/ui/MAVLinkDecoder.h b/src/ui/MAVLinkDecoder.h index 7031882e4f044a0ff7e23ba354a91407649132ca..2feaa63978a386fa759e7c6345064ec014a2c10d 100644 --- a/src/ui/MAVLinkDecoder.h +++ b/src/ui/MAVLinkDecoder.h @@ -12,17 +12,7 @@ public: signals: void textMessageReceived(int uasid, int componentid, int severity, const QString& text); - void valueChanged(const int uasId, const QString& name, const QString& unit, const quint8 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const qint8 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const quint16 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const qint16 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const quint32 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const qint32 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const quint64 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const qint64 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const double value, const quint64 msec); - //void valueChanged(const int uasId, const QString& name, const QString& unit, const QVariant value, const quint64 msec); - + void valueChanged(const int uasId, const QString& name, const QString& unit, const QVariant& value, const quint64 msec); public slots: /** @brief Receive one message from the protocol and decode it */ diff --git a/src/ui/MainWindow.cc b/src/ui/MainWindow.cc index be1994fc6228ab9ba41c5ac30b9ca2bd2397bbb1..a958dc1ed9f7b27d9abfcb90baa675059ba8f23f 100644 --- a/src/ui/MainWindow.cc +++ b/src/ui/MainWindow.cc @@ -38,7 +38,7 @@ This file is part of the QGROUNDCONTROL project #include #include #include -#include "dockwidgettitlebareventfilter.h" +#include #include "QGC.h" #include "MAVLinkSimulationLink.h" #include "SerialLink.h" @@ -56,7 +56,6 @@ This file is part of the QGROUNDCONTROL project #include "MAVLinkDecoder.h" #include "QGCMAVLinkMessageSender.h" #include "QGCRGBDView.h" -#include "QGCFirmwareUpdate.h" #include "QGCStatusBar.h" #include "UASQuickView.h" #include "QGCDataPlot2D.h" @@ -65,6 +64,13 @@ This file is part of the QGROUNDCONTROL project #include "QGCTabbedInfoView.h" #include "UASRawStatusView.h" #include "PrimaryFlightDisplay.h" +#include +#include +#include +#include +#include "SerialSettingsDialog.h" +#include "terminalconsole.h" +#include "menuactionhelper.h" #ifdef QGC_OSG_ENABLED #include "Q3DWidgetFactory.h" @@ -119,12 +125,16 @@ MainWindow::MainWindow(QWidget *parent): darkStyleFileName(defaultDarkStyle), lightStyleFileName(defaultLightStyle), autoReconnect(false), + simulationLink(NULL), lowPowerMode(false), - isAdvancedMode(false), - dockWidgetTitleBarEnabled(true), - customMode(CUSTOM_MODE_NONE) + mavlink(new MAVLinkProtocol()), + customMode(CUSTOM_MODE_NONE), + menuActionHelper(new MenuActionHelper()) { this->setAttribute(Qt::WA_DeleteOnClose); + connect(menuActionHelper, SIGNAL(needToShowDockWidget(QString,bool)),SLOT(showDockWidget(QString,bool))); + //TODO: move protocol outside UI + connect(mavlink, SIGNAL(protocolStatusMessage(QString,QString)), this, SLOT(showCriticalMessage(QString,QString)), Qt::QueuedConnection); loadSettings(); } @@ -144,7 +154,7 @@ void MainWindow::init() if (settings.contains("ADVANCED_MODE")) { - isAdvancedMode = settings.value("ADVANCED_MODE").toBool(); + menuActionHelper->setAdvancedMode(settings.value("ADVANCED_MODE").toBool()); } if (!settings.contains("CURRENT_VIEW")) @@ -171,6 +181,7 @@ void MainWindow::init() // Setup user interface ui.setupUi(this); hide(); + menuActionHelper->setMenu(ui.menuTools); // We only need this menu if we have more than one system // ui.menuConnected_Systems->setEnabled(false); @@ -189,28 +200,34 @@ void MainWindow::init() centerStack = new QStackedWidget(this); setCentralWidget(centerStack); + // Load Toolbar - toolBar = new QGCToolBar(this); - this->addToolBar(toolBar); - - // Add actions for average users (displayed next to each other) - QList actions; - actions << ui.actionFlightView; - actions << ui.actionMissionView; - actions << ui.actionConfiguration_2; - toolBar->setPerspectiveChangeActions(actions); - - // Add actions for advanced users (displayed in dropdown under "advanced") - QList advancedActions; - advancedActions << ui.actionSimulation_View; - advancedActions << ui.actionEngineersView; - - toolBar->setPerspectiveChangeAdvancedActions(advancedActions); + if (!(getCustomMode() == CUSTOM_MODE_APM)) { + toolBar = new QGCToolBar(this); + this->addToolBar(toolBar); + + ui.actionHardwareConfig->setText(tr("Config")); + + // Add actions for average users (displayed next to each other) + QList actions; + actions << ui.actionFlightView; + actions << ui.actionMissionView; + actions << ui.actionHardwareConfig; + toolBar->setPerspectiveChangeActions(actions); + + // Add actions for advanced users (displayed in dropdown under "advanced") + QList advancedActions; + advancedActions << ui.actionSimulation_View; + advancedActions << ui.actionEngineersView; + + toolBar->setPerspectiveChangeAdvancedActions(advancedActions); + } + customStatusBar = new QGCStatusBar(this); setStatusBar(customStatusBar); statusBar()->setSizeGripEnabled(true); - emit initStatusChanged(tr("Building common widgets"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141)); + emit initStatusChanged(tr("Building common widgets."), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141)); buildCommonWidgets(); connectCommonWidgets(); @@ -230,6 +247,28 @@ void MainWindow::init() connect(LinkManager::instance(), SIGNAL(newLink(LinkInterface*)), this, SLOT(addLink(LinkInterface*))); + if (getCustomMode() == CUSTOM_MODE_APM) { + // Add the APM 'toolbar' + + APMToolBar *apmToolBar = new APMToolBar(this); + apmToolBar->setFlightViewAction(ui.actionFlightView); + apmToolBar->setFlightPlanViewAction(ui.actionMissionView); + apmToolBar->setHardwareViewAction(ui.actionHardwareConfig); + apmToolBar->setSoftwareViewAction(ui.actionSoftwareConfig); + apmToolBar->setSimulationViewAction(ui.actionSimulation_View); + apmToolBar->setTerminalViewAction(ui.actionTerminalView); + + QDockWidget *widget = new QDockWidget(tr("APM Tool Bar"),this); + widget->setWidget(apmToolBar); + widget->setMinimumHeight(72); + widget->setMaximumHeight(72); + widget->setMinimumWidth(1024); + widget->setFeatures(QDockWidget::NoDockWidgetFeatures); + widget->setTitleBarWidget(new QWidget(this)); // Disables the title bar + // /*widget*/->setStyleSheet("QDockWidget { border: 0px solid #FFFFFF; border-radius: 0px; border-bottom: 0px;}"); + this->addDockWidget(Qt::TopDockWidgetArea, widget); + } + // Connect user interface devices emit initStatusChanged(tr("Initializing joystick interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141)); joystickWidget = 0; @@ -310,11 +349,11 @@ MainWindow::~MainWindow() delete mavlink; mavlink = NULL; } - // if (simulationLink) - // { - // simulationLink->deleteLater(); - // simulationLink = NULL; - // } + if (simulationLink) + { + delete simulationLink; + simulationLink = NULL; + } if (joystick) { joystick->shutdown(); @@ -347,12 +386,8 @@ MainWindow::~MainWindow() } } // Delete all UAS objects - - - if (debugConsole) - { - delete debugConsole; - } + delete debugConsole; + delete menuActionHelper; for (int i=0;ideleteLater(); @@ -361,15 +396,6 @@ MainWindow::~MainWindow() void MainWindow::resizeEvent(QResizeEvent * event) { - if (width() > 1200) - { - toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - } - else - { - toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly); - } - QMainWindow::resizeEvent(event); } @@ -409,19 +435,8 @@ void MainWindow::buildCustomWidget() QSettings settings; settings.beginGroup("QGC_MAINWINDOW"); - /*QDockWidget* dock = new QDockWidget(tool->windowTitle(), this); - dock->setObjectName(tool->objectName()+"_DOCK"); - dock->setWidget(tool); - connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater())); - QAction* showAction = new QAction(widgets.at(i)->windowTitle(), this); - showAction->setCheckable(true); - connect(showAction, SIGNAL(triggered(bool)), dock, SLOT(setVisible(bool))); - connect(dock, SIGNAL(visibilityChanged(bool)), showAction, SLOT(setChecked(bool))); - widgets.at(i)->setMainMenuAction(showAction); - ui.menuTools->addAction(showAction);*/ - // Load dock widget location (default is bottom) - Qt::DockWidgetArea location = static_cast (tool->getDockWidgetArea(currentView)); + Qt::DockWidgetArea location = tool->getDockWidgetArea(currentView); //addDockWidget(location, dock); //dock->hide(); @@ -463,11 +478,10 @@ void MainWindow::buildCustomWidget() void MainWindow::buildCommonWidgets() { - //TODO: move protocol outside UI - mavlink = new MAVLinkProtocol(); - connect(mavlink, SIGNAL(protocolStatusMessage(QString,QString)), this, SLOT(showCriticalMessage(QString,QString)), Qt::QueuedConnection); // Add generic MAVLink decoder mavlinkDecoder = new MAVLinkDecoder(mavlink, this); + connect(mavlinkDecoder, SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)), + this, SIGNAL(valueChanged(int,QString,QString,QVariant,quint64))); // Log player logPlayer = new QGCMAVLinkLogPlayer(mavlink, customStatusBar); @@ -477,81 +491,92 @@ void MainWindow::buildCommonWidgets() if (!plannerView) { plannerView = new SubMainWindow(this); + plannerView->setObjectName("VIEW_MISSION"); plannerView->setCentralWidget(new QGCMapTool(this)); - //mapWidget = new QGCMapTool(this); - addCentralWidget(plannerView, "Maps"); + addToCentralStackedWidget(plannerView, VIEW_MISSION, "Maps"); } - //pilotView + //pilotView (aka Flight or Mission View) if (!pilotView) { pilotView = new SubMainWindow(this); pilotView->setObjectName("VIEW_FLIGHT"); pilotView->setCentralWidget(new QGCMapTool(this)); - addCentralWidget(pilotView, "Pilot"); + addToCentralStackedWidget(pilotView, VIEW_FLIGHT, "Pilot"); } - if (!configView) - { - configView = new SubMainWindow(this); - configView->setObjectName("VIEW_CONFIGURATION"); - configView->setCentralWidget(new QGCVehicleConfig(this)); - addCentralWidget(configView,"Config"); - centralWidgetToDockWidgetsMap[VIEW_CONFIGURATION] = QMap(); + if (getCustomMode() == CUSTOM_MODE_APM) { + if (!configView) + { + configView = new SubMainWindow(this); + configView->setObjectName("VIEW_HARDWARE_CONFIG"); + configView->setCentralWidget(new ApmHardwareConfig(this)); + addToCentralStackedWidget(configView, VIEW_HARDWARE_CONFIG, "Hardware"); + + } + if (!softwareConfigView) + { + softwareConfigView = new SubMainWindow(this); + softwareConfigView->setObjectName("VIEW_SOFTWARE_CONFIG"); + softwareConfigView->setCentralWidget(new ApmSoftwareConfig(this)); + addToCentralStackedWidget(softwareConfigView, VIEW_SOFTWARE_CONFIG, "Software"); + } + if (!terminalView) + { + terminalView = new SubMainWindow(this); + terminalView->setObjectName("VIEW_TERMINAL"); + TerminalConsole *terminalConsole = new TerminalConsole(this); + terminalView->setCentralWidget(terminalConsole); + addToCentralStackedWidget(terminalView, VIEW_TERMINAL, tr("Terminal View")); + } + } else { + if (!configView) + { + configView = new SubMainWindow(this); + configView->setObjectName("VIEW_HARDWARE_CONFIG"); + configView->setCentralWidget(new QGCConfigView(this)); + addToCentralStackedWidget(configView, VIEW_HARDWARE_CONFIG, "Config"); + } } + if (!engineeringView) { engineeringView = new SubMainWindow(this); engineeringView->setObjectName("VIEW_ENGINEER"); engineeringView->setCentralWidget(new QGCDataPlot2D(this)); - addCentralWidget(engineeringView,tr("Logfile Plot")); + addToCentralStackedWidget(engineeringView, VIEW_ENGINEER, tr("Logfile Plot")); } + if (!mavlinkView) { mavlinkView = new SubMainWindow(this); mavlinkView->setObjectName("VIEW_MAVLINK"); mavlinkView->setCentralWidget(new XMLCommProtocolWidget(this)); - addCentralWidget(mavlinkView,tr("Mavlink Generator")); + addToCentralStackedWidget(mavlinkView, VIEW_MAVLINK, tr("Mavlink Generator")); } + if (!simView) { simView = new SubMainWindow(this); simView->setObjectName("VIEW_SIMULATOR"); simView->setCentralWidget(new QGCMapTool(this)); - addCentralWidget(simView,tr("Simulation View")); + addToCentralStackedWidget(simView, VIEW_SIMULATION, tr("Simulation View")); } // Dock widgets - QAction* tempAction = ui.menuTools->addAction(tr("Control")); - tempAction->setCheckable(true); - connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool))); - createDockWidget(simView,new UASControlWidget(this),tr("Control"),"UNMANNED_SYSTEM_CONTROL_DOCKWIDGET",VIEW_SIMULATION,Qt::LeftDockWidgetArea); createDockWidget(plannerView,new UASListWidget(this),tr("Unmanned Systems"),"UNMANNED_SYSTEM_LIST_DOCKWIDGET",VIEW_MISSION,Qt::LeftDockWidgetArea); createDockWidget(plannerView,new QGCWaypointListMulti(this),tr("Mission Plan"),"WAYPOINT_LIST_DOCKWIDGET",VIEW_MISSION,Qt::BottomDockWidgetArea); - { - //createDockWidget(plannerView,new QGCWaypointListMulti(this),tr("Mission Plan"),"WAYPOINT_LIST_DOCKWIDGET",VIEW_MISSION,Qt::BottomDockWidgetArea); - QAction* tempAction = ui.menuTools->addAction(tr("Mission Plan")); - tempAction->setCheckable(true); - connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool))); - menuToDockNameMap[tempAction] = "WAYPOINT_LIST_DOCKWIDGET"; - } - createDockWidget(simView,new QGCWaypointListMulti(this),tr("Mission Plan"),"WAYPOINT_LIST_DOCKWIDGET",VIEW_SIMULATION,Qt::BottomDockWidgetArea); createDockWidget(engineeringView,new QGCMAVLinkInspector(mavlink,this),tr("MAVLink Inspector"),"MAVLINK_INSPECTOR_DOCKWIDGET",VIEW_ENGINEER,Qt::RightDockWidgetArea); createDockWidget(engineeringView,new ParameterInterface(this),tr("Onboard Parameters"),"PARAMETER_INTERFACE_DOCKWIDGET",VIEW_ENGINEER,Qt::RightDockWidgetArea); createDockWidget(simView,new ParameterInterface(this),tr("Onboard Parameters"),"PARAMETER_INTERFACE_DOCKWIDGET",VIEW_SIMULATION,Qt::RightDockWidgetArea); + menuActionHelper->createToolAction(tr("Status Details"), "UAS_STATUS_DETAILS_DOCKWIDGET"); - { - QAction* tempAction = ui.menuTools->addAction(tr("Status Details")); - menuToDockNameMap[tempAction] = "UAS_STATUS_DETAILS_DOCKWIDGET"; - tempAction->setCheckable(true); - connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool))); - } { if (!debugConsole) { @@ -559,38 +584,22 @@ void MainWindow::buildCommonWidgets() debugConsole->setWindowTitle("Communications Console"); debugConsole->hide(); QAction* tempAction = ui.menuTools->addAction(tr("Communication Console")); - //menuToDockNameMap[tempAction] = "COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET"; tempAction->setCheckable(true); connect(tempAction,SIGNAL(triggered(bool)),debugConsole,SLOT(setShown(bool))); - } } createDockWidget(simView,new HSIDisplay(this),tr("Horizontal Situation"),"HORIZONTAL_SITUATION_INDICATOR_DOCKWIDGET",VIEW_SIMULATION,Qt::BottomDockWidgetArea); - { - QAction* tempAction = ui.menuTools->addAction(tr("Flight Display")); - tempAction->setCheckable(true); - connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool))); - menuToDockNameMap[tempAction] = "HEAD_DOWN_DISPLAY_1_DOCKWIDGET"; - } - - { - QAction* tempAction = ui.menuTools->addAction(tr("Actuator Status")); - tempAction->setCheckable(true); - connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool))); - menuToDockNameMap[tempAction] = "HEAD_DOWN_DISPLAY_2_DOCKWIDGET"; - } + menuActionHelper->createToolAction(tr("Flight Display"), "HEAD_DOWN_DISPLAY_1_DOCKWIDGET"); + menuActionHelper->createToolAction(tr("Actuator Status"), "HEAD_DOWN_DISPLAY_2_DOCKWIDGET"); + menuActionHelper->createToolAction(tr("Radio Control")); - { - QAction* tempAction = ui.menuTools->addAction(tr("Radio Control")); - tempAction->setCheckable(true); - connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool))); - } + createDockWidget(engineeringView,new HUD(320,240,this),tr("Video Downlink"),"HEAD_UP_DISPLAY_DOCKWIDGET",VIEW_ENGINEER,Qt::RightDockWidgetArea,QSize(this->width()/1.5,0)); - createDockWidget(engineeringView,new HUD(320,240,this),tr("Video Downlink"),"HEAD_UP_DISPLAY_DOCKWIDGET",VIEW_ENGINEER,Qt::RightDockWidgetArea,this->width()/1.5); - createDockWidget(simView,new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",VIEW_SIMULATION,Qt::RightDockWidgetArea,this->width()/1.5); + createDockWidget(engineeringView,new HUD(320,240,this),tr("Video Downlink"),"HEAD_UP_DISPLAY_DOCKWIDGET",VIEW_ENGINEER,Qt::RightDockWidgetArea,QSize(this->width()/1.5,0)); - createDockWidget(pilotView,new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",VIEW_FLIGHT,Qt::LeftDockWidgetArea,this->width()/1.8); + createDockWidget(simView,new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",VIEW_SIMULATION,Qt::RightDockWidgetArea,QSize(this->width()/1.5,0)); + createDockWidget(pilotView,new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",VIEW_FLIGHT,Qt::LeftDockWidgetArea,QSize(this->width()/1.8,0)); QGCTabbedInfoView *infoview = new QGCTabbedInfoView(this); infoview->addSource(mavlinkDecoder); @@ -653,89 +662,60 @@ void MainWindow::buildCommonWidgets() }*/ #ifdef QGC_OSG_ENABLED - if (!_3DWidget) + if (q3DWidget) { - _3DWidget = Q3DWidgetFactory::get("PIXHAWK", this); - addCentralWidget(_3DWidget, tr("Local 3D")); + q3DWidget = Q3DWidgetFactory::get("PIXHAWK", this); + q3DWidget->setObjectName("VIEW_3DWIDGET"); + + addToCentralStackedWidget(q3DWidget, VIEW_3DWIDGET, tr("Local 3D")); } #endif #if (defined _MSC_VER) /*| (defined Q_OS_MAC) mac os doesn't support gearth right now */ - if (!gEarthWidget) + if (!earthWidget) { - gEarthWidget = new QGCGoogleEarthView(this); - addCentralWidget(gEarthWidget, tr("Google Earth")); + earthWidget = new QGCGoogleEarthView(this); + addToCentralStackedWidget(earthWidget,VIEW_GOOGLEEARTH, tr("Google Earth")); } #endif } void MainWindow::addTool(SubMainWindow *parent,VIEW_SECTIONS view,QDockWidget* widget, const QString& title, Qt::DockWidgetArea area) { - QList actionlist = ui.menuTools->actions(); - bool found = false; - QAction *targetAction; - for (int i=0;itext() == title) - { - found = true; - targetAction = actionlist[i]; - } - } - if (!found) - { - QAction* tempAction = ui.menuTools->addAction(title); - tempAction->setCheckable(true); - menuToDockNameMap[tempAction] = widget->objectName(); - if (!centralWidgetToDockWidgetsMap.contains(view)) - { - centralWidgetToDockWidgetsMap[view] = QMap(); - } - centralWidgetToDockWidgetsMap[view][widget->objectName()]= widget; - connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool))); - connect(widget, SIGNAL(visibilityChanged(bool)), tempAction, SLOT(setChecked(bool))); - tempAction->setChecked(widget->isVisible()); - } - else - { - if (!menuToDockNameMap.contains(targetAction)) - { - menuToDockNameMap[targetAction] = widget->objectName(); - //menuToDockNameMap[targetAction] = title; - } - if (!centralWidgetToDockWidgetsMap.contains(view)) - { - centralWidgetToDockWidgetsMap[view] = QMap(); - } - centralWidgetToDockWidgetsMap[view][widget->objectName()]= widget; - connect(widget, SIGNAL(visibilityChanged(bool)), targetAction, SLOT(setChecked(bool))); - } + menuActionHelper->createToolActionForCustomDockWidget(title, widget->objectName(), widget, view); parent->addDockWidget(area,widget); } -QDockWidget* MainWindow::createDockWidget(QWidget *parent,QWidget *child,QString title,QString objectname,VIEW_SECTIONS view,Qt::DockWidgetArea area,int minwidth,int minheight) +QDockWidget* MainWindow::createDockWidget(QWidget *subMainWindowParent,QWidget *child,const QString& title,const QString& objectName,VIEW_SECTIONS view,Qt::DockWidgetArea area,const QSize& minSize) { - child->setObjectName(objectname); - QDockWidget *widget = new QDockWidget(title,this); - dockWidgets.append(widget); - setDockWidgetTitleBar(widget); - widget->setObjectName(child->objectName()); - widget->setWidget(child); - if (minheight != 0 || minwidth != 0) - { - widget->setMinimumHeight(minheight); - widget->setMinimumWidth(minwidth); - } - addTool(qobject_cast(parent),view,widget,title,area); + SubMainWindow *parent = qobject_cast(subMainWindowParent); + Q_ASSERT(parent); + QDockWidget* dockWidget = menuActionHelper->createDockWidget(title, objectName); + child->setObjectName(objectName); + dockWidget->setWidget(child); //Set child objectName before setting dockwidget, since the dock widget might react to object name changes + connect(child, SIGNAL(destroyed()), dockWidget, SLOT(deleteLater())); //Our dockwidget only has only child widget, so kill the dock widget if the child is deleted - return widget; + if (minSize.height() >= 0) + dockWidget->setMinimumHeight(minSize.height()); + if (minSize.width() >= 0) + dockWidget->setMinimumWidth(minSize.width()); + addTool(parent,view,dockWidget,title,area); + return dockWidget; } -void MainWindow::loadDockWidget(QString name) + +void MainWindow::showDockWidget(const QString& name, bool show) { - if (centralWidgetToDockWidgetsMap[currentView].contains(name)) - { + QDockWidget *dockWidget = menuActionHelper->getDockWidget(currentView, name); + if(dockWidget) + dockWidget->setVisible(show); + else if (show) + loadDockWidget(name); +} + +void MainWindow::loadDockWidget(const QString& name) +{ + if(menuActionHelper->containsDockWidget(currentView, name)) return; - } if (name.startsWith("HIL_CONFIG")) { //It's a HIL widget. @@ -768,8 +748,6 @@ void MainWindow::loadDockWidget(QString name) else if (name == "COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET") { //This is now a permanently detached window. - //centralWidgetToDockWidgetsMap[currentView][name] = console; - //createDockWidget(centerStack->currentWidget(),new DebugConsole(this),tr("Communication Console"),"COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET",currentView,Qt::BottomDockWidgetArea); } else if (name == "HORIZONTAL_SITUATION_INDICATOR_DOCKWIDGET") { @@ -777,21 +755,19 @@ void MainWindow::loadDockWidget(QString name) } else if (name == "HEAD_DOWN_DISPLAY_1_DOCKWIDGET") { - //FIXME: memory of acceptList will never be freed again - QStringList* acceptList = new QStringList(); - acceptList->append("-3.3,ATTITUDE.roll,rad,+3.3,s"); - acceptList->append("-3.3,ATTITUDE.pitch,deg,+3.3,s"); - acceptList->append("-3.3,ATTITUDE.yaw,deg,+3.3,s"); + QStringList acceptList; + acceptList.append("-3.3,ATTITUDE.roll,rad,+3.3,s"); + acceptList.append("-3.3,ATTITUDE.pitch,deg,+3.3,s"); + acceptList.append("-3.3,ATTITUDE.yaw,deg,+3.3,s"); HDDisplay *hddisplay = new HDDisplay(acceptList,"Flight Display",this); hddisplay->addSource(mavlinkDecoder); createDockWidget(centerStack->currentWidget(),hddisplay,tr("Flight Display"),"HEAD_DOWN_DISPLAY_1_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); } else if (name == "HEAD_DOWN_DISPLAY_2_DOCKWIDGET") { - //FIXME: memory of acceptList2 will never be freed again - QStringList* acceptList2 = new QStringList(); - acceptList2->append("0,RAW_PRESSURE.pres_abs,hPa,65500"); - HDDisplay *hddisplay = new HDDisplay(acceptList2,"Actuator Status",this); + QStringList acceptList; + acceptList.append("0,RAW_PRESSURE.pres_abs,hPa,65500"); + HDDisplay *hddisplay = new HDDisplay(acceptList,"Actuator Status",this); hddisplay->addSource(mavlinkDecoder); createDockWidget(centerStack->currentWidget(),hddisplay,tr("Actuator Status"),"HEAD_DOWN_DISPLAY_2_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); } @@ -802,7 +778,6 @@ void MainWindow::loadDockWidget(QString name) } else if (name == "PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET") { - // createDockWidget(centerStack->currentWidget(),new HUD(320,240,this),tr("Head Up Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); createDockWidget(centerStack->currentWidget(),new PrimaryFlightDisplay(320,240,this),tr("Primary Flight Display"),"HEAD_UP_DISPLAY_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); } else if (name == "UAS_INFO_QUICKVIEW_DOCKWIDGET") @@ -823,97 +798,15 @@ void MainWindow::loadDockWidget(QString name) } } -void MainWindow::setDockWidgetTitleBar(QDockWidget* widget) -{ - QWidget* oldTitleBar = widget->titleBarWidget(); - - // In advanced mode, we use the default titlebar provided by Qt. - if (isAdvancedMode) - { - widget->setTitleBarWidget(0); - } - // Otherwise, if just a textlabel should be shown, make that the titlebar. - else if (dockWidgetTitleBarEnabled) - { - QLabel* label = new QLabel(this); - label->setText(widget->windowTitle()); - label->installEventFilter(new DockWidgetTitleBarEventFilter()); - widget->setTitleBarWidget(label); - } - // And if nothing should be shown, use an empty widget. - else - { - QWidget* newTitleBar = new QWidget(this); - widget->setTitleBarWidget(newTitleBar); - } - - // Be sure to clean up the old titlebar. When using QDockWidget::setTitleBarWidget(), - // it doesn't delete the old titlebar object. - if (oldTitleBar) - { - delete oldTitleBar; - } -} - -void MainWindow::showTool(bool show) -{ - //Called when a menu item is clicked on, regardless of view. - - QAction* act = qobject_cast(sender()); - if (menuToDockNameMap.contains(act)) - { - QString name = menuToDockNameMap[act]; - if (centralWidgetToDockWidgetsMap.contains(currentView)) - { - if (centralWidgetToDockWidgetsMap[currentView].contains(name)) - { - if (show) - { - centralWidgetToDockWidgetsMap[currentView][name]->show(); - } - else - { - centralWidgetToDockWidgetsMap[currentView][name]->hide(); - } - } - else if (show) - { - loadDockWidget(name); - } - } - } - //QWidget* widget = qVariantValue(act->data()); - //widget->setVisible(show); -} -/*void addToolByName(QString name,SubMainWindow parent,const QString& title, Qt::DockWidgetArea area) -{ - if (name == "Control") - { - QDockWidget *widget = new QDockWidget(tr("Control"),this); - dockToTitleBarMap[widget] = widget->titleBarWidget(); - widget->setObjectName("UNMANNED_SYSTEM_CONTROL_DOCKWIDGET"); - widget->setWidget(new UASControlWidget(this)); - addTool(parent,VIEW_SIMULATION,widget,tr("Control"),area); - } -}*/ -void MainWindow::addCentralWidget(QWidget* widget, const QString& title) +void MainWindow::addToCentralStackedWidget(QWidget* widget, VIEW_SECTIONS viewSection, const QString& title) { Q_UNUSED(title); + Q_ASSERT(widget->objectName().length() != 0); + // Check if this widget already has been added if (centerStack->indexOf(widget) == -1) { centerStack->addWidget(widget); - - // QAction* tempAction = ui.menuMain->addAction(title); - - // tempAction->setCheckable(true); - // QVariant var; - // var.setValue((QWidget*)widget); - // tempAction->setData(var); - // centerStackActionGroup->addAction(tempAction); - // connect(tempAction,SIGNAL(triggered()),this, SLOT(showCentralWidget())); - //connect(widget, SIGNAL(visibilityChanged(bool)), tempAction, SLOT(setChecked(bool))); - // tempAction->setChecked(widget->isVisible()); } } @@ -932,18 +825,11 @@ void MainWindow::showHILConfigurationWidget(UASInterface* uas) if (mav && !hilDocks.contains(mav->getUASID())) { - //QGCToolWidget* tool = new QGCToolWidget("Unnamed Tool " + QString::number(ui.menuTools->actions().size())); - //createDockWidget(centerStack->currentWidget(),tool,"Unnamed Tool " + QString::number(ui.menuTools->actions().size()),"UNNAMED_TOOL_" + QString::number(ui.menuTools->actions().size())+"DOCK",currentView,Qt::BottomDockWidgetArea); - QGCHilConfiguration* hconf = new QGCHilConfiguration(mav, this); - QString hilDockName = tr("HIL Config %1").arg(uas->getUASName()); - QDockWidget* hilDock = createDockWidget(simView, hconf,hilDockName, hilDockName.toUpper().replace(" ", "_"),VIEW_SIMULATION,Qt::LeftDockWidgetArea); + QString hilDockName = tr("HIL Config %1").arg(uas->getUASName()); + QString hilDockObjectName = QString("HIL_CONFIG_%1").arg(uas->getUASName().toUpper().replace(' ','_')); + QDockWidget* hilDock = createDockWidget(simView, hconf,hilDockName, hilDockObjectName,VIEW_SIMULATION,Qt::LeftDockWidgetArea); hilDocks.insert(mav->getUASID(), hilDock); - - // if (currentView != VIEW_SIMULATION) - // hilDock->hide(); - // else - // hilDock->show(); } } @@ -971,35 +857,28 @@ void MainWindow::connectCommonWidgets() void MainWindow::createCustomWidget() { - //void MainWindow::createDockWidget(QWidget *parent,QWidget *child,QString title,QString objectname,VIEW_SECTIONS view,Qt::DockWidgetArea area,int minwidth,int minheight) - //QDockWidget* dock = new QDockWidget("Unnamed Tool", this); - - if (QGCToolWidget::instances()->size() < 2) + if (QGCToolWidget::instances()->isEmpty()) { // This is the first widget ui.menuTools->addSeparator(); } - QGCToolWidget* tool = new QGCToolWidget("Unnamed Tool " + QString::number(ui.menuTools->actions().size())); - createDockWidget(centerStack->currentWidget(),tool,"Unnamed Tool " + QString::number(ui.menuTools->actions().size()),"UNNAMED_TOOL_" + QString::number(ui.menuTools->actions().size())+"DOCK",currentView,Qt::BottomDockWidgetArea); - //tool->setObjectName("UNNAMED_TOOL_" + QString::number(ui.menuTools->actions().size())); + QString objectName; + int customToolIndex = 0; + //Find the next unique object name that we can use + do { + ++customToolIndex; + objectName = QString("CUSTOM_TOOL_%1").arg(customToolIndex) + "DOCK"; + } while(QGCToolWidget::instances()->contains(objectName)); + + QString title = tr("Custom Tool %1").arg(customToolIndex ); + + QGCToolWidget* tool = new QGCToolWidget(objectName, title); + createDockWidget(centerStack->currentWidget(),tool,title,objectName,currentView,Qt::BottomDockWidgetArea); + QSettings settings; settings.beginGroup("QGC_MAINWINDOW"); settings.setValue(QString("TOOL_PARENT_") + tool->objectName(),currentView); settings.endGroup(); - - - - //connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater())); - //dock->setWidget(tool); - - //QAction* showAction = new QAction(tool->getTitle(), this); - //showAction->setCheckable(true); - //connect(dock, SIGNAL(visibilityChanged(bool)), showAction, SLOT(setChecked(bool))); - //connect(showAction, SIGNAL(triggered(bool)), dock, SLOT(setVisible(bool))); - //tool->setMainMenuAction(showAction); - //ui.menuTools->addAction(showAction); - //this->addDockWidget(Qt::BottomDockWidgetArea, dock); - //dock->setVisible(true); } void MainWindow::loadCustomWidget() @@ -1010,7 +889,7 @@ void MainWindow::loadCustomWidget() } void MainWindow::loadCustomWidget(const QString& fileName, int view) { - QGCToolWidget* tool = new QGCToolWidget("", this); + QGCToolWidget* tool = new QGCToolWidget("", "", this); if (tool->loadSettings(fileName, true)) { qDebug() << "Loading custom tool:" << tool->getTitle() << tool->objectName(); @@ -1029,16 +908,12 @@ void MainWindow::loadCustomWidget(const QString& fileName, int view) createDockWidget(plannerView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea); break; default: - { + { //Delete tool, create menu item to tie it to. customWidgetNameToFilenameMap[tool->objectName()+"DOCK"] = fileName; - QAction* tempAction = ui.menuTools->addAction(tool->getTitle()); - menuToDockNameMap[tempAction] = tool->objectName()+"DOCK"; - tempAction->setCheckable(true); - connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool))); + menuActionHelper->createToolAction(tool->getTitle(), tool->objectName()+"DOCK"); tool->deleteLater(); - //createDockWidget(centerStack->currentWidget(),tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea); - } + } break; } } @@ -1050,7 +925,7 @@ void MainWindow::loadCustomWidget(const QString& fileName, int view) void MainWindow::loadCustomWidget(const QString& fileName, bool singleinstance) { - QGCToolWidget* tool = new QGCToolWidget("", this); + QGCToolWidget* tool = new QGCToolWidget("", "", this); if (tool->loadSettings(fileName, true) || !singleinstance) { qDebug() << "Loading custom tool:" << tool->getTitle() << tool->objectName(); @@ -1074,35 +949,18 @@ void MainWindow::loadCustomWidget(const QString& fileName, bool singleinstance) createDockWidget(plannerView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea); break; default: - { + { //Delete tool, create menu item to tie it to. customWidgetNameToFilenameMap[tool->objectName()+"DOCK"] = fileName; - QAction* tempAction = ui.menuTools->addAction(tool->getTitle()); - menuToDockNameMap[tempAction] = tool->objectName()+"DOCK"; - tempAction->setCheckable(true); - connect(tempAction,SIGNAL(triggered(bool)),this, SLOT(showTool(bool))); + QAction *action = menuActionHelper->createToolAction(tool->getTitle(), tool->objectName()+"DOCK"); + ui.menuTools->addAction(action); tool->deleteLater(); - //createDockWidget(centerStack->currentWidget(),tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea); - } + } break; } settings.endGroup(); - // Add widget to UI - /*QDockWidget* dock = new QDockWidget(tool->getTitle(), this); - connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater())); - dock->setWidget(tool); - tool->setParent(dock); - - QAction* showAction = new QAction(tool->getTitle(), this); - showAction->setCheckable(true); - connect(dock, SIGNAL(visibilityChanged(bool)), showAction, SLOT(setChecked(bool))); - connect(showAction, SIGNAL(triggered(bool)), dock, SLOT(setVisible(bool))); - tool->setMainMenuAction(showAction); - ui.menuTools->addAction(showAction); - this->addDockWidget(Qt::BottomDockWidgetArea, dock); - dock->hide();*/ } else { @@ -1146,14 +1004,13 @@ void MainWindow::loadSettings() QSettings settings; settings.sync(); customMode = static_cast(settings.value("QGC_CUSTOM_MODE", (unsigned int)MainWindow::CUSTOM_MODE_NONE).toInt()); - qDebug() << "MAINWINDOW: CUSTOM MODE:" << customMode; settings.beginGroup("QGC_MAINWINDOW"); autoReconnect = settings.value("AUTO_RECONNECT", autoReconnect).toBool(); currentStyle = (QGC_MAINWINDOW_STYLE)settings.value("CURRENT_STYLE", currentStyle).toInt(); darkStyleFileName = settings.value("DARK_STYLE_FILENAME", darkStyleFileName).toString(); lightStyleFileName = settings.value("LIGHT_STYLE_FILENAME", lightStyleFileName).toString(); lowPowerMode = settings.value("LOW_POWER_MODE", lowPowerMode).toBool(); - dockWidgetTitleBarEnabled = settings.value("DOCK_WIDGET_TITLEBARS",dockWidgetTitleBarEnabled).toBool(); + bool dockWidgetTitleBarEnabled = settings.value("DOCK_WIDGET_TITLEBARS",menuActionHelper->dockWidgetTitleBarsEnabled()).toBool(); settings.endGroup(); enableDockWidgetTitleBars(dockWidgetTitleBarEnabled); } @@ -1180,6 +1037,7 @@ void MainWindow::storeSettings() } settings.setValue("LOW_POWER_MODE", lowPowerMode); settings.setValue("QGC_CUSTOM_MODE", (int)customMode); + QGCToolWidget::storeWidgetsToSettings(settings); settings.sync(); } @@ -1247,17 +1105,12 @@ void MainWindow::saveScreen() } void MainWindow::enableDockWidgetTitleBars(bool enabled) { - dockWidgetTitleBarEnabled = enabled; + menuActionHelper->setDockWidgetTitleBarsEnabled(enabled); QSettings settings; settings.beginGroup("QGC_MAINWINDOW"); - settings.setValue("DOCK_WIDGET_TITLEBARS",dockWidgetTitleBarEnabled); + settings.setValue("DOCK_WIDGET_TITLEBARS",enabled); settings.endGroup(); settings.sync(); - - for (int i = 0; i < dockWidgets.size(); i++) - { - setDockWidgetTitleBar(dockWidgets[i]); - } } void MainWindow::enableAutoReconnect(bool enabled) @@ -1294,7 +1147,6 @@ bool MainWindow::loadStyle(QGC_MAINWINDOW_STYLE style, QString cssFile) // And trigger any changes to other UI elements that are watching for // theme changes. emit styleChanged(style); - emit styleChanged(); // Finally restore the cursor before returning. qApp->restoreOverrideCursor(); @@ -1362,8 +1214,12 @@ void MainWindow::connectCommonActions() perspectives->addAction(ui.actionFlightView); perspectives->addAction(ui.actionSimulation_View); perspectives->addAction(ui.actionMissionView); - perspectives->addAction(ui.actionConfiguration_2); - perspectives->addAction(ui.actionFirmwareUpdateView); + //perspectives->addAction(ui.actionConfiguration_2); + perspectives->addAction(ui.actionHardwareConfig); + if (getCustomMode() == CUSTOM_MODE_APM) { + perspectives->addAction(ui.actionSoftwareConfig); + } + perspectives->addAction(ui.actionTerminalView); perspectives->addAction(ui.actionUnconnectedView); perspectives->setExclusive(true); @@ -1393,15 +1249,20 @@ void MainWindow::connectCommonActions() ui.actionMissionView->setChecked(true); ui.actionMissionView->activate(QAction::Trigger); } - if (currentView == VIEW_CONFIGURATION) + if (currentView == VIEW_HARDWARE_CONFIG) + { + ui.actionHardwareConfig->setChecked(true); + ui.actionHardwareConfig->activate(QAction::Trigger); + } + if (currentView == VIEW_SOFTWARE_CONFIG) { - ui.actionConfiguration_2->setChecked(true); - ui.actionConfiguration_2->activate(QAction::Trigger); + ui.actionSoftwareConfig->setChecked(true); + ui.actionSoftwareConfig->activate(QAction::Trigger); } - if (currentView == VIEW_FIRMWAREUPDATE) + if (currentView == VIEW_TERMINAL) { - ui.actionFirmwareUpdateView->setChecked(true); - ui.actionFirmwareUpdateView->activate(QAction::Trigger); + ui.actionTerminalView->setChecked(true); + ui.actionTerminalView->activate(QAction::Trigger); } if (currentView == VIEW_UNCONNECTED) { @@ -1418,8 +1279,8 @@ void MainWindow::connectCommonActions() // Connect actions from ui connect(ui.actionAdd_Link, SIGNAL(triggered()), this, SLOT(addLink())); - ui.actionAdvanced_Mode->setChecked(isAdvancedMode); - connect(ui.actionAdvanced_Mode,SIGNAL(triggered()),this,SLOT(setAdvancedMode())); + ui.actionAdvanced_Mode->setChecked(menuActionHelper->isAdvancedMode()); + connect(ui.actionAdvanced_Mode,SIGNAL(toggled(bool)),this,SLOT(setAdvancedMode(bool))); // Connect internal actions connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(UASCreated(UASInterface*))); @@ -1439,9 +1300,13 @@ void MainWindow::connectCommonActions() connect(ui.actionEngineersView, SIGNAL(triggered()), this, SLOT(loadEngineerView())); connect(ui.actionMissionView, SIGNAL(triggered()), this, SLOT(loadOperatorView())); connect(ui.actionUnconnectedView, SIGNAL(triggered()), this, SLOT(loadUnconnectedView())); - connect(ui.actionConfiguration_2,SIGNAL(triggered()),this,SLOT(loadConfigurationView())); + connect(ui.actionHardwareConfig,SIGNAL(triggered()),this,SLOT(loadHardwareConfigView())); + + if (getCustomMode() == CUSTOM_MODE_APM) { + connect(ui.actionSoftwareConfig,SIGNAL(triggered()),this,SLOT(loadSoftwareConfigView())); + connect(ui.actionTerminalView,SIGNAL(triggered()),this,SLOT(loadTerminalView())); + } - connect(ui.actionFirmwareUpdateView, SIGNAL(triggered()), this, SLOT(loadFirmwareUpdateView())); connect(ui.actionMavlinkView, SIGNAL(triggered()), this, SLOT(loadMAVLinkView())); // Help Actions @@ -1470,6 +1335,8 @@ void MainWindow::connectCommonActions() connect(ui.actionJoystickSettings, SIGNAL(triggered()), this, SLOT(configure())); // Application Settings connect(ui.actionSettings, SIGNAL(triggered()), this, SLOT(showSettings())); + + connect(ui.actionSimulate, SIGNAL(triggered(bool)), this, SLOT(simulateLink(bool))); } void MainWindow::showHelp() @@ -1533,7 +1400,7 @@ void MainWindow::showSettings() settings->show(); } -void MainWindow::addLink() +LinkInterface* MainWindow::addLink() { SerialLink* link = new SerialLink(); // TODO This should be only done in the dialog itself @@ -1555,15 +1422,50 @@ void MainWindow::addLink() break; } } + + return link; +} + + +bool MainWindow::configLink(LinkInterface *link) +{ + // Go searching for this link's configuration window + QList actions = ui.menuNetwork->actions(); + + bool found(false); + + const int32_t& linkIndex(LinkManager::instance()->getLinks().indexOf(link)); + const int32_t& linkID(LinkManager::instance()->getLinks()[linkIndex]->getId()); + + foreach (QAction* action, actions) + { + if (action->data().toInt() == linkID) + { // LinkManager::instance()->getLinks().indexOf(link) + found = true; + action->trigger(); // Show the Link Config Dialog + } + } + + return found; } void MainWindow::addLink(LinkInterface *link) { + + qDebug() << "ADD LINK CALLED FROM SOMEWHERE"; + // IMPORTANT! KEEP THESE TWO LINES // THEY MAKE SURE THE LINK IS PROPERLY REGISTERED // BEFORE LINKING THE UI AGAINST IT // Register (does nothing if already registered) LinkManager::instance()->add(link); + + if (mavlink) { + qDebug() << "MAVLINK OK"; + } else { + qDebug() << "MAVLINK FAIL"; + } + LinkManager::instance()->addProtocol(link, mavlink); // Go fishing for this link's configuration window @@ -1582,10 +1484,8 @@ void MainWindow::addLink(LinkInterface *link) } } - //UDPLink* udp = dynamic_cast(link); - if (!found) - { // || udp + { CommConfigurationWindow* commWidget = new CommConfigurationWindow(link, mavlink, this); commsWidgetList.append(commWidget); connect(commWidget,SIGNAL(destroyed(QObject*)),this,SLOT(commsWidgetDestroyed(QObject*))); @@ -1594,14 +1494,19 @@ void MainWindow::addLink(LinkInterface *link) // Error handling connect(link, SIGNAL(communicationError(QString,QString)), this, SLOT(showCriticalMessage(QString,QString)), Qt::QueuedConnection); - // Special case for simulationlink - MAVLinkSimulationLink* sim = dynamic_cast(link); - if (sim) - { - connect(ui.actionSimulate, SIGNAL(triggered(bool)), sim, SLOT(connectLink(bool))); - } } } + +void MainWindow::simulateLink(bool simulate) { + if (!simulationLink) + simulationLink = new MAVLinkSimulationLink(":/demo-log.txt"); + simulationLink->connectLink(simulate); +} + +//void MainWindow::configLink(LinkInterface *link) +//{ + +//} void MainWindow::commsWidgetDestroyed(QObject *obj) { if (commsWidgetList.contains(obj)) @@ -1738,6 +1643,7 @@ void MainWindow::UASCreated(UASInterface* uas) connect(uas, SIGNAL(systemSpecsChanged(int)), this, SLOT(UASSpecsChanged(int))); + connect(uas, SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)), this, SIGNAL(valueChanged(int,QString,QString,QVariant,quint64))); // HIL showHILConfigurationWidget(uas); @@ -1903,9 +1809,13 @@ void MainWindow::loadViewState() // Load defaults switch (currentView) { - case VIEW_CONFIGURATION: + case VIEW_HARDWARE_CONFIG: centerStack->setCurrentWidget(configView); break; + case VIEW_SOFTWARE_CONFIG: + if (softwareConfigView) + centerStack->setCurrentWidget(softwareConfigView); + break; case VIEW_ENGINEER: centerStack->setCurrentWidget(engineeringView); break; @@ -1915,9 +1825,9 @@ void MainWindow::loadViewState() case VIEW_MAVLINK: centerStack->setCurrentWidget(mavlinkView); break; - case VIEW_FIRMWAREUPDATE: - centerStack->setCurrentWidget(firmwareUpdateWidget); - break; +// case VIEW_FIRMWAREUPDATE: +// centerStack->setCurrentWidget(firmwareUpdateWidget); +// break; case VIEW_MISSION: centerStack->setCurrentWidget(plannerView); break; @@ -1926,6 +1836,10 @@ void MainWindow::loadViewState() centerStack->setCurrentWidget(simView); break; + case VIEW_TERMINAL: + centerStack->setCurrentWidget(terminalView); + break; + case VIEW_UNCONNECTED: case VIEW_FULL: default: @@ -1963,16 +1877,11 @@ void MainWindow::loadViewState() win->restoreState(settings.value(getWindowStateKey()).toByteArray(), QGC::applicationVersion()); } } -void MainWindow::setAdvancedMode() +void MainWindow::setAdvancedMode(bool isAdvancedMode) { - isAdvancedMode = !isAdvancedMode; + menuActionHelper->setAdvancedMode(isAdvancedMode); ui.actionAdvanced_Mode->setChecked(isAdvancedMode); settings.setValue("ADVANCED_MODE",isAdvancedMode); - - for (int i = 0; i < dockWidgets.size(); i++) - { - setDockWidgetTitleBar(dockWidgets[i]); - } } void MainWindow::loadEngineerView() @@ -1996,17 +1905,40 @@ void MainWindow::loadOperatorView() loadViewState(); } } -void MainWindow::loadConfigurationView() +void MainWindow::loadHardwareConfigView() +{ + if (currentView != VIEW_HARDWARE_CONFIG) + { + storeViewState(); + currentView = VIEW_HARDWARE_CONFIG; + ui.actionHardwareConfig->setChecked(true); + loadViewState(); + } +} + +void MainWindow::loadSoftwareConfigView() +{ + if (currentView != VIEW_SOFTWARE_CONFIG) + { + storeViewState(); + currentView = VIEW_SOFTWARE_CONFIG; + ui.actionSoftwareConfig->setChecked(true); + loadViewState(); + } +} + +void MainWindow::loadTerminalView() { - if (currentView != VIEW_CONFIGURATION) + if (currentView != VIEW_TERMINAL) { storeViewState(); - currentView = VIEW_CONFIGURATION; - ui.actionConfiguration_2->setChecked(true); + currentView = VIEW_TERMINAL; + ui.actionTerminalView->setChecked(true); loadViewState(); } } + void MainWindow::loadUnconnectedView() { if (currentView != VIEW_UNCONNECTED) @@ -2051,17 +1983,6 @@ void MainWindow::loadMAVLinkView() } } -void MainWindow::loadFirmwareUpdateView() -{ - if (currentView != VIEW_FIRMWAREUPDATE) - { - storeViewState(); - currentView = VIEW_FIRMWAREUPDATE; - ui.actionFirmwareUpdateView->setChecked(true); - loadViewState(); - } -} - //void MainWindow::loadDataView(QString fileName) //{ // // Plot is now selected, now load data from file @@ -2083,11 +2004,16 @@ void MainWindow::loadFirmwareUpdateView() //} -QList MainWindow::listLinkMenuActions(void) +QList MainWindow::listLinkMenuActions() { return ui.menuNetwork->actions(); } +bool MainWindow::dockWidgetTitleBarsEnabled() const +{ + return menuActionHelper->dockWidgetTitleBarsEnabled(); +} + #ifdef MOUSE_ENABLED_LINUX bool MainWindow::x11Event(XEvent *event) { diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h index 8876564a6267402c67f0ef288c8d1c91e7548dbc..cc98d0f1678e3493fb2a117bd0b71be18c021f53 100644 --- a/src/ui/MainWindow.h +++ b/src/ui/MainWindow.h @@ -30,7 +30,6 @@ This file is part of the QGROUNDCONTROL project #ifndef _MAINWINDOW_H_ #define _MAINWINDOW_H_ - #include #include #include @@ -87,6 +86,7 @@ class QGCStatusBar; class Linecharts; class QGCDataPlot2D; class JoystickWidget; +class MenuActionHelper; /** * @brief Main Application Window @@ -143,41 +143,38 @@ public: static const QString defaultLightStyle; /** @brief Get current visual style */ - QGC_MAINWINDOW_STYLE getStyle() + QGC_MAINWINDOW_STYLE getStyle() const { return currentStyle; } /** @brief Get current light visual stylesheet */ - QString getLightStyleSheet() + QString getLightStyleSheet() const { return lightStyleFileName; } /** @brief Get current dark visual stylesheet */ - QString getDarkStyleSheet() + QString getDarkStyleSheet() const { return darkStyleFileName; } /** @brief Get auto link reconnect setting */ - bool autoReconnectEnabled() + bool autoReconnectEnabled() const { return autoReconnect; } /** @brief Get title bar mode setting */ - bool dockWidgetTitleBarsEnabled() - { - return dockWidgetTitleBarEnabled; - } + bool dockWidgetTitleBarsEnabled() const; /** @brief Get low power mode setting */ - bool lowPowerModeEnabled() + bool lowPowerModeEnabled() const { return lowPowerMode; } - void setCustomMode(enum MainWindow::CUSTOM_MODE mode) + void setCustomMode(MainWindow::CUSTOM_MODE mode) { if (mode != CUSTOM_MODE_UNCHANGED) { @@ -185,12 +182,12 @@ public: } } - enum MainWindow::CUSTOM_MODE getCustomMode() + MainWindow::CUSTOM_MODE getCustomMode() const { return customMode; } - QList listLinkMenuActions(void); + QList listLinkMenuActions(); public slots: /** @brief Shows a status message on the bottom status bar */ @@ -205,9 +202,12 @@ public slots: /** @brief Show the application settings */ void showSettings(); /** @brief Add a communication link */ - void addLink(); + LinkInterface* addLink(); void addLink(LinkInterface* link); + bool configLink(LinkInterface *link); void configure(); + /** @brief Simulate a link */ + void simulateLink(bool simulate); /** @brief Set the currently controlled UAS */ void setActiveUAS(UASInterface* uas); @@ -222,9 +222,10 @@ public slots: void saveScreen(); /** @brief Sets advanced mode, allowing for editing of tool widget locations */ - void setAdvancedMode(); - /** @brief Load configuration view */ - void loadConfigurationView(); + void setAdvancedMode(bool isAdvancedMode); + /** @brief Load configuration views */ + void loadHardwareConfigView(); + void loadSoftwareConfigView(); /** @brief Load default view when no MAV is connected */ void loadUnconnectedView(); /** @brief Load view for pilot */ @@ -237,8 +238,8 @@ public slots: void loadOperatorView(); /** @brief Load MAVLink XML generator view */ void loadMAVLinkView(); - /** @brief Load firmware update view */ - void loadFirmwareUpdateView(); + /** @brief Load Terminal Console views */ + void loadTerminalView(); /** @brief Show the online help for users */ void showHelp(); @@ -251,6 +252,7 @@ public slots: void enableDockWidgetTitleBars(bool enabled); /** @brief Automatically reconnect last link */ void enableAutoReconnect(bool enabled); + /** @brief Save power by reducing update rates */ void enableLowPowerMode(bool enabled) { lowPowerMode = enabled; } /** @brief Load a specific style. @@ -279,16 +281,6 @@ public slots: /** @brief Load data view, allowing to plot flight data */ // void loadDataView(QString fileName); - /** - * @brief Shows a Docked Widget based on the action sender - * - * This slot is written to be used in conjunction with the addTool() function - * It shows the QDockedWidget based on the action sender - * - */ - void showTool(bool visible); - - /** * @brief Shows a Widget from the center stack based on the action sender * @@ -303,10 +295,15 @@ public slots: void commsWidgetDestroyed(QObject *obj); +protected slots: + void showDockWidget(const QString &name, bool show); + signals: void styleChanged(MainWindow::QGC_MAINWINDOW_STYLE newTheme); - void styleChanged(); void initStatusChanged(const QString& message, int alignment, const QColor &color); + /** Emitted when any value changes from any source */ + void valueChanged(const int uasId, const QString& name, const QString& unit, const QVariant& value, const quint64 msec); + #ifdef MOUSE_ENABLED_LINUX /** @brief Forward X11Event to catch 3DMouse inputs */ void x11EventOccured(XEvent *event); @@ -333,7 +330,11 @@ protected: VIEW_SIMULATION, VIEW_MAVLINK, VIEW_FIRMWAREUPDATE, - VIEW_CONFIGURATION, + VIEW_HARDWARE_CONFIG, + VIEW_SOFTWARE_CONFIG, + VIEW_TERMINAL, + VIEW_3DWIDGET, + VIEW_GOOGLEEARTH, VIEW_UNCONNECTED, ///< View in unconnected mode, when no UAS is available VIEW_FULL ///< All widgets shown at once } VIEW_SECTIONS; @@ -350,8 +351,9 @@ protected: * @param location The default location for the QDockedWidget in case there is no previous key in the settings */ void addTool(SubMainWindow *parent,VIEW_SECTIONS view,QDockWidget* widget, const QString& title, Qt::DockWidgetArea area); - void loadDockWidget(QString name); - QDockWidget* createDockWidget(QWidget *parent,QWidget *child,QString title,QString objectname,VIEW_SECTIONS view,Qt::DockWidgetArea area,int minwidth=0,int minheight=0); + void loadDockWidget(const QString &name); + + QDockWidget* createDockWidget(QWidget *subMainWindowParent,QWidget *child,const QString& title,const QString& objectname,VIEW_SECTIONS view,Qt::DockWidgetArea area,const QSize& minSize = QSize()); /** * @brief Adds an already instantiated QWidget to the center stack * @@ -363,7 +365,7 @@ protected: * @param widget The QWidget being added * @param title The entry that will appear in the Menu */ - void addCentralWidget(QWidget* widget, const QString& title); + void addToCentralStackedWidget(QWidget* widget, VIEW_SECTIONS viewSection, const QString& title); /** @brief Catch window resize events */ void resizeEvent(QResizeEvent * event); @@ -387,9 +389,8 @@ protected: void storeSettings(); // TODO Should be moved elsewhere, as the protocol does not belong to the UI - MAVLinkProtocol* mavlink; + QPointer mavlink; - MAVLinkSimulationLink* simulationLink; LinkInterface* udpLink; QSettings settings; @@ -400,9 +401,11 @@ protected: QPointer plannerView; QPointer pilotView; QPointer configView; + QPointer softwareConfigView; QPointer mavlinkView; QPointer engineeringView; QPointer simView; + QPointer terminalView; // Center widgets QPointer linechartWidget; @@ -412,10 +415,10 @@ protected: //QPointer protocolWidget; //QPointer dataplotWidget; #ifdef QGC_OSG_ENABLED - QPointer _3DWidget; + QPointer q3DWidget; #endif #if (defined _MSC_VER) || (defined Q_OS_MAC) - QPointer gEarthWidget; + QPointer earthWidget; #endif QPointer firmwareUpdateWidget; @@ -491,6 +494,7 @@ protected: QString darkStyleFileName; QString lightStyleFileName; bool autoReconnect; + MAVLinkSimulationLink* simulationLink; Qt::WindowStates windowStateVal; bool lowPowerMode; ///< If enabled, QGC reduces the update rates of all widgets QGCFlightGearLink* fgLink; @@ -500,11 +504,7 @@ protected: private: QList commsWidgetList; QMap customWidgetNameToFilenameMap; - QMap menuToDockNameMap; - QList dockWidgets; - QMap > centralWidgetToDockWidgetsMap; - bool isAdvancedMode; ///< If enabled dock widgets can be moved and floated. - bool dockWidgetTitleBarEnabled; ///< If enabled, dock widget titlebars are displayed when NOT in advanced mode. + MenuActionHelper *menuActionHelper; Ui::MainWindow ui; /** @brief Set the appropriate titlebar for a given dock widget. @@ -515,6 +515,7 @@ private: QString getWindowStateKey(); QString getWindowGeometryKey(); + friend class MenuActionHelper; //For VIEW_SECTIONS }; #endif /* _MAINWINDOW_H_ */ diff --git a/src/ui/MainWindow.ui b/src/ui/MainWindow.ui index 41fb9846a90aa862c4c32983e9beb1619ac81ab3..75a6e83ff4f3ac18177c5f4754f90c48ec935ee1 100644 --- a/src/ui/MainWindow.ui +++ b/src/ui/MainWindow.ui @@ -6,14 +6,14 @@ 0 0 - 800 - 500 + 1024 + 600 - 800 - 500 + 1024 + 600 @@ -50,8 +50,8 @@ 0 0 - 800 - 25 + 1024 + 22 @@ -97,7 +97,9 @@ - + + + @@ -275,7 +277,7 @@ - :/files/images/status/weather-overcast.svg:/files/images/status/weather-overcast.svg + :/files/images/categories/applications-internet.svg:/files/images/categories/applications-internet.svg Mission @@ -441,7 +443,7 @@ Open the simulation view - + true @@ -450,7 +452,7 @@ :/files/images/categories/preferences-system.svg:/files/images/categories/preferences-system.svg - Config + Hardware Configuration options of the vehicle. @@ -465,10 +467,41 @@ + + true + + + + :/files/images/apps/accessories-calculator.svg:/files/images/apps/accessories-calculator.svg + Simulation + + + true + + + + :/files/images/categories/applications-system.svg:/files/images/categories/applications-system.svg + + + Software + + + + + true + + + + :/files/images/apps/utilities-terminal.svg:/files/images/apps/utilities-terminal.svg + + + Terminal + + diff --git a/src/ui/ParameterInterface.cc b/src/ui/ParameterInterface.cc index ac0f1f097f69fc305e43897784946452c9257f63..52189789624a64952befd2b044345f1c2c229791 100644 --- a/src/ui/ParameterInterface.cc +++ b/src/ui/ParameterInterface.cc @@ -36,6 +36,8 @@ This file is part of the QGROUNDCONTROL project #include "QGCSensorSettingsWidget.h" #include +#include +#include "MainWindow.h" ParameterInterface::ParameterInterface(QWidget *parent) : QWidget(parent), @@ -45,6 +47,15 @@ ParameterInterface::ParameterInterface(QWidget *parent) : { m_ui->setupUi(this); + QSettings settings; + enum MainWindow::CUSTOM_MODE mode = static_cast(settings.value("QGC_CUSTOM_MODE", MainWindow::CUSTOM_MODE_NONE).toInt()); + + if (mode == MainWindow::CUSTOM_MODE_PX4) + { + delete m_ui->sensorSettings; + m_ui->sensorSettings = NULL; + } + // Get current MAV list QList systems = UASManager::instance()->getUASList(); @@ -61,13 +72,15 @@ ParameterInterface::ParameterInterface(QWidget *parent) : ParameterInterface::~ParameterInterface() { + delete paramWidgets; delete m_ui; } void ParameterInterface::selectUAS(int index) { m_ui->stackedWidget->setCurrentIndex(index); - m_ui->sensorSettings->setCurrentIndex(index); + if (m_ui->sensorSettings) + m_ui->sensorSettings->setCurrentIndex(index); curr = index; } @@ -77,19 +90,37 @@ void ParameterInterface::selectUAS(int index) */ void ParameterInterface::addUAS(UASInterface* uas) { - QGCParamWidget* param = new QGCParamWidget(uas, this); - paramWidgets->insert(uas->getUASID(), param); - m_ui->stackedWidget->addWidget(param); + int uasId = uas->getUASID(); + qDebug() << "ParameterInterface::addUAS : " << uasId ; + + if (paramWidgets->contains(uasId) ) { + return; + } + QGCParamWidget* paramWidget = new QGCParamWidget(this); + paramWidget = (QGCParamWidget*)paramWidget->initWithUAS(uas); - QGCSensorSettingsWidget* sensor = new QGCSensorSettingsWidget(uas, this); - m_ui->sensorSettings->addWidget(sensor); + QString ptrStr; + ptrStr.sprintf("QGCParamWidget %8p (parent %8p)", paramWidget,this); + qDebug() << "Created " << ptrStr << " for UAS id: " << uasId << " count: " << paramWidgets->count(); + + paramWidgets->insert(uasId, paramWidget); + m_ui->stackedWidget->addWidget(paramWidget); + + QGCSensorSettingsWidget* sensor = NULL; + + if (m_ui->sensorSettings) + { + sensor = new QGCSensorSettingsWidget(uas, this); + m_ui->sensorSettings->addWidget(sensor); + } // Set widgets as default if (curr == -1) { // Clear - m_ui->sensorSettings->setCurrentWidget(sensor); - m_ui->stackedWidget->setCurrentWidget(param); + if (m_ui->sensorSettings && sensor) + m_ui->sensorSettings->setCurrentWidget(sensor); + m_ui->stackedWidget->setCurrentWidget(paramWidget); curr = 0; } } diff --git a/src/ui/PrimaryFlightDisplay.cc b/src/ui/PrimaryFlightDisplay.cc index a68acdf545b3c351432dc1421bcb84146064b8a2..cce53d63126473ab90ec851af9a22682a0c8a439 100644 --- a/src/ui/PrimaryFlightDisplay.cc +++ b/src/ui/PrimaryFlightDisplay.cc @@ -169,18 +169,13 @@ PrimaryFlightDisplay::PrimaryFlightDisplay(int width, int height, QWidget *paren setMinimumSize(120, 80); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + setActiveUAS(UASManager::instance()->getActiveUAS()); + // Connect with UAS signal //connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(addUAS(UASInterface*))); connect(UASManager::instance(), SIGNAL(UASDeleted(UASInterface*)), this, SLOT(forgetUAS(UASInterface*))); connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*))); -// // Get a list of all existing UAS and - well attach to one of them. The first one. -// foreach (UASInterface* uas, UASManager::instance()->getUASList()) { -// addUAS(uas); -// } - - setActiveUAS(UASManager::instance()->getActiveUAS()); - // Refresh timer refreshTimer->setInterval(updateInterval); // connect(refreshTimer, SIGNAL(timeout()), this, SLOT(paintHUD())); @@ -267,15 +262,24 @@ void PrimaryFlightDisplay::forgetUAS(UASInterface* uas) { if (this->uas != NULL && this->uas == uas) { // Disconnect any previously connected active MAV - disconnect(this->uas, SIGNAL(attitudeChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateAttitude(UASInterface*, double, double, double, quint64))); - disconnect(this->uas, SIGNAL(attitudeChanged(UASInterface*,int,double,double,double,quint64)), this, SLOT(updateAttitude(UASInterface*,int,double, double, double, quint64))); - disconnect(this->uas, SIGNAL(waypointSelected(int,int)), this, SLOT(selectWaypoint(int, int))); - disconnect(this->uas, SIGNAL(primarySpeedChanged(UASInterface*, double, quint64)), this, SLOT(updatePrimarySpeed(UASInterface*,double,quint64))); - disconnect(this->uas, SIGNAL(gpsSpeedChanged(UASInterface*, double, quint64)), this, SLOT(updateGPSSpeed(UASInterface*,double,quint64))); - disconnect(this->uas, SIGNAL(climbRateChanged(UASInterface*, double, quint64)), this, SLOT(updateClimbRate(UASInterface*, AltitudeMeasurementSource, double, quint64))); - disconnect(this->uas, SIGNAL(primaryAltitudeChanged(UASInterface*, double, quint64)), this, SLOT(updatePrimaryAltitude(UASInterface*, double, quint64))); - disconnect(this->uas, SIGNAL(gpsAltitudeChanged(UASInterface*, double, quint64)), this, SLOT(updateGPSAltitude(UASInterface*, double, quint64))); - disconnect(this->uas, SIGNAL(navigationControllerErrorsChanged(UASInterface*, double, double, double)), this, SLOT(updateNavigationControllerErrors(UASInterface*, double, double, double))); + disconnect(this->uas, SIGNAL(attitudeChanged(UASInterface*,double,double,double,quint64)), + this, SLOT(updateAttitude(UASInterface*, double, double, double, quint64))); + disconnect(this->uas, SIGNAL(attitudeChanged(UASInterface*,int,double,double,double,quint64)), + this, SLOT(updateAttitude(UASInterface*,int,double, double, double, quint64))); + //disconnect(this->uas, SIGNAL(waypointSelected(int,int)), + // this, SLOT(selectWaypoint(int, int))); + disconnect(this->uas, SIGNAL(primarySpeedChanged(UASInterface*, double, quint64)), + this, SLOT(updatePrimarySpeed(UASInterface*,double,quint64))); + disconnect(this->uas, SIGNAL(gpsSpeedChanged(UASInterface*, double, quint64)), + this, SLOT(updateGPSSpeed(UASInterface*,double,quint64))); + disconnect(this->uas, SIGNAL(climbRateChanged(UASInterface*, double, quint64)), + this,SLOT(updateClimbRate(UASInterface*, double, quint64))); + disconnect(this->uas, SIGNAL(primaryAltitudeChanged(UASInterface*, double, quint64)), + this, SLOT(updatePrimaryAltitude(UASInterface*, double, quint64))); + disconnect(this->uas, SIGNAL(gpsAltitudeChanged(UASInterface*, double, quint64)), + this, SLOT(updateGPSAltitude(UASInterface*, double, quint64))); + disconnect(this->uas, SIGNAL(navigationControllerErrorsChanged(UASInterface*, double, double, double)), + this, SLOT(updateNavigationControllerErrors(UASInterface*, double, double, double))); //disconnect(this->uas, SIGNAL(batteryChanged(UASInterface*, double, double, double, int)), this, SLOT(updateBattery(UASInterface*, double, double, double, int))); //disconnect(this->uas, SIGNAL(statusChanged(UASInterface*,QString,QString)), this, SLOT(updateState(UASInterface*,QString))); @@ -293,6 +297,9 @@ void PrimaryFlightDisplay::forgetUAS(UASInterface* uas) */ void PrimaryFlightDisplay::setActiveUAS(UASInterface* uas) { + if (uas == this->uas) + return; //no need to rewire + // Disconnect the previous one (if any) forgetUAS(this->uas); @@ -311,10 +318,12 @@ void PrimaryFlightDisplay::setActiveUAS(UASInterface* uas) //connect(uas, SIGNAL(localPositionChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateLocalPosition(UASInterface*,double,double,double,quint64))); //connect(uas, SIGNAL(globalPositionChanged(UASInterface*,double,double,double,quint64)), this, SLOT(updateGlobalPosition(UASInterface*,double,double,double,quint64))); - connect(uas, SIGNAL(waypointSelected(int,int)), this, SLOT(selectWaypoint(int, int))); + //connect(uas, SIGNAL(waypointSelected(int,int)), this, + // SLOT(selectWaypoint(int, int))); connect(uas, SIGNAL(primarySpeedChanged(UASInterface*, double, quint64)), this, SLOT(updatePrimarySpeed(UASInterface*,double,quint64))); connect(uas, SIGNAL(gpsSpeedChanged(UASInterface*, double, quint64)), this, SLOT(updateGPSSpeed(UASInterface*,double,quint64))); - connect(uas, SIGNAL(climbRateChanged(UASInterface*, double, quint64)), this, SLOT(updateClimbRate(UASInterface*, AltitudeMeasurementSource, double, quint64))); + connect(uas, SIGNAL(climbRateChanged(UASInterface*, double, quint64)), this, + SLOT(updateClimbRate(UASInterface*, double, quint64))); connect(uas, SIGNAL(primaryAltitudeChanged(UASInterface*, double, quint64)), this, SLOT(updatePrimaryAltitude(UASInterface*, double, quint64))); connect(uas, SIGNAL(gpsAltitudeChanged(UASInterface*, double, quint64)), this, SLOT(updateGPSAltitude(UASInterface*, double, quint64))); connect(uas, SIGNAL(navigationControllerErrorsChanged(UASInterface*, double, double, double)), this, SLOT(updateNavigationControllerErrors(UASInterface*, double, double, double))); @@ -348,6 +357,7 @@ void PrimaryFlightDisplay::updateAttitude(UASInterface* uas, double roll, double if (yaw<0) yaw+=360; this->heading = yaw; } + } void PrimaryFlightDisplay::updateAttitude(UASInterface* uas, int component, double roll, double pitch, double yaw, quint64 timestamp) diff --git a/src/ui/QGCBaseParamWidget.cc b/src/ui/QGCBaseParamWidget.cc new file mode 100644 index 0000000000000000000000000000000000000000..f1d8d60a73c4c3f868ecb820074165b75a6716b0 --- /dev/null +++ b/src/ui/QGCBaseParamWidget.cc @@ -0,0 +1,129 @@ +#include "QGCBaseParamWidget.h" + +#include +#include +#include +#include > + +#include "QGCUASParamManager.h" +#include "UASInterface.h" + + +QGCBaseParamWidget::QGCBaseParamWidget(QWidget *parent) : + QWidget(parent), + mav(NULL), + paramMgr(NULL), + updatingParamNameLock("") +{ +} + +QGCBaseParamWidget* QGCBaseParamWidget::initWithUAS(UASInterface *uas) +{ + setUAS(uas); + return this; +} + +void QGCBaseParamWidget::setUAS(UASInterface* uas) +{ + if (uas != mav) { + if (mav) { + //TODO disconnect any connections as needed + disconnectViewSignalsAndSlots(); + disconnectFromParamManager(); + clearOnboardParamDisplay(); + clearPendingParamDisplay(); + } + + mav = uas; + + if (mav) { + connectToParamManager(); + connectViewSignalsAndSlots(); + layoutWidget(); + + paramMgr->requestParameterListIfEmpty(); + } + } + +} + + +void QGCBaseParamWidget::connectToParamManager() +{ + paramMgr = mav->getParamManager(); + //TODO route via paramManager instead? + // Listen to updated param signals from the data model + connect(paramMgr, SIGNAL(parameterUpdated(int, QString , QVariant )), + this, SLOT(handleOnboardParamUpdate(int,QString,QVariant))); + + connect(paramMgr, SIGNAL(pendingParamUpdate(int , const QString&, QVariant , bool )), + this, SLOT(handlePendingParamUpdate(int , const QString& , QVariant, bool ))); + + // Listen for param list reload finished + connect(paramMgr, SIGNAL(parameterListUpToDate()), + this, SLOT(handleOnboardParameterListUpToDate())); + + // Listen to communications status messages so we can display them + connect(paramMgr, SIGNAL(parameterStatusMsgUpdated(QString,int)), + this, SLOT(handleParamStatusMsgUpdate(QString , int ))); +} + + +void QGCBaseParamWidget::disconnectFromParamManager() +{ + disconnect(paramMgr, SIGNAL(parameterUpdated(int, QString , QVariant )), + this, SLOT(handleOnboardParamUpdate(int,QString,QVariant))); + + disconnect(paramMgr, SIGNAL(pendingParamUpdate(int , const QString&, QVariant , bool )), + this, SLOT(handlePendingParamUpdate(int , const QString& , QVariant, bool ))); + + disconnect(paramMgr, SIGNAL(parameterListUpToDate()), + this, SLOT(handleOnboardParameterListUpToDate())); + + // Listen to communications status messages so we can display them + disconnect(paramMgr, SIGNAL(parameterStatusMsgUpdated(QString,int)), + this, SLOT(handleParamStatusMsgUpdate(QString , int ))); + + paramMgr = NULL; +} + + + +void QGCBaseParamWidget::requestOnboardParamsUpdate() +{ + paramMgr->requestParameterList(); +} + + +void QGCBaseParamWidget::saveParametersToFile() +{ + if (!mav) + return; + QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "./parameters.txt", tr("Parameter File (*.txt)")); + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + return; + } + + QTextStream outstream(&file); + paramMgr->writeOnboardParamsToStream(outstream,mav->getUASName()); + file.close(); +} + + +void QGCBaseParamWidget::loadParametersFromFile() +{ + if (!mav) + return; + + QString fileName = QFileDialog::getOpenFileName(this, tr("Load File"), ".", tr("Parameter file (*.txt)")); + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return; + + QTextStream in(&file); + paramMgr->readPendingParamsFromStream(in); + file.close(); +} + + diff --git a/src/ui/QGCBaseParamWidget.h b/src/ui/QGCBaseParamWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..e9e1309d3c9f19f4322cd8beff67462d50d3615a --- /dev/null +++ b/src/ui/QGCBaseParamWidget.h @@ -0,0 +1,59 @@ +#ifndef QGCBASEPARAMWIDGET_H +#define QGCBASEPARAMWIDGET_H + +#include +#include + + + + +//forward declarations +class QGCUASParamManager; +class UASInterface; + + +class QGCBaseParamWidget : public QWidget +{ + Q_OBJECT +public: + explicit QGCBaseParamWidget(QWidget *parent = 0); + virtual QGCBaseParamWidget* initWithUAS(UASInterface* uas);///< Two-stage construction: initialize this object + virtual void setUAS(UASInterface* uas);///< Allows swapping the underlying UAS + +protected: + virtual void setParameterStatusMsg(const QString& msg) = 0; + virtual void layoutWidget() = 0;///< Layout the appearance of this widget + virtual void connectViewSignalsAndSlots() = 0;///< Connect view signals/slots as needed + virtual void disconnectViewSignalsAndSlots() = 0;///< Disconnect view signals/slots as needed + virtual void connectToParamManager(); ///>Connect to any required param manager signals + virtual void disconnectFromParamManager(); ///< Disconnect from any connected param manager signals + +signals: + +public slots: + virtual void handleOnboardParamUpdate(int component,const QString& parameterName, QVariant value) = 0; + virtual void handlePendingParamUpdate(int compId, const QString& paramName, QVariant value, bool isPending) = 0; + virtual void handleOnboardParameterListUpToDate() = 0; + virtual void handleParamStatusMsgUpdate(QString msg, int level) = 0; + /** @brief Clear the rendering of onboard parameters */ + virtual void clearOnboardParamDisplay() = 0; + /** @brief Clear the rendering of pending parameters */ + virtual void clearPendingParamDisplay() = 0; + + /** @brief Request list of parameters from MAV */ + virtual void requestOnboardParamsUpdate(); + + + /** @brief Store parameters to a file */ + virtual void saveParametersToFile(); + /** @brief Load parameters from a file */ + virtual void loadParametersFromFile(); + +protected: + QGCUASParamManager* paramMgr; + UASInterface* mav; + QString updatingParamNameLock; ///< Name of param currently being updated-- used for reducing echo on param change + +}; + +#endif // QGCBASEPARAMWIDGET_H diff --git a/src/ui/QGCConfigView.cc b/src/ui/QGCConfigView.cc new file mode 100644 index 0000000000000000000000000000000000000000..16147f3e4b91ca8ec28b1e69a30c0c7a1cd24f75 --- /dev/null +++ b/src/ui/QGCConfigView.cc @@ -0,0 +1,103 @@ +#include "QGCConfigView.h" +#include "ui_QGCConfigView.h" +#include "UASManager.h" +#include "QGCPX4VehicleConfig.h" +#include "QGCVehicleConfig.h" +#include "QGCPX4VehicleConfig.h" +#include "MainWindow.h" + +QGCConfigView::QGCConfigView(QWidget *parent) : + QWidget(parent), + ui(new Ui::QGCConfigView), + config(NULL), + mav(NULL) +{ + ui->setupUi(this); + + connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(activeUASChanged(UASInterface*))); + + // The config screens are required for firmware uploading + if (MainWindow::instance()->getCustomMode() == MainWindow::CUSTOM_MODE_PX4) { + + ui->gridLayout->removeWidget(ui->waitingLabel); + ui->waitingLabel->setVisible(false); + delete ui->waitingLabel; + ui->waitingLabel = NULL; + + config = new QGCPX4VehicleConfig(); + ui->gridLayout->addWidget(config); + + } else { + //don't show a configuration widget if no vehicle is connected + //show a placeholder informational widget instead + } + +} + +QGCConfigView::~QGCConfigView() +{ + delete ui; +} + +void QGCConfigView::activeUASChanged(UASInterface* uas) +{ + if (mav == uas) + return; + + int type = -1; + if (mav) + type = mav->getAutopilotType(); + + mav = uas; + if (uas && type != uas->getAutopilotType()) { + + if (ui->waitingLabel) { + ui->gridLayout->removeWidget(ui->waitingLabel); + ui->waitingLabel->setVisible(false); + } + + //remove all child widgets since they could contain stale data + //for example, when we switch from one PX4 UAS to another UAS + foreach (QObject* obj, ui->gridLayout->children()) { + QWidget* w = dynamic_cast(obj); + if (w) { + if (obj != ui->waitingLabel) { + ui->gridLayout->removeWidget(w); + delete obj; + } + } + } + + int autopilotType = mav->getAutopilotType(); + switch (autopilotType) { + case MAV_AUTOPILOT_PX4: + { + QGCPX4VehicleConfig* px4config = qobject_cast(config); + if (!px4config) { + if (config) + delete config; + config = new QGCPX4VehicleConfig(); + ui->gridLayout->addWidget(config); + } + } + break; + default: + { + QGCVehicleConfig* generalconfig = qobject_cast(config); + if (!generalconfig) { + if (config) + delete config; + config = new QGCVehicleConfig(); + ui->gridLayout->addWidget(config); + } + } + break; + } + } + else { + //restore waiting label if we no longer have a connection + ui->gridLayout->addWidget(ui->waitingLabel); + ui->waitingLabel->setVisible(true); + } + +} diff --git a/src/ui/QGCConfigView.h b/src/ui/QGCConfigView.h new file mode 100644 index 0000000000000000000000000000000000000000..a1bd34075e0e126a5c5989fef8c95afd5d10d7ee --- /dev/null +++ b/src/ui/QGCConfigView.h @@ -0,0 +1,29 @@ +#ifndef QGCCONFIGVIEW_H +#define QGCCONFIGVIEW_H + +#include +#include + +namespace Ui { +class QGCConfigView; +} + +class QGCConfigView : public QWidget +{ + Q_OBJECT + +public: + explicit QGCConfigView(QWidget *parent = 0); + ~QGCConfigView(); + +public slots: + void activeUASChanged(UASInterface* uas); + +private: + Ui::QGCConfigView *ui; + QWidget *config; + UASInterface* mav; + +}; + +#endif // QGCCONFIGVIEW_H diff --git a/src/ui/QGCConfigView.ui b/src/ui/QGCConfigView.ui new file mode 100644 index 0000000000000000000000000000000000000000..38ce1ce7774ec6d80a70474fdb36eace4d5cdb90 --- /dev/null +++ b/src/ui/QGCConfigView.ui @@ -0,0 +1,31 @@ + + + QGCConfigView + + + + 0 + 0 + 400 + 300 + + + + Form + + + + 0 + + + + + Waiting for connection... + + + + + + + + diff --git a/src/ui/QGCDataPlot2D.cc b/src/ui/QGCDataPlot2D.cc index 02dc9d1721d4c5888a3d29464eae02a9efbd646d..4a24151a1452bbad9b537ba968580390191bce4f 100644 --- a/src/ui/QGCDataPlot2D.cc +++ b/src/ui/QGCDataPlot2D.cc @@ -120,6 +120,8 @@ void QGCDataPlot2D::savePlot() fileName = QFileDialog::getSaveFileName( this, "Export File Name", QDesktopServices::storageLocation(QDesktopServices::DesktopLocation), "PDF Documents (*.pdf);;SVG Images (*.svg)"); + if (fileName.isEmpty()) + return; if (!fileName.contains(".")) { // .pdf is default extension @@ -138,6 +140,8 @@ void QGCDataPlot2D::savePlot() fileName = QFileDialog::getSaveFileName( this, "Export File Name", QDesktopServices::storageLocation(QDesktopServices::DesktopLocation), "PDF Documents (*.pdf);;SVG Images (*.svg)"); + if (fileName.isEmpty()) + return; //Abort if cancelled } if (fileName.endsWith(".pdf")) { @@ -689,6 +693,8 @@ void QGCDataPlot2D::saveCsvLog() fileName = QFileDialog::getSaveFileName( this, "Export CSV File Name", QDesktopServices::storageLocation(QDesktopServices::DesktopLocation), "CSV file (*.csv);;Text file (*.txt)"); + if (fileName.isEmpty()) + return; //User cancelled if (!fileName.contains(".")) { // .csv is default extension diff --git a/src/ui/QGCHilConfiguration.cc b/src/ui/QGCHilConfiguration.cc index 37467fb1378711a5229cda49248d367d7d340017..e501e8c6aaf7d16252fbd65b74e3c7599324953f 100644 --- a/src/ui/QGCHilConfiguration.cc +++ b/src/ui/QGCHilConfiguration.cc @@ -64,7 +64,7 @@ void QGCHilConfiguration::on_simComboBox_currentIndexChanged(int index) if(1 == index) { // Ensure the sim exists and is disabled - mav->enableHilFlightGear(false, ""); + mav->enableHilFlightGear(false, "", true); QGCHilFlightGearConfiguration* hfgconf = new QGCHilFlightGearConfiguration(mav, this); hfgconf->show(); ui->simulatorConfigurationLayout->addWidget(hfgconf); diff --git a/src/ui/QGCHilConfiguration.ui b/src/ui/QGCHilConfiguration.ui index cffe03b91d6ad3917c8c0521db9f92a94e5826c6..1db3ec1b621f675b463961f691482e8488222a1f 100644 --- a/src/ui/QGCHilConfiguration.ui +++ b/src/ui/QGCHilConfiguration.ui @@ -20,13 +20,6 @@ Form - - - - No simulator active.. - - - @@ -73,6 +66,13 @@ + + + + No simulator active.. + + + diff --git a/src/ui/QGCHilFlightGearConfiguration.cc b/src/ui/QGCHilFlightGearConfiguration.cc index 6a39a257e92c81343ae1741c1ba935aa8ca9affe..ddbccb7c7fa94edb6d6a0caa3dd08796e0f25e1a 100644 --- a/src/ui/QGCHilFlightGearConfiguration.cc +++ b/src/ui/QGCHilFlightGearConfiguration.cc @@ -40,7 +40,7 @@ void QGCHilFlightGearConfiguration::on_startButton_clicked() //XXX check validity of inputs QString options = ui->optionsPlainTextEdit->toPlainText(); options.append(" --aircraft=" + ui->aircraftComboBox->currentText()); - mav->enableHilFlightGear(true, options); + mav->enableHilFlightGear(true, options, ui->sensorHilCheckBox->isChecked()); } void QGCHilFlightGearConfiguration::on_stopButton_clicked() diff --git a/src/ui/QGCHilFlightGearConfiguration.ui b/src/ui/QGCHilFlightGearConfiguration.ui index 2a4cb315b18d0b0ef530b02e9611c2f1a569694a..d06f174223349217bae9244cc3cabe096c03700b 100644 --- a/src/ui/QGCHilFlightGearConfiguration.ui +++ b/src/ui/QGCHilFlightGearConfiguration.ui @@ -25,8 +25,17 @@ false - - + + + 0 + + + 0 + + + 0 + + 0 @@ -52,14 +61,14 @@ - + <html><head/><body><p>Additional Options:</p></body></html> - + @@ -72,7 +81,7 @@ - + @@ -85,13 +94,23 @@ - + Stop + + + + Sensor HIL + + + true + + + diff --git a/src/ui/QGCPX4VehicleConfig.cc b/src/ui/QGCPX4VehicleConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..3cc3603b794b0e5dee295b8341769fa0c75648ec --- /dev/null +++ b/src/ui/QGCPX4VehicleConfig.cc @@ -0,0 +1,1852 @@ +// On Windows (for VS2010) stdint.h contains the limits normally contained in limits.h +// It also needs the __STDC_LIMIT_MACROS macro defined in order to include them (done +// in qgroundcontrol.pri). +#ifdef WIN32 +#include +#else +#include +#endif + +#include +#include +#include +#include +#include + +#include "QGCPX4VehicleConfig.h" + +#include "QGC.h" +#include "QGCToolWidget.h" +#include "UASManager.h" +#include "LinkManager.h" +#include "UASParameterCommsMgr.h" +#include "ui_QGCPX4VehicleConfig.h" +#include "px4_configuration/QGCPX4AirframeConfig.h" +#include "px4_configuration/QGCPX4SensorCalibration.h" +#include + +#define WIDGET_INDEX_FIRMWARE 0 +#define WIDGET_INDEX_RC 1 +#define WIDGET_INDEX_SENSOR_CAL 2 +#define WIDGET_INDEX_AIRFRAME_CONFIG 3 +#define WIDGET_INDEX_GENERAL_CONFIG 4 +#define WIDGET_INDEX_ADV_CONFIG 5 + +#define MIN_PWM_VAL 800 +#define MAX_PWM_VAL 2200 + +QGCPX4VehicleConfig::QGCPX4VehicleConfig(QWidget *parent) : + QWidget(parent), + mav(NULL), + chanCount(0), + channelWanted(-1), + channelReverseStateWanted(-1), + rcRoll(0.0f), + rcPitch(0.0f), + rcYaw(0.0f), + rcThrottle(0.0f), + rcMode(0.0f), + rcAssist(0.0f), + rcMission(0.0f), + rcReturn(0.0f), + rcFlaps(0.0f), + rcAux1(0.0f), + rcAux2(0.0f), + dataModelChanged(true), + calibrationEnabled(false), + configEnabled(false), + px4AirframeConfig(NULL), + #ifdef QUPGRADE_SUPPORT + firmwareDialog(NULL), + #endif + planeBack(":/files/images/px4/rc/cessna_back.png"), + planeSide(":/files/images/px4/rc/cessna_side.png"), + px4SensorCalibration(NULL), + ui(new Ui::QGCPX4VehicleConfig) +{ + doneLoadingConfig = false; + + channelNames << "Roll / Aileron"; + channelNames << "Pitch / Elevator"; + channelNames << "Yaw / Rudder"; + channelNames << "Throttle"; + channelNames << "Main Mode Switch"; + channelNames << "Assist Switch"; + channelNames << "Mission Switch"; + channelNames << "Return Switch"; + channelNames << "Flaps"; + channelNames << "Aux1"; + channelNames << "Aux2"; + channelNames << "Aux3"; + channelNames << "Aux4"; + channelNames << "Aux5"; + channelNames << "Aux6"; + channelNames << "Aux7"; + channelNames << "Aux8"; + + setObjectName("QGC_VEHICLECONFIG"); + ui->setupUi(this); + + ui->advancedMenuButton->setEnabled(false); + ui->airframeMenuButton->setEnabled(false); + ui->sensorMenuButton->setEnabled(false); + ui->rcMenuButton->setEnabled(false); + ui->generalMenuButton->hide(); + + px4AirframeConfig = new QGCPX4AirframeConfig(this); + ui->airframeLayout->addWidget(px4AirframeConfig); + + px4SensorCalibration = new QGCPX4SensorCalibration(this); + ui->sensorLayout->addWidget(px4SensorCalibration); + +#ifdef QUPGRADE_SUPPORT + firmwareDialog = new DialogBare(this); + ui->firmwareLayout->addWidget(firmwareDialog); + + connect(firmwareDialog, SIGNAL(connectLinks()), LinkManager::instance(), SLOT(connectAll())); + connect(firmwareDialog, SIGNAL(disconnectLinks()), LinkManager::instance(), SLOT(disconnectAll())); +#else +#error Please check out QUpgrade from http://github.com/LorenzMeier/qupgrade/ into the QGroundControl folder. + + QLabel* label = new QLabel(this); + label->setText("THIS VERSION OF QGROUNDCONTROL WAS BUILT WITHOUT QUPGRADE. To enable firmware upload support, checkout QUpgrade WITHIN the QGroundControl folder"); + ui->firmwareLayout->addWidget(label); +#endif + + ui->rollWidget->setOrientation(Qt::Horizontal); + ui->rollWidget->setName("Roll"); + ui->yawWidget->setOrientation(Qt::Horizontal); + ui->yawWidget->setName("Yaw"); + ui->pitchWidget->setName("Pitch"); + ui->throttleWidget->setName("Throttle"); + ui->radio5Widget->setOrientation(Qt::Horizontal); + ui->radio5Widget->setName("Radio 5"); + ui->radio6Widget->setOrientation(Qt::Horizontal); + ui->radio6Widget->setName("Radio 6"); + ui->radio7Widget->setOrientation(Qt::Horizontal); + ui->radio7Widget->setName("Radio 7"); + ui->radio8Widget->setOrientation(Qt::Horizontal); + ui->radio8Widget->setName("Radio 8"); + + connect(ui->rcMenuButton,SIGNAL(clicked()), + this,SLOT(rcMenuButtonClicked())); + connect(ui->sensorMenuButton,SIGNAL(clicked()), + this,SLOT(sensorMenuButtonClicked())); + connect(ui->generalMenuButton,SIGNAL(clicked()), + this,SLOT(generalMenuButtonClicked())); + connect(ui->advancedMenuButton,SIGNAL(clicked()), + this,SLOT(advancedMenuButtonClicked())); + connect(ui->airframeMenuButton, SIGNAL(clicked()), + this, SLOT(airframeMenuButtonClicked())); + connect(ui->firmwareMenuButton, SIGNAL(clicked()), + this, SLOT(firmwareMenuButtonClicked())); + + connect(ui->advancedCheckBox, SIGNAL(clicked(bool)), ui->advancedGroupBox, SLOT(setVisible(bool))); + ui->advancedGroupBox->setVisible(false); + + connect(ui->advancedCheckBox, SIGNAL(clicked(bool)), ui->graphicsView, SLOT(setHidden(bool))); + ui->graphicsView->setScene(&scene); + + scene.addPixmap(planeBack); + scene.addPixmap(planeSide); + + // XXX hide while WIP + ui->graphicsView->hide(); + + ui->rcCalibrationButton->setCheckable(true); + ui->rcCalibrationButton->setEnabled(false); + connect(ui->rcCalibrationButton, SIGNAL(clicked(bool)), this, SLOT(toggleCalibrationRC(bool))); + ui->spektrumPairButton->setCheckable(false); + ui->spektrumPairButton->setEnabled(false); + connect(ui->spektrumPairButton, SIGNAL(clicked(bool)), this, SLOT(toggleSpektrumPairing(bool))); + + //TODO connect buttons here to save/clear actions? + UASInterface* tmpMav = UASManager::instance()->getActiveUAS(); + if (tmpMav) { + ui->pendingCommitsWidget->initWithUAS(tmpMav); + ui->pendingCommitsWidget->update(); + setActiveUAS(tmpMav); + } + + connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), + this, SLOT(setActiveUAS(UASInterface*))); + + // Connect RC mapping assignments + connect(ui->rollSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setRollChan(int))); + connect(ui->pitchSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setPitchChan(int))); + connect(ui->yawSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setYawChan(int))); + connect(ui->throttleSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setThrottleChan(int))); + connect(ui->modeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setModeChan(int))); + connect(ui->assistSwSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setAssistChan(int))); + connect(ui->missionSwSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setMissionChan(int))); + connect(ui->returnSwSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setReturnChan(int))); + connect(ui->flapsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setFlapsChan(int))); + connect(ui->aux1SpinBox, SIGNAL(valueChanged(int)), this, SLOT(setAux1Chan(int))); + connect(ui->aux2SpinBox, SIGNAL(valueChanged(int)), this, SLOT(setAux2Chan(int))); + + // Connect RC reverse assignments + connect(ui->invertCheckBox, SIGNAL(clicked(bool)), this, SLOT(setRollInverted(bool))); + connect(ui->invertCheckBox_2, SIGNAL(clicked(bool)), this, SLOT(setPitchInverted(bool))); + connect(ui->invertCheckBox_3, SIGNAL(clicked(bool)), this, SLOT(setYawInverted(bool))); + connect(ui->invertCheckBox_4, SIGNAL(clicked(bool)), this, SLOT(setThrottleInverted(bool))); + connect(ui->invertCheckBox_5, SIGNAL(clicked(bool)), this, SLOT(setModeInverted(bool))); + connect(ui->assistSwInvertCheckBox, SIGNAL(clicked(bool)), this, SLOT(setAssistInverted(bool))); + connect(ui->missionSwInvertCheckBox, SIGNAL(clicked(bool)), this, SLOT(setMissionInverted(bool))); + connect(ui->returnSwInvertCheckBox, SIGNAL(clicked(bool)), this, SLOT(setReturnInverted(bool))); + connect(ui->flapsInvertCheckBox, SIGNAL(clicked(bool)), this, SLOT(setFlapsInverted(bool))); + connect(ui->aux1InvertCheckBox, SIGNAL(clicked(bool)), this, SLOT(setAux1Inverted(bool))); + connect(ui->aux2InvertCheckBox, SIGNAL(clicked(bool)), this, SLOT(setAux2Inverted(bool))); + + connect(ui->rollButton, SIGNAL(clicked()), this, SLOT(identifyRollChannel())); + connect(ui->pitchButton, SIGNAL(clicked()), this, SLOT(identifyPitchChannel())); + connect(ui->yawButton, SIGNAL(clicked()), this, SLOT(identifyYawChannel())); + connect(ui->throttleButton, SIGNAL(clicked()), this, SLOT(identifyThrottleChannel())); + connect(ui->modeButton, SIGNAL(clicked()), this, SLOT(identifyModeChannel())); + connect(ui->assistSwButton, SIGNAL(clicked()), this, SLOT(identifyAssistChannel())); + connect(ui->missionSwButton, SIGNAL(clicked()), this, SLOT(identifyMissionChannel())); + connect(ui->returnSwButton, SIGNAL(clicked()), this, SLOT(identifyReturnChannel())); + connect(ui->flapsButton, SIGNAL(clicked()), this, SLOT(identifyFlapsChannel())); + connect(ui->aux1Button, SIGNAL(clicked()), this, SLOT(identifyAux1Channel())); + connect(ui->aux2Button, SIGNAL(clicked()), this, SLOT(identifyAux2Channel())); + connect(ui->persistRcValuesButt,SIGNAL(clicked()), this, SLOT(writeCalibrationRC())); + + //set rc values to defaults + for (unsigned int i = 0; i < chanMax; i++) { + rcValue[i] = UINT16_MAX; + rcValueReversed[i] = UINT16_MAX; + rcMapping[i] = i; + rcToFunctionMapping[i] = i; + channelWantedList[i] = (float)UINT16_MAX;//TODO need to clean these up! + rcMin[i] = 1000.0f; + rcMax[i] = 2000.0f; + + // Mapping not established here, so can't pick values via mapping yet! + rcMappedMin[i] = 1000; + rcMappedMax[i] = 2000; + rcMappedValue[i] = UINT16_MAX; + rcMappedValueRev[i] = UINT16_MAX; + rcMappedNormalizedValue[i] = 0.0f; + } + + for (unsigned int i = chanMax -1; i < chanMappedMax; i++) { + rcMapping[i] = -1; + rcMappedMin[i] = 1000; + rcMappedMax[i] = 2000; + rcMappedValue[i] = UINT16_MAX; + rcMappedValueRev[i] = UINT16_MAX; + rcMappedNormalizedValue[i] = 0.0f; + } + + firmwareMenuButtonClicked(); + + updateTimer.setInterval(150); + connect(&updateTimer, SIGNAL(timeout()), this, SLOT(updateView())); + updateTimer.start(); + + ui->rcLabel->setText(tr("NO RADIO CONTROL INPUT DETECTED. PLEASE ENSURE THE TRANSMITTER IS ON.")); + +} + +QGCPX4VehicleConfig::~QGCPX4VehicleConfig() +{ + delete ui; +} + +void QGCPX4VehicleConfig::rcMenuButtonClicked() +{ + //TODO eg ui->stackedWidget->findChild("rcConfig"); + ui->stackedWidget->setCurrentIndex(WIDGET_INDEX_RC); + ui->tabTitleLabel->setText(tr("Radio Calibration")); +} + +void QGCPX4VehicleConfig::sensorMenuButtonClicked() +{ + ui->stackedWidget->setCurrentIndex(WIDGET_INDEX_SENSOR_CAL); + ui->tabTitleLabel->setText(tr("Sensor Calibration")); +} + +void QGCPX4VehicleConfig::generalMenuButtonClicked() +{ + ui->stackedWidget->setCurrentIndex(WIDGET_INDEX_GENERAL_CONFIG); + ui->tabTitleLabel->setText(tr("General Configuration Options")); +} + +void QGCPX4VehicleConfig::advancedMenuButtonClicked() +{ + ui->stackedWidget->setCurrentIndex(WIDGET_INDEX_ADV_CONFIG); + ui->tabTitleLabel->setText(tr("Advanced Configuration Options")); +} + +void QGCPX4VehicleConfig::airframeMenuButtonClicked() +{ + ui->stackedWidget->setCurrentIndex(WIDGET_INDEX_AIRFRAME_CONFIG); + ui->tabTitleLabel->setText(tr("Airframe Configuration")); +} + +void QGCPX4VehicleConfig::firmwareMenuButtonClicked() +{ + ui->stackedWidget->setCurrentIndex(WIDGET_INDEX_FIRMWARE); + ui->tabTitleLabel->setText(tr("Firmware Upgrade")); +} + +void QGCPX4VehicleConfig::identifyChannelMapping(int aert_index) +{ + if (chanCount == 0 || aert_index < 0) + return; + + int oldmapping = rcMapping[aert_index]; + channelWanted = aert_index; + + for (unsigned i = 0; i < chanMax; i++) { + if (i >= chanCount) { + channelWantedList[i] = 0; + } + else { + channelWantedList[i] = rcValue[i]; + } + } + + msgBox.setText(tr("Detecting %1 ...\t\t").arg(channelNames[channelWanted])); + msgBox.setInformativeText(tr("Please move stick, switch or potentiometer for this channel all the way up/down or left/right.")); + msgBox.setStandardButtons(QMessageBox::NoButton); + skipActionButton = msgBox.addButton(tr("Skip"),QMessageBox::RejectRole); + msgBox.exec(); + skipActionButton->hide(); + msgBox.removeButton(skipActionButton); + if (msgBox.clickedButton() == skipActionButton ){ + channelWanted = -1; + rcMapping[aert_index] = oldmapping; + } + skipActionButton = NULL; + +} + +void QGCPX4VehicleConfig::toggleCalibrationRC(bool enabled) +{ + if (enabled) + { + startCalibrationRC(); + } + else + { + stopCalibrationRC(); + } +} + +void QGCPX4VehicleConfig::toggleSpektrumPairing(bool enabled) +{ + if (!ui->dsm2RadioButton->isChecked() && !ui->dsmxRadioButton && !ui->dsmx8RadioButton) { + // Reject + QMessageBox warnMsgBox; + warnMsgBox.setText(tr("Please select a Spektrum Protocol Version")); + warnMsgBox.setInformativeText(tr("Please select either DSM2 or DSM-X\ndirectly below the pair button,\nbased on the receiver type.")); + warnMsgBox.setStandardButtons(QMessageBox::Ok); + warnMsgBox.setDefaultButton(QMessageBox::Ok); + (void)warnMsgBox.exec(); + return; + } + + UASInterface* mav = UASManager::instance()->getActiveUAS(); + if (mav) { + int rxSubType; + if (ui->dsm2RadioButton->isChecked()) + rxSubType = 0; + else if (ui->dsmxRadioButton->isChecked()) + rxSubType = 1; + else // if (ui->dsmx8RadioButton->isChecked()) + rxSubType = 2; + mav->pairRX(0, rxSubType); + } +} + +void QGCPX4VehicleConfig::setTrimPositions() +{ + int rollMap = rcMapping[0]; + int pitchMap = rcMapping[1]; + int yawMap = rcMapping[2]; + int throttleMap = rcMapping[3]; + + // Reset all trims, as some might not be touched + for (unsigned i = 0; i < chanCount; i++) { + rcTrim[i] = 1500; + } + + // Set trim to min if stick is close to min + if (abs(rcValue[throttleMap] - rcMin[throttleMap]) < 100) { + rcTrim[throttleMap] = rcMin[throttleMap]; // throttle + } + // Set trim to max if stick is close to max + else if (abs(rcValue[throttleMap] - rcMax[throttleMap]) < 100) { + rcTrim[throttleMap] = rcMax[throttleMap]; // throttle + } + else { + // Reject + QMessageBox warnMsgBox; + warnMsgBox.setText(tr("Throttle Stick Trim Position Invalid")); + warnMsgBox.setInformativeText(tr("The throttle stick is not in the min position. Please set it to the minimum value")); + warnMsgBox.setStandardButtons(QMessageBox::Ok); + warnMsgBox.setDefaultButton(QMessageBox::Ok); + (void)warnMsgBox.exec(); + } + + // Set trim for roll, pitch, yaw, throttle + rcTrim[rollMap] = rcValue[rollMap]; // roll + rcTrim[pitchMap] = rcValue[pitchMap]; // pitch + rcTrim[yawMap] = rcValue[yawMap]; // yaw + + // Mode switch and optional modes, might not be mapped (== -1) + for (unsigned i = 4; i < chanMappedMax; i++) { + if (rcMapping[i] >= 0 && rcMapping[i] < (int)chanCount) { + rcTrim[rcMapping[i]] = ((rcMax[rcMapping[i]] - rcMin[rcMapping[i]]) / 2.0f) + rcMin[rcMapping[i]]; + } else if (rcMapping[i] != -1){ + qDebug() << "RC MAPPING FAILED #" << i << "VAL:" << rcMapping[i]; + } + } +} + +void QGCPX4VehicleConfig::detectChannelInversion(int aert_index) +{ + if (chanCount == 0 || aert_index < 0 || aert_index >= (int)chanMappedMax) + return; + + bool oldstatus = rcRev[rcMapping[aert_index]]; + channelReverseStateWanted = aert_index; + + // Reset search list + for (unsigned i = 0; i < chanMax; i++) { + if (i >= chanCount) { + channelReverseStateWantedList[i] = 0; + } + else { + channelReverseStateWantedList[i] = rcValue[i]; + } + } + + QStringList instructions; + instructions << "ROLL: Move stick left"; + instructions << "PITCH: Move stick down";//matches the other sticks: should cause DECREASE in raw rc channel value when not reversed + instructions << "YAW: Move stick left"; + instructions << "THROTTLE: Move stick down"; + instructions << "MODE SWITCH: Push down / towards you"; + instructions << "ASSISTED SWITCH: Push down / towards you"; + instructions << "MISSION SWITCH: Push down / towards you"; + instructions << "RETURN SWITCH: Push down / towards you"; + instructions << "FLAPS: Push down / towards you or turn dial to the leftmost position"; + instructions << "AUX1: Push down / towards you or turn dial to the leftmost position"; + instructions << "AUX2: Push down / towards you or turn dial to the leftmost position"; + + msgBox.setText(tr("%1 Direction").arg(channelNames[channelReverseStateWanted])); + msgBox.setInformativeText(tr("%2").arg((aert_index < instructions.length()) ? instructions[aert_index] : "")); + msgBox.setStandardButtons(QMessageBox::NoButton); + skipActionButton = msgBox.addButton(tr("Skip"),QMessageBox::RejectRole); + msgBox.exec(); + skipActionButton->hide(); + msgBox.removeButton(skipActionButton); + if (msgBox.clickedButton() == skipActionButton ){ + channelReverseStateWanted = -1; + rcRev[rcMapping[aert_index]] = oldstatus; + } + skipActionButton = NULL; +} + +void QGCPX4VehicleConfig::startCalibrationRC() +{ + if (chanCount < 5) { + QMessageBox::warning(0, + tr("RC not Connected"), + tr("Is the RC receiver connected and transmitter turned on? Detected %1 radio channels. To operate PX4, you need at least 5 channels. ").arg(chanCount)); + ui->rcCalibrationButton->setChecked(false); + return; + } + + // reset all channel mappings above Ch 5 to invalid/unused value before starting calibration + for (unsigned int j= 5; j < chanMappedMax; j++) { + rcMapping[j] = -1; + } + + configEnabled = true; + + QMessageBox::warning(0,tr("Safety Warning"), + tr("Starting RC calibration.\n\nEnsure that motor power is disconnected, all props are removed, RC transmitter and receiver are powered and connected.\n\nReset transmitter trims to center, then click OK to continue")); + + //go ahead and try to map first 8 channels, now that user can skip channels + for (int i = 0; i < 8; i++) { + identifyChannelMapping(i); + } + + //QMessageBox::information(0,"Information","Additional channels have not been mapped, but can be mapped in the channel table below."); + configEnabled = false; + QMessageBox::information(0, tr("Information"),tr("Click OK, then move all sticks to their extreme positions, watching the min/max values to ensure you get the most range from your controller. This includes all switches")); + ui->rcCalibrationButton->setText(tr("Finish RC Calibration")); + resetCalibrationRC(); + calibrationEnabled = true; + ui->rollWidget->showMinMax(); + ui->pitchWidget->showMinMax(); + ui->yawWidget->showMinMax(); + ui->throttleWidget->showMinMax(); + ui->radio5Widget->showMinMax(); + ui->radio6Widget->showMinMax(); + ui->radio7Widget->showMinMax(); + ui->radio8Widget->showMinMax(); + + QMessageBox::information(0, tr("Information"), tr("Please click on the button once finished")); +} + +void QGCPX4VehicleConfig::stopCalibrationRC() +{ + if (!calibrationEnabled) + return; + + // Try to identify inverted channels, but only for R/P/Y/T + for (int i = 0; i < 4; i++) { + detectChannelInversion(i); + } + + QMessageBox::information(0,"Trims","Ensure all controls are centered and throttle is in the lowest position. Click OK to continue"); + + calibrationEnabled = false; + configEnabled = false; + ui->rcCalibrationButton->setText(tr("Start RC Calibration")); + + ui->rollWidget->hideMinMax(); + ui->pitchWidget->hideMinMax(); + ui->yawWidget->hideMinMax(); + ui->throttleWidget->hideMinMax(); + ui->radio5Widget->hideMinMax(); + ui->radio6Widget->hideMinMax(); + ui->radio7Widget->hideMinMax(); + ui->radio8Widget->hideMinMax(); + + for (unsigned int i = 0; i < chanCount; i++) { + if (rcMin[i] > 1350) { + rcMin[i] = 1000; + } + + if (rcMax[i] < 1650) { + rcMax[i] = 2000; + } + } + + qDebug() << "SETTING TRIM"; + setTrimPositions(); + + QString statusstr; + statusstr = tr("This is the RC calibration information that will be sent to the autopilot if you click OK. To prevent transmission, click Cancel."); + statusstr += tr(" Normal values range from 1000 to 2000, with disconnected channels reading 1000, 1500, 2000\n\n"); + statusstr += tr("Channel\tMin\tCenter\tMax\n"); + statusstr += "-------\t---\t------\t---\n"; + for (unsigned int i=0; i < chanCount; i++) { + statusstr += QString::number(i) +"\t"+ QString::number(rcMin[i]) +"\t"+ QString::number(rcValue[i]) +"\t"+ QString::number(rcMax[i]) +"\n"; + } + + + msgBox.setText(tr("Confirm Calibration")); + msgBox.setInformativeText(statusstr); + msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);//allow user to cancel upload after reviewing values + int msgBoxResult = msgBox.exec(); + if (QMessageBox::Cancel == msgBoxResult) { + return;//don't commit these values + } + + QMessageBox::information(0,"Uploading the RC Calibration","The configuration will now be uploaded and permanently stored."); + writeCalibrationRC(); +} + +void QGCPX4VehicleConfig::loadQgcConfig(bool primary) +{ + Q_UNUSED(primary); + QDir autopilotdir(qApp->applicationDirPath() + "/files/" + mav->getAutopilotTypeName().toLower()); + QDir generaldir = QDir(autopilotdir.absolutePath() + "/general/widgets"); + QDir vehicledir = QDir(autopilotdir.absolutePath() + "/" + mav->getSystemTypeName().toLower() + "/widgets"); + if (!autopilotdir.exists("general")) + { + //TODO: Throw some kind of error here. There is no general configuration directory + qWarning() << "Invalid general dir. no general configuration will be loaded."; + } + if (!autopilotdir.exists(mav->getAutopilotTypeName().toLower())) + { + //TODO: Throw an error here too, no autopilot specific configuration + qWarning() << "Invalid vehicle dir, no vehicle specific configuration will be loaded."; + } + + // Generate widgets for the General tab. + QGCToolWidget *tool; + bool left = true; + foreach (QString file,generaldir.entryList(QDir::Files | QDir::NoDotAndDotDot)) + { + if (file.toLower().endsWith(".qgw")) { + QWidget* parent = left?ui->generalLeftContents:ui->generalRightContents; + tool = new QGCToolWidget("", "", parent); + if (tool->loadSettings(generaldir.absoluteFilePath(file), false)) + { + toolWidgets.append(tool); + QGroupBox *box = new QGroupBox(parent); + box->setTitle(tool->objectName()); + box->setLayout(new QVBoxLayout(box)); + box->layout()->addWidget(tool); + if (left) + { + left = false; + ui->generalLeftLayout->addWidget(box); + } + else + { + left = true; + ui->generalRightLayout->addWidget(box); + } + } else { + delete tool; + } + } + } + + + //TODO fix and reintegrate the Advanced parameter editor +// // Generate widgets for the Advanced tab. +// foreach (QString file,vehicledir.entryList(QDir::Files | QDir::NoDotAndDotDot)) +// { +// if (file.toLower().endsWith(".qgw")) { +// QWidget* parent = ui->advanceColumnContents; +// tool = new QGCToolWidget("", parent); +// if (tool->loadSettings(vehicledir.absoluteFilePath(file), false)) +// { +// toolWidgets.append(tool); +// QGroupBox *box = new QGroupBox(parent); +// box->setTitle(tool->objectName()); +// box->setLayout(new QVBoxLayout(box)); +// box->layout()->addWidget(tool); +// ui->advancedColumnLayout->addWidget(box); + +// } else { +// delete tool; +// } +// } +// } + + + // Load tabs for general configuration + foreach (QString dir,generaldir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) + { + QPushButton *button = new QPushButton(this); + connect(button,SIGNAL(clicked()),this,SLOT(menuButtonClicked())); + ui->navBarLayout->insertWidget(2,button); + button->setMinimumHeight(75); + button->setMinimumWidth(100); + button->show(); + button->setText(dir); + QWidget *tab = new QWidget(ui->stackedWidget); + ui->stackedWidget->insertWidget(2,tab); + buttonToWidgetMap[button] = tab; + tab->setLayout(new QVBoxLayout()); + tab->show(); + QScrollArea *area = new QScrollArea(tab); + tab->layout()->addWidget(area); + QWidget *scrollArea = new QWidget(tab); + scrollArea->setLayout(new QVBoxLayout(tab)); + area->setWidget(scrollArea); + area->setWidgetResizable(true); + area->show(); + scrollArea->show(); + QDir newdir = QDir(generaldir.absoluteFilePath(dir)); + foreach (QString file,newdir.entryList(QDir::Files| QDir::NoDotAndDotDot)) + { + if (file.toLower().endsWith(".qgw")) { + tool = new QGCToolWidget("", "", tab); + if (tool->loadSettings(newdir.absoluteFilePath(file), false)) + { + toolWidgets.append(tool); + //ui->sensorLayout->addWidget(tool); + QGroupBox *box = new QGroupBox(tab); + box->setTitle(tool->objectName()); + box->setLayout(new QVBoxLayout(tab)); + box->layout()->addWidget(tool); + scrollArea->layout()->addWidget(box); + } else { + delete tool; + } + } + } + } + + // Load additional tabs for vehicle specific configuration + foreach (QString dir,vehicledir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) + { + QPushButton *button = new QPushButton(this); + connect(button,SIGNAL(clicked()),this,SLOT(menuButtonClicked())); + ui->navBarLayout->insertWidget(2,button); + + QWidget *tab = new QWidget(ui->stackedWidget); + ui->stackedWidget->insertWidget(2,tab); + buttonToWidgetMap[button] = tab; + + button->setMinimumHeight(75); + button->setMinimumWidth(100); + button->show(); + button->setText(dir); + tab->setLayout(new QVBoxLayout()); + tab->show(); + QScrollArea *area = new QScrollArea(tab); + tab->layout()->addWidget(area); + QWidget *scrollArea = new QWidget(tab); + scrollArea->setLayout(new QVBoxLayout(tab)); + area->setWidget(scrollArea); + area->setWidgetResizable(true); + area->show(); + scrollArea->show(); + + QDir newdir = QDir(vehicledir.absoluteFilePath(dir)); + foreach (QString file,newdir.entryList(QDir::Files| QDir::NoDotAndDotDot)) + { + if (file.toLower().endsWith(".qgw")) { + tool = new QGCToolWidget("", "", tab); + tool->addUAS(mav); + if (tool->loadSettings(newdir.absoluteFilePath(file), false)) + { + toolWidgets.append(tool); + //ui->sensorLayout->addWidget(tool); + QGroupBox *box = new QGroupBox(tab); + box->setTitle(tool->objectName()); + box->setLayout(new QVBoxLayout(box)); + box->layout()->addWidget(tool); + scrollArea->layout()->addWidget(box); + box->show(); + //gbox->layout()->addWidget(box); + } else { + delete tool; + } + } + } + } +} +void QGCPX4VehicleConfig::menuButtonClicked() +{ + QPushButton *button = qobject_cast(sender()); + if (!button) + { + return; + } + if (buttonToWidgetMap.contains(button)) + { + ui->stackedWidget->setCurrentWidget(buttonToWidgetMap[button]); + } + +} + +void QGCPX4VehicleConfig::loadConfig() +{ + QGCToolWidget* tool; + + QDir autopilotdir(qApp->applicationDirPath() + "/files/" + mav->getAutopilotTypeName().toLower()); + QDir generaldir = QDir(autopilotdir.absolutePath() + "/general/widgets"); + QDir vehicledir = QDir(autopilotdir.absolutePath() + "/" + mav->getSystemTypeName().toLower() + "/widgets"); + if (!autopilotdir.exists("general")) + { + //TODO: Throw some kind of error here. There is no general configuration directory + qWarning() << "Invalid general dir. no general configuration will be loaded."; + } + if (!autopilotdir.exists(mav->getAutopilotTypeName().toLower())) + { + //TODO: Throw an error here too, no autopilot specific configuration + qWarning() << "Invalid vehicle dir, no vehicle specific configuration will be loaded."; + } + qDebug() << autopilotdir.absolutePath(); + qDebug() << generaldir.absolutePath(); + qDebug() << vehicledir.absolutePath(); + QFile xmlfile(autopilotdir.absolutePath() + "/arduplane.pdef.xml"); + if (xmlfile.exists() && !xmlfile.open(QIODevice::ReadOnly)) + { + loadQgcConfig(false); + doneLoadingConfig = true; + return; + } + loadQgcConfig(true); + + QXmlStreamReader xml(xmlfile.readAll()); + xmlfile.close(); + + //TODO: Testing to ensure that incorrectly formatted XML won't break this. + while (!xml.atEnd()) + { + if (xml.isStartElement() && xml.name() == "paramfile") + { + xml.readNext(); + while ((xml.name() != "paramfile") && !xml.atEnd()) + { + QString valuetype = ""; + if (xml.isStartElement() && (xml.name() == "vehicles" || xml.name() == "libraries")) //Enter into the vehicles loop + { + valuetype = xml.name().toString(); + xml.readNext(); + while ((xml.name() != valuetype) && !xml.atEnd()) + { + if (xml.isStartElement() && xml.name() == "parameters") //This is a parameter block + { + QString parametersname = ""; + if (xml.attributes().hasAttribute("name")) + { + parametersname = xml.attributes().value("name").toString(); + } + QVariantMap genset; + QVariantMap advset; + + QString setname = parametersname; + xml.readNext(); + int genarraycount = 0; + int advarraycount = 0; + while ((xml.name() != "parameters") && !xml.atEnd()) + { + if (xml.isStartElement() && xml.name() == "param") + { + QString humanname = xml.attributes().value("humanName").toString(); + QString name = xml.attributes().value("name").toString(); + QString tab= xml.attributes().value("user").toString(); + if (tab == "Advanced") + { + advset["title"] = parametersname; + } + else + { + genset["title"] = parametersname; + } + if (name.contains(":")) + { + name = name.split(":")[1]; + } + QString docs = xml.attributes().value("documentation").toString(); + paramTooltips[name] = name + " - " + docs; + + int type = -1; //Type of item + QMap fieldmap; + xml.readNext(); + while ((xml.name() != "param") && !xml.atEnd()) + { + if (xml.isStartElement() && xml.name() == "values") + { + type = 1; //1 is a combobox + if (tab == "Advanced") + { + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "TYPE"] = "COMBO"; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_COMBOBOX_DESCRIPTION"] = humanname; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_COMBOBOX_PARAMID"] = name; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_COMBOBOX_COMPONENTID"] = 1; + } + else + { + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "TYPE"] = "COMBO"; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_COMBOBOX_DESCRIPTION"] = humanname; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_COMBOBOX_PARAMID"] = name; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_COMBOBOX_COMPONENTID"] = 1; + } + int paramcount = 0; + xml.readNext(); + while ((xml.name() != "values") && !xml.atEnd()) + { + if (xml.isStartElement() && xml.name() == "value") + { + + QString code = xml.attributes().value("code").toString(); + QString arg = xml.readElementText(); + if (tab == "Advanced") + { + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_COMBOBOX_ITEM_" + QString::number(paramcount) + "_TEXT"] = arg; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_COMBOBOX_ITEM_" + QString::number(paramcount) + "_VAL"] = code.toInt(); + } + else + { + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_COMBOBOX_ITEM_" + QString::number(paramcount) + "_TEXT"] = arg; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_COMBOBOX_ITEM_" + QString::number(paramcount) + "_VAL"] = code.toInt(); + } + paramcount++; + } + xml.readNext(); + } + if (tab == "Advanced") + { + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_COMBOBOX_COUNT"] = paramcount; + } + else + { + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_COMBOBOX_COUNT"] = paramcount; + } + } + if (xml.isStartElement() && xml.name() == "field") + { + type = 2; //2 is a slider + QString fieldtype = xml.attributes().value("name").toString(); + QString text = xml.readElementText(); + fieldmap[fieldtype] = text; + } + xml.readNext(); + } + if (type == -1) + { + //Nothing inside! Assume it's a value, give it a default range. + type = 2; + QString fieldtype = "Range"; + QString text = "0 100"; //TODO: Determine a better way of figuring out default ranges. + fieldmap[fieldtype] = text; + } + if (type == 2) + { + if (tab == "Advanced") + { + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "TYPE"] = "SLIDER"; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_SLIDER_DESCRIPTION"] = humanname; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_SLIDER_PARAMID"] = name; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_SLIDER_COMPONENTID"] = 1; + } + else + { + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "TYPE"] = "SLIDER"; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_SLIDER_DESCRIPTION"] = humanname; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_SLIDER_PARAMID"] = name; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_SLIDER_COMPONENTID"] = 1; + } + if (fieldmap.contains("Range")) + { + float min = 0; + float max = 0; + //Some range fields list "0-10" and some list "0 10". Handle both. + if (fieldmap["Range"].split(" ").size() > 1) + { + min = fieldmap["Range"].split(" ")[0].trimmed().toFloat(); + max = fieldmap["Range"].split(" ")[1].trimmed().toFloat(); + } + else if (fieldmap["Range"].split("-").size() > 1) + { + min = fieldmap["Range"].split("-")[0].trimmed().toFloat(); + max = fieldmap["Range"].split("-")[1].trimmed().toFloat(); + } + if (tab == "Advanced") + { + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_SLIDER_MIN"] = min; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_SLIDER_MAX"] = max; + } + else + { + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_SLIDER_MIN"] = min; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_SLIDER_MAX"] = max; + } + } + } + if (tab == "Advanced") + { + advarraycount++; + advset["count"] = advarraycount; + } + else + { + genarraycount++; + genset["count"] = genarraycount; + } + } + xml.readNext(); + } + if (genarraycount > 0) + { + QWidget* parent = this; + if (valuetype == "vehicles") + { + parent = ui->generalLeftContents; + } + else if (valuetype == "libraries") + { + parent = ui->generalRightContents; + } + tool = new QGCToolWidget(parametersname, parametersname, parent); + tool->addUAS(mav); + tool->setSettings(genset); + QList paramlist = tool->getParamList(); + for (int i=0;isetTitle(tool->objectName()); + box->setLayout(new QVBoxLayout(box)); + box->layout()->addWidget(tool); + if (valuetype == "vehicles") + { + ui->generalLeftLayout->addWidget(box); + } + else if (valuetype == "libraries") + { + ui->generalRightLayout->addWidget(box); + } + box->hide(); + toolToBoxMap[tool] = box; + } + if (advarraycount > 0) + { + QWidget* parent = this; + if (valuetype == "vehicles") + { + parent = ui->generalLeftContents; + } + else if (valuetype == "libraries") + { + parent = ui->generalRightContents; + } + tool = new QGCToolWidget(parametersname, parametersname, parent); + tool->addUAS(mav); + tool->setSettings(advset); + QList paramlist = tool->getParamList(); + for (int i=0;isetTitle(tool->objectName()); + box->setLayout(new QVBoxLayout(box)); + box->layout()->addWidget(tool); + if (valuetype == "vehicles") + { + ui->generalLeftLayout->addWidget(box); + } + else if (valuetype == "libraries") + { + ui->generalRightLayout->addWidget(box); + } + box->hide(); + toolToBoxMap[tool] = box; + } + } + xml.readNext(); + } + } + xml.readNext(); + } + } + xml.readNext(); + } + + if (!paramTooltips.isEmpty()) { + paramMgr->setParamDescriptions(paramTooltips); + } + doneLoadingConfig = true; + //Config is finished, lets do a parameter request to ensure none are missed if someone else started requesting before we were finished. + paramMgr->requestParameterListIfEmpty(); +} + +void QGCPX4VehicleConfig::setActiveUAS(UASInterface* active) +{ + // Hide items if NULL and abort + if (!active) { + return; + } + + + // Do nothing if UAS is already visible + if (mav == active) + return; + + if (mav) + { + + // Disconnect old system + disconnect(mav, SIGNAL(remoteControlChannelRawChanged(int,float)), this, + SLOT(remoteControlChannelRawChanged(int,float))); + //TODO use paramCommsMgr instead + disconnect(mav, SIGNAL(parameterChanged(int,int,QString,QVariant)), this, + SLOT(parameterChanged(int,int,QString,QVariant))); + + // Delete all children from all fixed tabs. + foreach(QWidget* child, ui->generalLeftContents->findChildren()) { + child->deleteLater(); + } + foreach(QWidget* child, ui->generalRightContents->findChildren()) { + child->deleteLater(); + } + foreach(QWidget* child, ui->advanceColumnContents->findChildren()) { + child->deleteLater(); + } +// foreach(QWidget* child, ui->sensorLayout->findChildren()) { +// child->deleteLater(); +// } + + foreach(QWidget* child, ui->airframeLayout->findChildren()) + { + child->deleteLater(); + } + + // And then delete any custom tabs + foreach(QWidget* child, additionalTabs) { + child->deleteLater(); + } + additionalTabs.clear(); + + toolWidgets.clear(); + paramToWidgetMap.clear(); + libParamToWidgetMap.clear(); + systemTypeToParamMap.clear(); + toolToBoxMap.clear(); + paramTooltips.clear(); + } + + // Connect new system + mav = active; + + paramMgr = mav->getParamManager(); + + ui->pendingCommitsWidget->setUAS(mav); + ui->paramTreeWidget->setUAS(mav); + + // Reset current state + resetCalibrationRC(); + //TODO eliminate the separate RC_TYPE call + mav->requestParameter(0, "RC_TYPE"); + + chanCount = 0; + + // Connect new system + connect(mav, SIGNAL(remoteControlChannelRawChanged(int,float)), this, + SLOT(remoteControlChannelRawChanged(int,float))); + connect(mav, SIGNAL(parameterChanged(int,int,QString,QVariant)), this, + SLOT(parameterChanged(int,int,QString,QVariant))); + + + if (systemTypeToParamMap.contains(mav->getSystemTypeName())) { + paramToWidgetMap = systemTypeToParamMap[mav->getSystemTypeName()]; + } + else { + //Indication that we have no meta data for this system type. + qDebug() << "No parameters defined for system type:" << mav->getSystemTypeName(); + paramToWidgetMap = systemTypeToParamMap[mav->getSystemTypeName()]; + } + + if (!paramTooltips.isEmpty()) { + mav->getParamManager()->setParamDescriptions(paramTooltips); + } + + qDebug() << "CALIBRATION!! System Type Name:" << mav->getSystemTypeName(); + + //Load configuration after 1ms. This allows it to go into the event loop, and prevents application hangups due to the + //amount of time it actually takes to load the configuration windows. + QTimer::singleShot(1,this,SLOT(loadConfig())); + + updateStatus(QString("Reading from system %1").arg(mav->getUASName())); + + // Since a system is now connected, enable the VehicleConfig UI. + // Enable buttons + ui->advancedMenuButton->setEnabled(true); + ui->airframeMenuButton->setEnabled(true); + ui->sensorMenuButton->setEnabled(true); + ui->rcMenuButton->setEnabled(true); + + ui->rcCalibrationButton->setEnabled(true); + ui->spektrumPairButton->setEnabled(true); +} + +void QGCPX4VehicleConfig::resetCalibrationRC() +{ + for (unsigned int i = 0; i < chanMax; ++i) { + rcMin[i] = 1500; + rcMax[i] = 1500; + } +} + +/** + * Sends the RC calibration to the vehicle and stores it in EEPROM + */ +void QGCPX4VehicleConfig::writeCalibrationRC() +{ + if (!mav) return; + + updateStatus(tr("Sending RC configuration and storing to persistent memory.")); + + QString minTpl("RC%1_MIN"); + QString maxTpl("RC%1_MAX"); + QString trimTpl("RC%1_TRIM"); + QString revTpl("RC%1_REV"); + + // Do not write the RC type, as these values depend on this + // active onboard parameter + + for (unsigned int i = 0; i < chanCount; ++i) { + //qDebug() << "SENDING" << minTpl.arg(i+1) << rcMin[i]; + paramMgr->setPendingParam(0, minTpl.arg(i+1), rcMin[i]); + paramMgr->setPendingParam(0, trimTpl.arg(i+1), rcTrim[i]); + paramMgr->setPendingParam(0, maxTpl.arg(i+1), rcMax[i]); + paramMgr->setPendingParam(0, revTpl.arg(i+1), (rcRev[i]) ? -1.0f : 1.0f); + } + + // Write mappings + paramMgr->setPendingParam(0, "RC_MAP_ROLL", (int32_t)(rcMapping[0]+1)); + paramMgr->setPendingParam(0, "RC_MAP_PITCH", (int32_t)(rcMapping[1]+1)); + paramMgr->setPendingParam(0, "RC_MAP_YAW", (int32_t)(rcMapping[2]+1)); + paramMgr->setPendingParam(0, "RC_MAP_THROTTLE", (int32_t)(rcMapping[3]+1)); + paramMgr->setPendingParam(0, "RC_MAP_MODE_SW", (int32_t)(rcMapping[4]+1)); + paramMgr->setPendingParam(0, "RC_MAP_ASSIST_SW", (int32_t)(rcMapping[5]+1)); + paramMgr->setPendingParam(0, "RC_MAP_MISSIO_SW", (int32_t)(rcMapping[6]+1)); + paramMgr->setPendingParam(0, "RC_MAP_RETURN_SW", (int32_t)(rcMapping[7]+1)); + paramMgr->setPendingParam(0, "RC_MAP_FLAPS", (int32_t)(rcMapping[8]+1)); + paramMgr->setPendingParam(0, "RC_MAP_AUX1", (int32_t)(rcMapping[9]+1)); + paramMgr->setPendingParam(0, "RC_MAP_AUX2", (int32_t)(rcMapping[10]+1)); + + //let the param mgr manage sending all the pending RC_foo updates and persisting after + paramMgr->sendPendingParameters(true); + +} + +void QGCPX4VehicleConfig::requestCalibrationRC() +{ + paramMgr->requestRcCalibrationParamsUpdate(); +} + +void QGCPX4VehicleConfig::writeParameters() +{ + updateStatus(tr("Writing all onboard parameters.")); + writeCalibrationRC(); +} + +void QGCPX4VehicleConfig::remoteControlChannelRawChanged(int chan, float fval) +{ + // Check if index and values are sane + if (chan < 0 || static_cast(chan) >= chanMax || fval < 500.0f || fval > 2500.0f) + return; + + if (chan + 1 > (int)chanCount) { + chanCount = chan+1; + } + + // Raw value + float deltaRaw = fabsf(fval - rcValue[chan]); + float delta = fabsf(fval - rcMappedValue[rcToFunctionMapping[chan]]); + if (!configEnabled && !calibrationEnabled && + (deltaRaw < 12.0f && delta < 12.0f && rcValue[chan] > 800 && rcValue[chan] < 2200)) + { + // ignore tiny jitter values + return; + } + else { + rcValue[chan] = fval; + } + + + // Update calibration data + if (calibrationEnabled) { + if (fval < rcMin[chan]) { + rcMin[chan] = fval; + } + if (fval > rcMax[chan]) { + rcMax[chan] = fval; + } + } + + if (channelWanted >= 0) { + // If the first channel moved considerably, pick it + if (fabsf(channelWantedList[chan] - fval) > 300.0f) { + rcMapping[channelWanted] = chan; + updateMappingView(channelWanted); + + int chanFound = channelWanted; + channelWanted = -1; + + // Confirm found channel + msgBox.setText(tr("Found %1 \t\t").arg(channelNames[chanFound])); + msgBox.setInformativeText(tr("Assigned raw RC channel %2").arg(chan + 1)); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setDefaultButton(QMessageBox::Ok); + skipActionButton->hide(); + msgBox.removeButton(skipActionButton); + + (void)msgBox.exec(); + + // XXX fuse with parameter update handling + switch (chanFound) { + case 0: + ui->rollSpinBox->setValue(chan + 1); + break; + case 1: + ui->pitchSpinBox->setValue(chan + 1); + break; + case 2: + ui->yawSpinBox->setValue(chan + 1); + break; + case 3: + ui->throttleSpinBox->setValue(chan + 1); + break; + case 4: + ui->modeSpinBox->setValue(chan + 1); + break; + case 5: + ui->assistSwSpinBox->setValue(chan + 1); + break; + case 6: + ui->missionSwSpinBox->setValue(chan + 1); + break; + case 7: + ui->returnSwSpinBox->setValue(chan + 1); + break; + case 8: + ui->flapsSpinBox->setValue(chan + 1); + break; + case 9: + ui->aux1SpinBox->setValue(chan + 1); + break; + case 10: + ui->aux2SpinBox->setValue(chan + 1); + break; + } + } + } + + rcValueReversed[chan] = (rcRev[chan]) ? rcMax[chan] - (fval - rcMin[chan]) : fval; + + // Normalized value + float normalized; + float chanTrim = rcTrim[chan]; + if (fval >= rcTrim[chan]) { + normalized = (fval - chanTrim)/(rcMax[chan] - chanTrim); + } + else { + normalized = -(chanTrim - fval)/(chanTrim - rcMin[chan]); + } + + // Bound + normalized = qBound(-1.0f, normalized, 1.0f); + // Invert + normalized = (rcRev[chan]) ? -1.0f*normalized : normalized; + + // Find correct mapped channel + rcMappedValueRev[rcToFunctionMapping[chan]] = (rcRev[chan]) ? rcMax[chan] - (fval - rcMin[chan]) : fval; + rcMappedValue[rcToFunctionMapping[chan]] = fval; + + // Copy min / max + rcMappedMin[rcToFunctionMapping[chan]] = rcMin[chan]; + rcMappedMax[rcToFunctionMapping[chan]] = rcMax[chan]; + rcMappedNormalizedValue[rcToFunctionMapping[chan]] = normalized; + + if (chan == rcMapping[0]) { + rcRoll = normalized; + } + else if (chan == rcMapping[1]) { + rcPitch = normalized; + } + else if (chan == rcMapping[2]) { + rcYaw = normalized; + } + else if (chan == rcMapping[3]) { + if (rcRev[chan]) { + rcThrottle = 1.0f + normalized; + } + else { + rcThrottle = normalized; + } + + rcThrottle = qBound(0.0f, rcThrottle, 1.0f); + } + else if (chan == rcMapping[4]) { + rcMode = normalized; // MODE SWITCH + } + else if (chan == rcMapping[5]) { + rcAssist = normalized; // ASSIST SWITCH + } + else if (chan == rcMapping[6]) { + rcMission = normalized; // MISSION SWITCH + } + else if (chan == rcMapping[7]) { + rcReturn = normalized; // RETURN SWITCH + } + else if (chan == rcMapping[8]) { + rcFlaps = normalized; // FLAPS + } + else if (chan == rcMapping[9]) { + rcAux1 = normalized; // AUX2 + } + else if (chan == rcMapping[10]) { + rcAux2 = normalized; // AUX3 + } + + if (channelReverseStateWanted >= 0) { + // If the *right* channel moved considerably, evaluate it + if (fabsf(fval - 1500) > 350.0f && + rcMapping[channelReverseStateWanted] == chan) { + + // Check if the output is positive + if (fval > 1750) { + rcRev[rcMapping[channelReverseStateWanted]] = true; + } else { + rcRev[rcMapping[channelReverseStateWanted]] = false; + } + + unsigned currRevFunc = channelReverseStateWanted; + + channelReverseStateWanted = -1; + + // Confirm found channel + msgBox.setText(tr("%1 direction assigned").arg(channelNames[currRevFunc])); + msgBox.setInformativeText(tr("%1").arg((rcRev[rcMapping[currRevFunc]]) ? tr("Reversed channel.") : tr("Did not reverse channel.") )); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setDefaultButton(QMessageBox::Ok); + skipActionButton->hide(); + msgBox.removeButton(skipActionButton); + (void)msgBox.exec(); + } + } + + dataModelChanged = true; + + //qDebug() << "RC CHAN:" << chan << "PPM:" << fval << "NORMALIZED:" << normalized; +} + +void QGCPX4VehicleConfig::updateAllInvertedCheckboxes() +{ + for (unsigned function_index = 0; function_index < chanMappedMax; function_index++) { + + int rc_input_index = rcMapping[function_index]; + + if (rc_input_index < 0 || rc_input_index > (int)chanMax) + continue; + + // Map index to checkbox. + // TODO(lm) Would be better to stick the checkboxes into a vector upfront + switch (function_index) + { + case 0: + ui->invertCheckBox->setChecked(rcRev[rc_input_index]); + ui->rollWidget->setName(tr("Roll (#%1)").arg(rcMapping[0] + 1)); + break; + case 1: + ui->invertCheckBox_2->setChecked(rcRev[rc_input_index]); + ui->pitchWidget->setName(tr("Pitch (#%1)").arg(rcMapping[1] + 1)); + break; + case 2: + ui->invertCheckBox_3->setChecked(rcRev[rc_input_index]); + ui->yawWidget->setName(tr("Yaw (#%1)").arg(rcMapping[2] + 1)); + break; + case 3: + ui->invertCheckBox_4->setChecked(rcRev[rc_input_index]); + ui->throttleWidget->setName(tr("Throt. (#%1)").arg(rcMapping[3] + 1)); + break; + case 4: + ui->invertCheckBox_5->setChecked(rcRev[rc_input_index]); + //ui->radio5Widget->setName(tr("Mode Switch (#%1)").arg(rcMapping[4] + 1)); + break; + case 5: + ui->assistSwInvertCheckBox->setChecked(rcRev[rc_input_index]); + break; + case 6: + ui->missionSwInvertCheckBox->setChecked(rcRev[rc_input_index]); + break; + case 7: + ui->returnSwInvertCheckBox->setChecked(rcRev[rc_input_index]); + break; + case 8: + ui->flapsInvertCheckBox->setChecked(rcRev[rc_input_index]); + break; + case 9: + ui->aux1InvertCheckBox->setChecked(rcRev[rc_input_index]); + break; + case 10: + ui->aux2InvertCheckBox->setChecked(rcRev[rc_input_index]); + break; + } + } +} + +void QGCPX4VehicleConfig::updateMappingView(int function_index) +{ + Q_UNUSED(function_index); + updateAllInvertedCheckboxes(); + + QStringList assignments; + + for (unsigned i = 0; i < chanMax; i++) { + assignments << ""; + } + + for (unsigned i = 0; i < chanMappedMax; i++) { + if (rcMapping[i] >= 0 && rcMapping[i] < (int)chanMax) { + assignments.replace(rcMapping[i], assignments[rcMapping[i]].append(QString(" / ").append(channelNames[i]))); + } + } + + for (unsigned i = 0; i < chanMax; i++) { + if (assignments[i] == "") + assignments[i] = "UNUSED"; + } + + for (unsigned i = 0; i < chanMax; i++) { + switch (i) { + case 4: + ui->radio5Widget->setName(tr("%1 (#5)").arg(assignments[4])); + break; + case 5: + ui->radio6Widget->setName(tr("%1 (#6)").arg(assignments[5])); + break; + case 6: + ui->radio7Widget->setName(tr("%1 (#7)").arg(assignments[6])); + break; + case 7: + ui->radio8Widget->setName(tr("%1 (#8)").arg(assignments[7])); + break; + } + } +} + +void QGCPX4VehicleConfig::handleRcParameterChange(QString parameterName, QVariant value) +{ + if (parameterName.startsWith("RC_")) { + if (parameterName.startsWith("RC_MAP_")) { + //RC Mapping radio channels to meaning + // Order is: roll, pitch, yaw, throttle, mode sw, aux 1-3 + + int intValue = value.toInt() - 1; + + if (parameterName.startsWith("RC_MAP_ROLL")) { + setChannelToFunctionMapping(0, intValue); + ui->rollSpinBox->setValue(rcMapping[0]+1); + ui->rollSpinBox->setEnabled(true); + } + else if (parameterName.startsWith("RC_MAP_PITCH")) { + setChannelToFunctionMapping(1, intValue); + ui->pitchSpinBox->setValue(rcMapping[1]+1); + ui->pitchSpinBox->setEnabled(true); + } + else if (parameterName.startsWith("RC_MAP_YAW")) { + setChannelToFunctionMapping(2, intValue); + ui->yawSpinBox->setValue(rcMapping[2]+1); + ui->yawSpinBox->setEnabled(true); + } + else if (parameterName.startsWith("RC_MAP_THROTTLE")) { + setChannelToFunctionMapping(3, intValue); + ui->throttleSpinBox->setValue(rcMapping[3]+1); + ui->throttleSpinBox->setEnabled(true); + } + else if (parameterName.startsWith("RC_MAP_MODE_SW")) { + setChannelToFunctionMapping(4, intValue); + ui->modeSpinBox->setValue(rcMapping[4]+1); + ui->modeSpinBox->setEnabled(true); + } + else if (parameterName.startsWith("RC_MAP_ASSIST_SW")) { + setChannelToFunctionMapping(5, intValue); + ui->assistSwSpinBox->setValue(rcMapping[5]+1); + ui->assistSwSpinBox->setEnabled(true); + } + else if (parameterName.startsWith("RC_MAP_MISSIO_SW")) { + setChannelToFunctionMapping(6, intValue); + ui->missionSwSpinBox->setValue(rcMapping[6]+1); + ui->missionSwSpinBox->setEnabled(true); + } + else if (parameterName.startsWith("RC_MAP_RETURN_SW")) { + setChannelToFunctionMapping(7, intValue); + ui->returnSwSpinBox->setValue(rcMapping[7]+1); + ui->returnSwSpinBox->setEnabled(true); + } + else if (parameterName.startsWith("RC_MAP_FLAPS")) { + setChannelToFunctionMapping(8, intValue); + ui->flapsSpinBox->setValue(rcMapping[8]+1); + ui->flapsSpinBox->setEnabled(true); + } + else if (parameterName.startsWith("RC_MAP_AUX1")) { + setChannelToFunctionMapping(9, intValue); + ui->aux1SpinBox->setValue(rcMapping[9]+1); + ui->aux1SpinBox->setEnabled(true); + } + else if (parameterName.startsWith("RC_MAP_AUX2")) { + setChannelToFunctionMapping(10, intValue); + ui->aux2SpinBox->setValue(rcMapping[10]+1); + ui->aux2SpinBox->setEnabled(true); + } + } + else if (parameterName.startsWith("RC_SCALE_")) { + // Scaling + float floatVal = value.toFloat(); + if (parameterName.startsWith("RC_SCALE_ROLL")) { + rcScaling[0] = floatVal; + } + else if (parameterName.startsWith("RC_SCALE_PITCH")) { + rcScaling[1] = floatVal; + } + else if (parameterName.startsWith("RC_SCALE_YAW")) { + rcScaling[2] = floatVal; + } + // Not implemented at this point +// else if (parameterName.startsWith("RC_SCALE_THROTTLE")) { +// rcScaling[3] = floatVal; +// } +// else if (parameterName.startsWith("RC_SCALE_AUX1")) { +// rcScaling[5] = floatVal; +// } +// else if (parameterName.startsWith("RC_SCALE_AUX2")) { +// rcScaling[6] = floatVal; +// } + } + } + else { + // Channel calibration values + bool ok = false; + unsigned int index = chanMax; + QRegExp minTpl("RC?_MIN"); + minTpl.setPatternSyntax(QRegExp::Wildcard); + QRegExp maxTpl("RC?_MAX"); + maxTpl.setPatternSyntax(QRegExp::Wildcard); + QRegExp trimTpl("RC?_TRIM"); + trimTpl.setPatternSyntax(QRegExp::Wildcard); + QRegExp revTpl("RC?_REV"); + revTpl.setPatternSyntax(QRegExp::Wildcard); + + // Do not write the RC type, as these values depend on this + // active onboard parameter + int intVal = value.toInt(); + + if (minTpl.exactMatch(parameterName)) { + index = parameterName.mid(2, 1).toInt(&ok) - 1; + if (ok && index < chanMax) { + rcMin[index] = intVal; + updateRcWidgetValues(); + } + } + else if (maxTpl.exactMatch(parameterName)) { + index = parameterName.mid(2, 1).toInt(&ok) - 1; + if (ok && index < chanMax) { + rcMax[index] = intVal; + updateRcWidgetValues(); + } + } + else if (trimTpl.exactMatch(parameterName)) { + index = parameterName.mid(2, 1).toInt(&ok) - 1; + if (ok && index < chanMax) { + rcTrim[index] = intVal; + } + } + else if (revTpl.exactMatch(parameterName)) { + index = parameterName.mid(2, 1).toInt(&ok) - 1; + if (ok && index < chanMax) { + rcRev[index] = (intVal == -1) ? true : false; + + for (unsigned i = 0; i < chanMappedMax; i++) + { + if (rcMapping[i] == (int)index) + updateMappingView(i); + } + } + } + } +} + +void QGCPX4VehicleConfig::setChannelToFunctionMapping(int function, int channel) +{ + if (function >= 0 && function < (int)chanMappedMax) + rcMapping[function] = channel; + + if (channel >= 0 && channel < (int)chanMax) + rcToFunctionMapping[channel] = function; +} + +void QGCPX4VehicleConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (!doneLoadingConfig) { + //We do not want to attempt to generate any UI elements until loading of the config file is complete. + //We should re-request params later if needed, that is not implemented yet. + return; + } + + //TODO this may introduce a bug with param editor widgets not receiving param updates + if (parameterName.startsWith("RC")) { + handleRcParameterChange(parameterName,value); + return; + } + + if (paramToWidgetMap.contains(parameterName)) { + //Main group of parameters of the selected airframe + paramToWidgetMap.value(parameterName)->setParameterValue(uas,component,parameterName,value); + if (toolToBoxMap.contains(paramToWidgetMap.value(parameterName))) { + toolToBoxMap[paramToWidgetMap.value(parameterName)]->show(); + } + else { + qCritical() << "Widget with no box, possible memory corruption for param:" << parameterName; + } + } + else if (libParamToWidgetMap.contains(parameterName)) { + //All the library parameters + libParamToWidgetMap.value(parameterName)->setParameterValue(uas,component,parameterName,value); + if (toolToBoxMap.contains(libParamToWidgetMap.value(parameterName))) { + toolToBoxMap[libParamToWidgetMap.value(parameterName)]->show(); + } + else { + qCritical() << "Widget with no box, possible memory corruption for param:" << parameterName; + } + } + else { + //Param recieved that we have no metadata for. Search to see if it belongs in a + //group with some other params + bool found = false; + for (int i=0;iobjectName())) { + //It should be grouped with this one, add it. + toolWidgets[i]->addParam(uas,component,parameterName,value); + libParamToWidgetMap.insert(parameterName,toolWidgets[i]); + found = true; + break; + } + } +// if (!found) { +// //New param type, create a QGroupBox for it. +// QWidget* parent = ui->advanceColumnContents; + +// // Create the tool, attaching it to the QGroupBox +// QGCToolWidget *tool = new QGCToolWidget("", parent); +// QString tooltitle = parameterName; +// if (parameterName.split("_").size() > 1) { +// tooltitle = parameterName.split("_")[0] + "_"; +// } +// tool->setTitle(tooltitle); +// tool->setObjectName(tooltitle); +// //tool->setSettings(set); +// libParamToWidgetMap.insert(parameterName,tool); +// toolWidgets.append(tool); +// tool->addParam(uas, component, parameterName, value); +// QGroupBox *box = new QGroupBox(parent); +// box->setTitle(tool->objectName()); +// box->setLayout(new QVBoxLayout(box)); +// box->layout()->addWidget(tool); + +// libParamToWidgetMap.insert(parameterName,tool); +// toolWidgets.append(tool); +// ui->advancedColumnLayout->addWidget(box); + +// toolToBoxMap[tool] = box; +// } + } + +} + +void QGCPX4VehicleConfig::updateStatus(const QString& str) +{ + ui->advancedStatusLabel->setText(str); + ui->advancedStatusLabel->setStyleSheet(""); +} + +void QGCPX4VehicleConfig::updateError(const QString& str) +{ + ui->advancedStatusLabel->setText(str); + ui->advancedStatusLabel->setStyleSheet(QString("QLabel { margin: 0px 2px; font: 14px; color: %1; background-color: %2; }").arg(QGC::colorDarkWhite.name()).arg(QGC::colorMagenta.name())); +} + +void QGCPX4VehicleConfig::checktimeOuts() +{ + +} + + +void QGCPX4VehicleConfig::updateRcWidgetValues() +{ + ui->rollWidget->setValueAndRange(rcMappedValue[0],rcMappedMin[0],rcMappedMax[0]); + ui->pitchWidget->setValueAndRange(rcMappedValue[1],rcMappedMin[1],rcMappedMax[1]); + ui->yawWidget->setValueAndRange(rcMappedValue[2],rcMappedMin[2],rcMappedMax[2]); + ui->throttleWidget->setValueAndRange(rcMappedValue[3],rcMappedMin[3],rcMappedMax[3]); + + ui->radio5Widget->setValueAndRange(rcValueReversed[4],rcMin[4],rcMax[4]); + ui->radio6Widget->setValueAndRange(rcValueReversed[5],rcMin[5],rcMax[5]); + ui->radio7Widget->setValueAndRange(rcValueReversed[6],rcMin[6],rcMax[6]); + ui->radio8Widget->setValueAndRange(rcValueReversed[7],rcMin[7],rcMax[7]); +} + +void QGCPX4VehicleConfig::updateRcChanLabels() +{ + ui->rollChanLabel->setText(labelForRcValue(rcRoll)); + ui->pitchChanLabel->setText(labelForRcValue(rcPitch)); + ui->yawChanLabel->setText(labelForRcValue(rcYaw)); + ui->throttleChanLabel->setText(labelForRcValue(rcThrottle)); + + QString blankLabel = tr("---"); + if (rcValue[rcMapping[4]] != UINT16_MAX) { + ui->modeChanLabel->setText(labelForRcValue(rcMode)); + } + else { + ui->modeChanLabel->setText(blankLabel); + } + + if (rcValue[rcMapping[5]] != UINT16_MAX) { + ui->assistSwChanLabel->setText(labelForRcValue(rcAssist)); + } + else { + ui->assistSwChanLabel->setText(blankLabel); + } + + if (rcValue[rcMapping[6]] != UINT16_MAX) { + ui->missionSwChanLabel->setText(labelForRcValue(rcMission)); + } + else { + ui->missionSwChanLabel->setText(blankLabel); + } + + if (rcValue[rcMapping[7]] != UINT16_MAX) { + ui->returnSwChanLabel->setText(labelForRcValue(rcReturn)); + } + else { + ui->returnSwChanLabel->setText(blankLabel); + } + + if (rcValue[rcMapping[8]] != UINT16_MAX) { + ui->flapsChanLabel->setText(labelForRcValue(rcFlaps)); + } + else { + ui->flapsChanLabel->setText(blankLabel); + } + + if (rcValue[rcMapping[9]] != UINT16_MAX) { + ui->aux1ChanLabel->setText(labelForRcValue(rcAux1)); + } + else { + ui->aux1ChanLabel->setText(blankLabel); + } + + if (rcValue[rcMapping[10]] != UINT16_MAX) { + ui->aux2ChanLabel->setText(labelForRcValue(rcAux2)); + } + else { + ui->aux2ChanLabel->setText(blankLabel); + } +} + +void QGCPX4VehicleConfig::updateView() +{ + if (dataModelChanged) { + dataModelChanged = false; + + updateRcWidgetValues(); + updateRcChanLabels(); + if (chanCount > 0) + ui->rcLabel->setText(tr("Radio control detected with %1 channels.").arg(chanCount)); + } + +} diff --git a/src/ui/QGCPX4VehicleConfig.h b/src/ui/QGCPX4VehicleConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..55778bc3a8af05e3692cff35709ea5fe98a29b26 --- /dev/null +++ b/src/ui/QGCPX4VehicleConfig.h @@ -0,0 +1,344 @@ +#ifndef QGCPX4VehicleConfig_H +#define QGCPX4VehicleConfig_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "QGCToolWidget.h" +#include "UASInterface.h" +#include "px4_configuration/QGCPX4AirframeConfig.h" + +class UASParameterCommsMgr; +class DialogBare; +class QGCPX4SensorCalibration; + +namespace Ui { +class QGCPX4VehicleConfig; +} + +class QGCPX4VehicleConfig : public QWidget +{ + Q_OBJECT + +public: + explicit QGCPX4VehicleConfig(QWidget *parent = 0); + ~QGCPX4VehicleConfig(); + + enum RC_MODE { + RC_MODE_1 = 1, + RC_MODE_2 = 2, + RC_MODE_3 = 3, + RC_MODE_4 = 4, + RC_MODE_NONE = 5 + }; + +public slots: + void rcMenuButtonClicked(); + void sensorMenuButtonClicked(); + void generalMenuButtonClicked(); + void advancedMenuButtonClicked(); + void airframeMenuButtonClicked(); + void firmwareMenuButtonClicked(); + + void identifyChannelMapping(int aert_index); + + /** Set the MAV currently being calibrated */ + void setActiveUAS(UASInterface* active); + /** Fallback function, automatically called by loadConfig() upon failure to find and xml file*/ + void loadQgcConfig(bool primary); + /** Load configuration from xml file */ + void loadConfig(); + /** Start the RC calibration routine */ + void startCalibrationRC(); + /** Stop the RC calibration routine */ + void stopCalibrationRC(); + /** Start/stop the RC calibration routine */ + void toggleCalibrationRC(bool enabled); + /** Start/stop the Spektrum pair routine */ + void toggleSpektrumPairing(bool enabled); + /** Set trim positions */ + void setTrimPositions(); + /** Detect which channels need to be inverted */ + void detectChannelInversion(int aert_index); + /** Render the data updated */ + void updateView(); + + void handleRcParameterChange(QString parameterName, QVariant value); + + + /** Set the RC channel */ + void setRollChan(int channel) { + rcMapping[0] = channel - 1; + updateMappingView(0); + } + /** Set the RC channel */ + void setPitchChan(int channel) { + rcMapping[1] = channel - 1; + updateMappingView(1); + } + /** Set the RC channel */ + void setYawChan(int channel) { + rcMapping[2] = channel - 1; + updateMappingView(2); + } + /** Set the RC channel */ + void setThrottleChan(int channel) { + rcMapping[3] = channel - 1; + updateMappingView(3); + } + /** Set the RC channel */ + void setModeChan(int channel) { + rcMapping[4] = channel - 1; + updateMappingView(4); + } + /** Set the RC channel */ + void setAssistChan(int channel) { + rcMapping[5] = channel - 1; + updateMappingView(5); + } + /** Set the RC channel */ + void setMissionChan(int channel) { + rcMapping[6] = channel - 1; + updateMappingView(6); + } + /** Set the RC channel */ + void setReturnChan(int channel) { + rcMapping[7] = channel - 1; + updateMappingView(7); + } + /** Set the RC channel */ + void setFlapsChan(int channel) { + rcMapping[8] = channel - 1; + updateMappingView(8); + } + /** Set the RC channel */ + void setAux1Chan(int channel) { + rcMapping[9] = channel - 1; + updateMappingView(9); + } + /** Set the RC channel */ + void setAux2Chan(int channel) { + rcMapping[10] = channel - 1; + updateMappingView(10); + } + + /** Set channel inversion status */ + void setRollInverted(bool inverted) { + rcRev[rcMapping[0]] = inverted; + updateMappingView(0); + } + /** Set channel inversion status */ + void setPitchInverted(bool inverted) { + rcRev[rcMapping[1]] = inverted; + updateMappingView(1); + } + /** Set channel inversion status */ + void setYawInverted(bool inverted) { + rcRev[rcMapping[2]] = inverted; + updateMappingView(2); + } + /** Set channel inversion status */ + void setThrottleInverted(bool inverted) { + rcRev[rcMapping[3]] = inverted; + updateMappingView(3); + } + /** Set channel inversion status */ + void setModeInverted(bool inverted) { + rcRev[rcMapping[4]] = inverted; + updateMappingView(4); + } + /** Set channel inversion status */ + void setAssistInverted(bool inverted) { + rcRev[rcMapping[5]] = inverted; + updateMappingView(5); + } + /** Set channel inversion status */ + void setMissionInverted(bool inverted) { + rcRev[rcMapping[6]] = inverted; + updateMappingView(6); + } + /** Set channel inversion status */ + void setReturnInverted(bool inverted) { + rcRev[rcMapping[7]] = inverted; + updateMappingView(7); + } + /** Set channel inversion status */ + void setFlapsInverted(bool inverted) { + rcRev[rcMapping[8]] = inverted; + updateMappingView(8); + } + /** Set channel inversion status */ + void setAux1Inverted(bool inverted) { + rcRev[rcMapping[9]] = inverted; + updateMappingView(9); + } + /** Set channel inversion status */ + void setAux2Inverted(bool inverted) { + rcRev[rcMapping[10]] = inverted; + updateMappingView(10); + } + + /** Identify roll */ + void identifyRollChannel() { + identifyChannelMapping(0); + } + + /** Identify pitch */ + void identifyPitchChannel() { + identifyChannelMapping(1); + } + + /** Identify yaw */ + void identifyYawChannel() { + identifyChannelMapping(2); + } + + /** Identify throttle */ + void identifyThrottleChannel() { + identifyChannelMapping(3); + } + + /** Identify mode */ + void identifyModeChannel() { + identifyChannelMapping(4); + } + + /** Identify assist channel */ + void identifyAssistChannel() { + identifyChannelMapping(5); + } + + /** Identify mission channel */ + void identifyMissionChannel() { + identifyChannelMapping(6); + } + + /** Identify return channel */ + void identifyReturnChannel() { + identifyChannelMapping(7); + } + + /** Identify flaps channel */ + void identifyFlapsChannel() { + identifyChannelMapping(8); + } + + /** Identify aux 1 */ + void identifyAux1Channel() { + identifyChannelMapping(9); + } + + /** Identify aux 2 */ + void identifyAux2Channel() { + identifyChannelMapping(10); + } + +protected slots: + void menuButtonClicked(); + /** Reset the RC calibration */ + void resetCalibrationRC(); + /** Write the RC calibration */ + void writeCalibrationRC(); + /** Request the RC calibration */ + void requestCalibrationRC(); + /** Store all parameters in onboard EEPROM */ + void writeParameters(); + /** Receive remote control updates from MAV */ + void remoteControlChannelRawChanged(int chan, float val); + /** Parameter changed onboard */ + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void updateStatus(const QString& str); + void updateError(const QString& str); + /** Check timeouts */ + void checktimeOuts(); + /** Update checkbox status */ + void updateAllInvertedCheckboxes(); + /** Update mapping view state */ + void updateMappingView(int index); + /** Update the displayed values */ + void updateRcWidgetValues(); + /** update the channel labels */ + void updateRcChanLabels(); + + QString labelForRcValue(float val) { + return QString("%1").arg(val, 5, 'f', 2, QChar(' ')); + } + +protected: + + void setChannelToFunctionMapping(int function, int channel); + + bool doneLoadingConfig; + UASInterface* mav; ///< The current MAV + QGCUASParamManager* paramMgr; ///< params mgr for the mav + static const unsigned int chanMax = 14; ///< Maximum number of channels + static const unsigned int chanMappedMax = 16; ///< Maximum number of mapped channels (can be higher than input channel count) + unsigned int chanCount; ///< Actual channels + float rcMin[chanMax]; ///< Minimum values + float rcMax[chanMax]; ///< Maximum values + float rcTrim[chanMax]; ///< Zero-position (center for roll/pitch/yaw, 0 throttle for throttle) + int rcMapping[chanMappedMax]; ///< PWM to function mappings + int rcToFunctionMapping[chanMax]; + float rcScaling[chanMax]; ///< Scaling of channel input to control commands + bool rcRev[chanMax]; ///< Channel reverse + int rcValue[chanMax]; ///< Last values, RAW + int rcValueReversed[chanMax]; ///< Last values, accounted for reverse + int rcMappedMin[chanMappedMax]; ///< Mapped channels in default order + int rcMappedMax[chanMappedMax]; ///< Mapped channels in default order + int rcMappedValue[chanMappedMax]; ///< Mapped channels in default order + int rcMappedValueRev[chanMappedMax]; + float rcMappedNormalizedValue[chanMappedMax]; ///< Mapped channels in default order + int channelWanted; ///< During channel assignment search the requested default index + int channelReverseStateWanted; + float channelWantedList[chanMax]; ///< During channel assignment search the start values + float channelReverseStateWantedList[chanMax]; + QStringList channelNames; ///< List of channel names in standard order + float rcRoll; ///< PPM input channel used as roll control input + float rcPitch; ///< PPM input channel used as pitch control input + float rcYaw; ///< PPM input channel used as yaw control input + float rcThrottle; ///< PPM input channel used as throttle control input + float rcMode; ///< PPM input channel used as mode switch control input + float rcAssist; ///< PPM input channel used as assist switch control input + float rcMission; ///< PPM input channel used as mission switch control input + float rcReturn; ///< PPM input channel used as return switch control input + float rcFlaps; ///< PPM input channel used as flaps control input + float rcAux1; ///< PPM input channel used as aux 1 input + float rcAux2; ///< PPM input channel used as aux 2 input + bool rcCalChanged; ///< Set if the calibration changes (and needs to be written) + bool dataModelChanged; ///< Set if any of the input data changed + QTimer updateTimer; ///< Controls update intervals + QList toolWidgets; ///< Configurable widgets + QMap toolWidgetsByName; ///< + bool calibrationEnabled; ///< calibration mode on / off + bool configEnabled; ///< config mode on / off + + QMap paramToWidgetMap; ///< Holds the current active MAV's parameter widgets. + QList additionalTabs; ///< Stores additional tabs loaded for this vehicle/autopilot configuration. Used for cleaning up. + QMap libParamToWidgetMap; ///< Holds the library parameter widgets + QMap > systemTypeToParamMap; ///< Holds all loaded MAV specific parameter widgets, for every MAV. + QMap toolToBoxMap; ///< Easy method of figuring out which QGroupBox is tied to which ToolWidget. + QMap paramTooltips; ///< Tooltips for the ? button next to a parameter. + + QGCPX4AirframeConfig* px4AirframeConfig; + DialogBare* firmwareDialog; + QPixmap planeBack; + QPixmap planeSide; + QGCPX4SensorCalibration* px4SensorCalibration; + QMessageBox msgBox; + QGraphicsScene scene; + QPushButton* skipActionButton; + +private: + Ui::QGCPX4VehicleConfig *ui; + QMap buttonToWidgetMap; +signals: + void visibilityChanged(bool visible); +}; + +#endif // QGCPX4VehicleConfig_H diff --git a/src/ui/QGCPX4VehicleConfig.ui b/src/ui/QGCPX4VehicleConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..ffd58d5f007cde5c95678e52ea69d50b439b1de5 --- /dev/null +++ b/src/ui/QGCPX4VehicleConfig.ui @@ -0,0 +1,1290 @@ + + + QGCPX4VehicleConfig + + + + 0 + 0 + 1256 + 1009 + + + + + 0 + 0 + + + + Form + + + + 0 + + + + + + 16 + 75 + true + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 50 + 200 + + + + + 50 + 200 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 1 + 0 + + + + + 50 + 200 + + + + + 50 + 200 + + + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + + Start Calibration + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Spektrum RC + + + + + + Pair Receiver + + + + + + + DSM2 Mode + + + true + + + + + + + DSMX Mode (3 to 7 channels) + + + + + + + DSMX Mode (8 or more channels) + + + + + + + + + + + + + + Waiting for RC channel data.. + + + + + + + Show Advanced Configuration Options + + + + + + + + + + Stick to Channel Mapping and Reverse + + + + + + + + Assist Switch + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 0000 + + + Qt::AlignCenter + + + + + + + Reverse + + + + + + + false + + + 0 + + + 16 + + + + + + + Identify Aux 1 Channel + + + + + + + Mapping to Index of RC Channel used for (0 if not used) + + + + + + + Return Switch + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 0000 + + + Qt::AlignCenter + + + + + + + Aux 1 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Identify Mode Switch + + + + + + + Identify Yaw Channel + + + + + + + false + + + 0 + + + 16 + + + + + + + 0000 + + + Qt::AlignCenter + + + + + + + Pitch / Elevator + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Reverse / Invert + + + + + + + Yaw / Rudder + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + false + + + 0 + + + 16 + + + + + + + Reverse + + + + + + + 0000 + + + Qt::AlignCenter + + + + + + + 0000 + + + Qt::AlignCenter + + + + + + + false + + + 0 + + + 16 + + + + + + + false + + + 0 + + + 16 + + + + + + + Reverse + + + + + + + 0000 + + + Qt::AlignCenter + + + + + + + Mode Switch + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Identify Aux 2 Channel + + + + + + + false + + + 0 + + + 16 + + + + + + + Roll / Ailerons + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Identify Throttle Channel + + + + + + + Channel Name + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Reverse + + + + + + + 0000 + + + Qt::AlignCenter + + + + + + + Identify Assist Switch + + + + + + + Aux 2 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Reverse + + + + + + + false + + + 0 + + + 16 + + + + + + + 0000 + + + Qt::AlignCenter + + + + + + + Reverse + + + + + + + Normalized Value + + + Qt::AlignCenter + + + + + + + Reverse + + + + + + + Identify Pitch Channel + + + + + + + Reverse + + + + + + + 0000 + + + Qt::AlignCenter + + + + + + + false + + + 0 + + + 16 + + + + + + + Identify Roll Channel + + + + + + + Mission Switch + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 0000 + + + Qt::AlignCenter + + + + + + + Throttle + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Flaps + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 0000 + + + Qt::AlignCenter + + + + + + + Reverse + + + + + + + Reverse + + + + + + + Reverse + + + + + + + false + + + + + + + false + + + + + + + false + + + ArrowCursor + + + + + + + Identify Mission Switch + + + + + + + Identify Return Switch + + + + + + + Identify Flaps Channel + + + + + + + + + Persist RC Mapping and Calibration + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 16 + 75 + true + + + + + + + + + + + 16 + 75 + true + + + + + + + + + Configuration + + + + 0 + + + + + true + + + + + 0 + 0 + 16 + 16 + + + + + 0 + + + + + + + + + + + + + + + Configuration + + + + 0 + + + + + true + + + + + 0 + 0 + 16 + 16 + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + 3 + 1 + + + + Onboard Configuration + + + + 0 + + + + + true + + + + + 0 + 0 + 16 + 16 + + + + + 0 + + + + + + + true + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 10 + 20 + + + + + + + + + 2 + 0 + + + + + 329 + 0 + + + + Changes Pending + + + + + + -1 + + + + + + 0 + 0 + + + + true + + + + + + + + + + + + Qt::Horizontal + + + + 10 + 20 + + + + + + + + + + Status + + + + + + + + + + + + + + 0 + + + + + QLayout::SetMinAndMaxSize + + + 12 + + + 12 + + + 24 + + + 12 + + + + + Firmware +Upgrade + + + + :/files/images/px4/menu/firmware_upgrade.png:/files/images/px4/menu/firmware_upgrade.png + + + + 64 + 64 + + + + + + + + + 100 + 75 + + + + + 16777215 + 16777215 + + + + Radio +Calibration + + + + :/files/images/px4/menu/remote.png:/files/images/px4/menu/remote.png + + + + 64 + 64 + + + + + + + + + 100 + 75 + + + + Sensor +Calibration + + + + :/files/images/px4/menu/sensors.png:/files/images/px4/menu/sensors.png + + + + 64 + 64 + + + + + + + + Airframe +Config + + + + :/files/images/px4/menu/plane.png:/files/images/px4/menu/plane.png + + + + 64 + 64 + + + + + + + + + 100 + 75 + + + + General +Config + + + + :/files/images/px4/menu/cogwheels.png:/files/images/px4/menu/cogwheels.png + + + + 64 + 64 + + + + + + + + + 100 + 75 + + + + Advanced +Config + + + + :/files/images/px4/menu/cogwheels.png:/files/images/px4/menu/cogwheels.png + + + + 64 + 64 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + QGCRadioChannelDisplay + QWidget +
ui/designer/QGCRadioChannelDisplay.h
+ 1 +
+ + QGCPendingParamWidget + QWidget +
ui/QGCPendingParamWidget.h
+ 1 +
+ + QGCParamWidget + QWidget +
ui/QGCParamWidget.h
+ 1 +
+
+ + + + +
diff --git a/src/ui/QGCParamWidget.cc b/src/ui/QGCParamWidget.cc index 7f02609c15ffe1205ee276a40747e1576c93d440..a81782238573ceaadd54ad9446c4c4c87ecedae6 100644 --- a/src/ui/QGCParamWidget.cc +++ b/src/ui/QGCParamWidget.cc @@ -27,107 +27,130 @@ This file is part of the QGROUNDCONTROL project */ #include #include -#include -#include -#include +#include +#include #include +#include +#include + #include -#include -#include #include -#include +#include +#include +#include -#include "QGCParamWidget.h" -#include "UASInterface.h" #include "MainWindow.h" -#include #include "QGC.h" +#include "QGCParamWidget.h" +#include "UASInterface.h" +#include "UASParameterCommsMgr.h" /** * @param uas MAV to set the parameters on * @param parent Parent widget */ -QGCParamWidget::QGCParamWidget(UASInterface* uas, QWidget *parent) : - QGCUASParamManager(uas, parent), - components(new QMap()) +QGCParamWidget::QGCParamWidget(QWidget *parent) : + QGCBaseParamWidget(parent), + componentItems(new QMap()), + statusLabel(new QLabel(this)), + tree(new QTreeWidget(this)) { - // Load settings - loadSettings(); - // Load default values and tooltips - QString hey(uas->getAutopilotTypeName()); - QString hey2(uas->getSystemTypeName()); - loadParameterInfoCSV(hey, hey2); - // Create tree widget - tree = new QTreeWidget(this); - statusLabel = new QLabel(); - statusLabel->setAutoFillBackground(true); - tree->setColumnWidth(70, 30); - - // Set tree widget as widget onto this component - QGridLayout* horizontalLayout; - //form->setAutoFillBackground(false); - horizontalLayout = new QGridLayout(this); - horizontalLayout->setHorizontalSpacing(6); - horizontalLayout->setVerticalSpacing(6); - horizontalLayout->setMargin(0); - horizontalLayout->setSizeConstraint(QLayout::SetMinimumSize); - //horizontalLayout->setSizeConstraint( QLayout::SetFixedSize ); +} - // Parameter tree - horizontalLayout->addWidget(tree, 0, 0, 1, 3); - // Status line - statusLabel->setText(tr("Click refresh to download parameters")); - horizontalLayout->addWidget(statusLabel, 1, 0, 1, 3); +void QGCParamWidget::disconnectViewSignalsAndSlots() +{ + disconnect(tree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), + this, SLOT(parameterItemChanged(QTreeWidgetItem*,int))); +} - // BUTTONS + +void QGCParamWidget::connectViewSignalsAndSlots() +{ + // Listen for edits to the tree UI + connect(tree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), + this, SLOT(parameterItemChanged(QTreeWidgetItem*,int))); +} + + +void QGCParamWidget::addActionButtonsToLayout(QGridLayout* layout) +{ QPushButton* refreshButton = new QPushButton(tr("Get")); - refreshButton->setToolTip(tr("Load parameters currently in non-permanent memory of aircraft.")); - refreshButton->setWhatsThis(tr("Load parameters currently in non-permanent memory of aircraft.")); - connect(refreshButton, SIGNAL(clicked()), this, SLOT(requestParameterList())); - horizontalLayout->addWidget(refreshButton, 2, 0); + refreshButton->setToolTip(tr("Fetch parameters currently in volatile memory of aircraft.")); + refreshButton->setWhatsThis(tr("Fetch parameters currently in volatile memory of aircraft.")); + connect(refreshButton, SIGNAL(clicked()), + this, SLOT(requestOnboardParamsUpdate())); + layout->addWidget(refreshButton, 2, 0); QPushButton* setButton = new QPushButton(tr("Set")); - setButton->setToolTip(tr("Set current parameters in non-permanent onboard memory")); - setButton->setWhatsThis(tr("Set current parameters in non-permanent onboard memory")); - connect(setButton, SIGNAL(clicked()), this, SLOT(setParameters())); - horizontalLayout->addWidget(setButton, 2, 1); + setButton->setToolTip(tr("Send pending parameters to volatile onboard memory")); + setButton->setWhatsThis(tr("Send pending parameters to volatile onboard memory")); + connect(setButton, SIGNAL(clicked()), + paramMgr, SLOT(sendPendingParameters())); + layout->addWidget(setButton, 2, 1); QPushButton* writeButton = new QPushButton(tr("Write (ROM)")); - writeButton->setToolTip(tr("Copy current parameters in non-permanent memory of the aircraft to permanent memory. Transmit your parameters first to write these.")); - writeButton->setWhatsThis(tr("Copy current parameters in non-permanent memory of the aircraft to permanent memory. Transmit your parameters first to write these.")); - connect(writeButton, SIGNAL(clicked()), this, SLOT(writeParameters())); - horizontalLayout->addWidget(writeButton, 2, 2); + writeButton->setToolTip(tr("Copy parameters in volatile memory of the aircraft to persistent memory. Transmit your parameters first to write these.")); + writeButton->setWhatsThis(tr("Copy parameters in volatile memory of the aircraft to persistent memory. Transmit your parameters first to write these.")); + connect(writeButton, SIGNAL(clicked()), + paramMgr, SLOT(copyVolatileParamsToPersistent())); + layout->addWidget(writeButton, 2, 2); QPushButton* loadFileButton = new QPushButton(tr("Load File")); - loadFileButton->setToolTip(tr("Load parameters from a file on this computer in the view. To write them to the aircraft, use transmit after loading them.")); - loadFileButton->setWhatsThis(tr("Load parameters from a file on this computer in the view. To write them to the aircraft, use transmit after loading them.")); - connect(loadFileButton, SIGNAL(clicked()), this, SLOT(loadParameters())); - horizontalLayout->addWidget(loadFileButton, 3, 0); + loadFileButton->setToolTip(tr("Load parameters from a file into qgroundcontrol. To write these to the aircraft, use transmit after loading them.")); + loadFileButton->setWhatsThis(tr("Load parameters from a file into qgroundcontrol. To write these to the aircraft, use transmit after loading them.")); + connect(loadFileButton, SIGNAL(clicked()), + this, SLOT(loadParametersFromFile())); + layout->addWidget(loadFileButton, 3, 0); QPushButton* saveFileButton = new QPushButton(tr("Save File")); saveFileButton->setToolTip(tr("Save parameters in this view to a file on this computer.")); saveFileButton->setWhatsThis(tr("Save parameters in this view to a file on this computer.")); - connect(saveFileButton, SIGNAL(clicked()), this, SLOT(saveParameters())); - horizontalLayout->addWidget(saveFileButton, 3, 1); + connect(saveFileButton, SIGNAL(clicked()), + this, SLOT(saveParametersToFile())); + layout->addWidget(saveFileButton, 3, 1); QPushButton* readButton = new QPushButton(tr("Read (ROM)")); - readButton->setToolTip(tr("Copy parameters from permanent memory to non-permanent current memory of aircraft. DOES NOT update the parameters in this view, click refresh after copying them to get them.")); - readButton->setWhatsThis(tr("Copy parameters from permanent memory to non-permanent current memory of aircraft. DOES NOT update the parameters in this view, click refresh after copying them to get them.")); - connect(readButton, SIGNAL(clicked()), this, SLOT(readParameters())); - horizontalLayout->addWidget(readButton, 3, 2); + readButton->setToolTip(tr("Copy parameters from persistent onboard memory to volatile onboard memory of aircraft. DOES NOT update the parameters in this view: click refresh after copying them to get them.")); + readButton->setWhatsThis(tr("Copy parameters from persistent onboard memory to volatile onboard memory of aircraft. DOES NOT update the parameters in this view: click refresh after copying them to get them.")); + connect(readButton, SIGNAL(clicked()), + paramMgr, SLOT(copyPersistentParamsToVolatile())); + layout->addWidget(readButton, 3, 2); + +} + +void QGCParamWidget::layoutWidget() +{ + + statusLabel->setAutoFillBackground(true); + + QGridLayout* layout = new QGridLayout(this); + layout->setHorizontalSpacing(6); + layout->setVerticalSpacing(6); + layout->setMargin(0); + layout->setSizeConstraint(QLayout::SetMinimumSize); + + // Parameter tree + layout->addWidget(tree, 0, 0, 1, 3); + + // Status line + statusLabel->setText(tr("Click refresh to download parameters")); + layout->addWidget(statusLabel, 1, 0, 1, 3); + + // BUTTONS + addActionButtonsToLayout(layout); // Set correct vertical scaling - horizontalLayout->setRowStretch(0, 100); - horizontalLayout->setRowStretch(1, 10); - horizontalLayout->setRowStretch(2, 10); - horizontalLayout->setRowStretch(3, 10); + layout->setRowStretch(0, 100); + layout->setRowStretch(1, 10); + layout->setRowStretch(2, 10); + layout->setRowStretch(3, 10); // Set layout - this->setLayout(horizontalLayout); + this->setLayout(layout); // Set header QStringList headerItems; @@ -135,1047 +158,325 @@ QGCParamWidget::QGCParamWidget(UASInterface* uas, QWidget *parent) : headerItems.append("Value"); tree->setHeaderLabels(headerItems); tree->setColumnCount(2); + tree->setColumnWidth(0,200); + tree->setColumnWidth(1,120); tree->setExpandsOnDoubleClick(true); - // Connect signals/slots - connect(this, SIGNAL(parameterChanged(int,QString,QVariant)), mav, SLOT(setParameter(int,QString,QVariant))); - connect(tree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(parameterItemChanged(QTreeWidgetItem*,int))); - - // New parameters from UAS - connect(uas, SIGNAL(parameterChanged(int,int,int,int,QString,QVariant)), this, SLOT(addParameter(int,int,int,int,QString,QVariant))); - - // Connect retransmission guard - connect(this, SIGNAL(requestParameter(int,QString)), uas, SLOT(requestParameter(int,QString))); - connect(this, SIGNAL(requestParameter(int,int)), uas, SLOT(requestParameter(int,int))); - connect(&retransmissionTimer, SIGNAL(timeout()), this, SLOT(retransmissionGuardTick())); - - // Get parameters - if (uas) requestParameterList(); + tree->setVisible(true); } -void QGCParamWidget::loadSettings() -{ - QSettings settings; - settings.beginGroup("QGC_MAVLINK_PROTOCOL"); - bool ok; - int temp = settings.value("PARAMETER_RETRANSMISSION_TIMEOUT", retransmissionTimeout).toInt(&ok); - if (ok) retransmissionTimeout = temp; - temp = settings.value("PARAMETER_REWRITE_TIMEOUT", rewriteTimeout).toInt(&ok); - if (ok) rewriteTimeout = temp; - settings.endGroup(); -} -void QGCParamWidget::loadParameterInfoCSV(const QString& autopilot, const QString& airframe) +void QGCParamWidget::addComponentItem(int compId, QString compName) { - Q_UNUSED(airframe); - - qDebug() << "ATTEMPTING TO LOAD CSV"; - QDir appDir = QApplication::applicationDirPath(); - appDir.cd("files"); - QString fileName = QString("%1/%2/parameter_tooltips/tooltips.txt").arg(appDir.canonicalPath()).arg(autopilot.toLower()); - QFile paramMetaFile(fileName); + QString compLine = QString("%1 (#%2)").arg(compName).arg(compId); - qDebug() << "AUTOPILOT:" << autopilot; - qDebug() << "FILENAME: " << fileName; + //QString ptrStr = QString().sprintf("%8p", this); + //qDebug() << "QGCParamWidget" << ptrStr << "addComponentItem:" << compLine; - // Load CSV data - if (!paramMetaFile.open(QIODevice::ReadOnly | QIODevice::Text)) - { - //qDebug() << "COULD NOT OPEN PARAM META INFO FILE:" << fileName; - return; + if (componentItems->contains(compId)) { + // Update existing component item + componentItems->value(compId)->setData(0, Qt::DisplayRole, compLine); + //components->value(component)->setData(1, Qt::DisplayRole, QString::number(component)); + componentItems->value(compId)->setFirstColumnSpanned(true); + } else { + // Add new component item + QStringList list(compLine); + QTreeWidgetItem* compItem = new QTreeWidgetItem(list); + compItem->setFirstColumnSpanned(true); + componentItems->insert(compId, compItem); + // Create parameter grouping for this component and update maps + paramGroups.insert(compId, new QMap()); + tree->addTopLevelItem(compItem); + tree->update(); } - // Extract header - - // Read in values - // Find all keys - QTextStream in(¶mMetaFile); +} - // First line is header - // there might be more lines, but the first - // line is assumed to be at least header - QString header = in.readLine(); +void QGCParamWidget::handlePendingParamUpdate(int compId, const QString& paramName, QVariant value, bool isPending) +{ + //qDebug() << "handlePendingParamUpdate:" << paramName << "with updatingParamNameLock:" << updatingParamNameLock; - // Ignore top-level comment lines - while (header.startsWith('#') || header.startsWith('/') - || header.startsWith('=') || header.startsWith('^')) - { - header = in.readLine(); + if (updatingParamNameLock == paramName) { + //qDebug() << "ignoring bounce from " << paramName; + return; } - - bool charRead = false; - QString separator = ""; - QList sepCandidates; - sepCandidates << '\t'; - sepCandidates << ','; - sepCandidates << ';'; - //sepCandidates << ' '; - sepCandidates << '~'; - sepCandidates << '|'; - - // Iterate until separator is found - // or full header is parsed - for (int i = 0; i < header.length(); i++) - { - if (sepCandidates.contains(header.at(i))) - { - // Separator found - if (charRead) - { - separator += header[i]; - } - } - else - { - // Char found - charRead = true; - // If the separator is not empty, this char - // has been read after a separator, so detection - // is now complete - if (separator != "") break; - } + else { + updatingParamNameLock = paramName; } - bool stripFirstSeparator = false; - bool stripLastSeparator = false; - - // Figure out if the lines start with the separator (e.g. wiki syntax) - if (header.startsWith(separator)) stripFirstSeparator = true; - - // Figure out if the lines end with the separator (e.g. wiki syntax) - if (header.endsWith(separator)) stripLastSeparator = true; - - QString out = separator; - out.replace("\t", ""); - //qDebug() << " Separator: \"" << out << "\""; - //qDebug() << "READING CSV:" << header; - - - // Read data - while (!in.atEnd()) - { - QString line = in.readLine(); - - //qDebug() << "LINE PRE-STRIP" << line; - - // Strip separtors if necessary - if (stripFirstSeparator) line.remove(0, separator.length()); - if (stripLastSeparator) line.remove(line.length()-separator.length(), line.length()-1); - - //qDebug() << "LINE POST-STRIP" << line; - - // Keep empty parts here - we still have to act on them - QStringList parts = line.split(separator, QString::KeepEmptyParts); - - // Each line is: - // variable name, Min, Max, Default, Multiplier, Enabled (0 = no, 1 = yes), Comment + QTreeWidgetItem* paramItem = updateParameterDisplay(compId,paramName,value); + if (isPending) { + paramItem->setBackground(0, QBrush(QColor(QGC::colorOrange))); + paramItem->setBackground(1, QBrush(QColor(QGC::colorOrange))); + //ensure that the adjusted item is visible + tree->expandItem(paramItem->parent()); + } + else { + paramItem->setBackground(0, Qt::NoBrush); + paramItem->setBackground(1, Qt::NoBrush); + } + updatingParamNameLock.clear(); - // Fill in min, max and default values - if (parts.count() > 1) - { - // min - paramMin.insert(parts.at(0).trimmed(), parts.at(1).toDouble()); - } - if (parts.count() > 2) - { - // max - paramMax.insert(parts.at(0).trimmed(), parts.at(2).toDouble()); - } - if (parts.count() > 3) - { - // default - paramDefault.insert(parts.at(0).trimmed(), parts.at(3).toDouble()); - } - // IGNORING 4 and 5 for now - if (parts.count() > 6) - { - // tooltip - paramToolTips.insert(parts.at(0).trimmed(), parts.at(6).trimmed()); - qDebug() << "PARAM META:" << parts.at(0).trimmed(); - } - } } -/** - * @return The MAV of this widget. Unless the MAV object has been destroyed, this - * pointer is never zero. - */ -UASInterface* QGCParamWidget::getUAS() +void QGCParamWidget::handleOnboardParamUpdate(int compId, const QString& paramName, QVariant value) { - return mav; -} - -/** - * - * @param uas System which has the component - * @param component id of the component - * @param componentName human friendly name of the component - */ -void QGCParamWidget::addComponent(int uas, int component, QString componentName) -{ - Q_UNUSED(uas); - if (components->contains(component)) { - // Update existing - components->value(component)->setData(0, Qt::DisplayRole, QString("%1 (#%2)").arg(componentName).arg(component)); - //components->value(component)->setData(1, Qt::DisplayRole, QString::number(component)); - components->value(component)->setFirstColumnSpanned(true); - } else { - // Add new - QStringList list(QString("%1 (#%2)").arg(componentName).arg(component)); - QTreeWidgetItem* comp = new QTreeWidgetItem(list); - comp->setFirstColumnSpanned(true); - components->insert(component, comp); - // Create grouping and update maps - paramGroups.insert(component, new QMap()); - tree->addTopLevelItem(comp); - tree->update(); - // Create map in parameters - if (!parameters.contains(component)) { - parameters.insert(component, new QMap()); - } - // Create map in changed parameters - if (!changedValues.contains(component)) { - changedValues.insert(component, new QMap()); - } + //qDebug() << "handlePendingParamUpdate:" << paramName << "with updatingParamNameLock:" << updatingParamNameLock; + if (paramName == updatingParamNameLock) { + //qDebug() << "handlePendingParamUpdate ignoring bounce from " << paramName; + return; } + updatingParamNameLock = paramName; + updateParameterDisplay(compId, paramName, value); + updatingParamNameLock.clear(); } -/** - * @param uas System which has the component - * @param component id of the component - * @param parameterName human friendly name of the parameter - */ -void QGCParamWidget::addParameter(int uas, int component, int paramCount, int paramId, QString parameterName, QVariant value) -{ - addParameter(uas, component, parameterName, value); - // Missing packets list has to be instantiated for all components - if (!transmissionMissingPackets.contains(component)) { - transmissionMissingPackets.insert(component, new QList()); - } +void QGCParamWidget::handleOnboardParameterListUpToDate() +{ + //turn off updates while we refresh the entire list + tree->setUpdatesEnabled(false); - // List mode is different from single parameter transfers - if (transmissionListMode) { - // Only accept the list size once on the first packet from - // each component - if (!transmissionListSizeKnown.contains(component)) - { - // Mark list size as known - transmissionListSizeKnown.insert(component, true); - - // Mark all parameters as missing - for (int i = 0; i < paramCount; ++i) - { - if (!transmissionMissingPackets.value(component)->contains(i)) - { - transmissionMissingPackets.value(component)->append(i); - } - } + //rewrite the component item tree after receiving the full list + QMap*>::iterator i; + QMap*>* onboardParams = paramMgr->dataModel()->getAllOnboardParams(); - // There is only one transmission timeout for all components - // since components do not manage their transmission, - // the longest timeout is safe for all components. - quint64 thisTransmissionTimeout = QGC::groundTimeMilliseconds() + ((paramCount)*retransmissionTimeout); - if (thisTransmissionTimeout > transmissionTimeout) - { - transmissionTimeout = thisTransmissionTimeout; - } + for (i = onboardParams->begin(); i != onboardParams->end(); ++i) { + int compId = i.key(); + QMap* paramPairs = onboardParams->value(compId); + QMap::iterator j; + for (j = paramPairs->begin(); j != paramPairs->end(); j++) { + updatingParamNameLock = j.key(); + updateParameterDisplay(compId, j.key(),j.value()); + updatingParamNameLock.clear(); } - - // Start retransmission guard - // or reset timer - setRetransmissionGuardEnabled(true); } - // Mark this parameter as received in read list - int index = transmissionMissingPackets.value(component)->indexOf(paramId); - // If the MAV sent the parameter without request, it wont be in missing list - if (index != -1) transmissionMissingPackets.value(component)->removeAt(index); - - bool justWritten = false; - bool writeMismatch = false; - //bool lastWritten = false; - // Mark this parameter as received in write ACK list - QMap* map = transmissionMissingWriteAckPackets.value(component); - if (map && map->contains(parameterName)) - { - justWritten = true; - QVariant newval = map->value(parameterName); - if (map->value(parameterName) != value) - { - writeMismatch = true; - } - map->remove(parameterName); - } + // Expand visual tree + tree->expandItem(tree->topLevelItem(0)); + tree->setUpdatesEnabled(true); + tree->update(); - int missCount = 0; - foreach (int key, transmissionMissingPackets.keys()) - { - missCount += transmissionMissingPackets.value(key)->count(); - } +} - int missWriteCount = 0; - foreach (int key, transmissionMissingWriteAckPackets.keys()) - { - missWriteCount += transmissionMissingWriteAckPackets.value(key)->count(); - } +QTreeWidgetItem* QGCParamWidget::findChildWidgetItemForParam(QTreeWidgetItem* parentItem, const QString& paramName) +{ + QTreeWidgetItem* childItem = NULL; - if (justWritten && !writeMismatch && missWriteCount == 0) - { - // Just wrote one and count went to 0 - this was the last missing write parameter - statusLabel->setText(tr("SUCCESS: WROTE ALL PARAMETERS")); - QPalette pal = statusLabel->palette(); - pal.setColor(backgroundRole(), QGC::colorGreen); - statusLabel->setPalette(pal); - } else if (justWritten && !writeMismatch) - { - statusLabel->setText(tr("SUCCESS: Wrote %2 (#%1/%4): %3").arg(paramId+1).arg(parameterName).arg(value.toDouble()).arg(paramCount)); - QPalette pal = statusLabel->palette(); - pal.setColor(backgroundRole(), QGC::colorGreen); - statusLabel->setPalette(pal); - } else if (justWritten && writeMismatch) - { - // Mismatch, tell user - QPalette pal = statusLabel->palette(); - pal.setColor(backgroundRole(), QGC::colorRed); - statusLabel->setPalette(pal); - statusLabel->setText(tr("FAILURE: Wrote %1: sent %2 != onboard %3").arg(parameterName).arg(map->value(parameterName).toDouble()).arg(value.toDouble())); - } - else - { - if (missCount > 0) - { - QPalette pal = statusLabel->palette(); - pal.setColor(backgroundRole(), QGC::colorOrange); - statusLabel->setPalette(pal); - } - else - { - QPalette pal = statusLabel->palette(); - pal.setColor(backgroundRole(), QGC::colorGreen); - statusLabel->setPalette(pal); - } - QString val = QString("%1").arg(value.toFloat(), 5, 'f', 1, QChar(' ')); - //statusLabel->setText(tr("OK: %1 %2 #%3/%4, %5 miss").arg(parameterName).arg(val).arg(paramId+1).arg(paramCount).arg(missCount)); - if (missCount == 0) - { - // Transmission done - QTime time = QTime::currentTime(); - QString timeString = time.toString(); - statusLabel->setText(tr("All received. (updated at %1)").arg(timeString)); - } - else - { - // Transmission in progress - statusLabel->setText(tr("OK: %1 %2 (%3/%4)").arg(parameterName).arg(val).arg(paramCount-missCount).arg(paramCount)); + for (int i = 0; i < parentItem->childCount(); i++) { + QTreeWidgetItem* child = parentItem->child(i); + QString key = child->data(0, Qt::DisplayRole).toString(); + if (key == paramName) { + childItem = child; + break; } } - // Check if last parameter was received - if (missCount == 0 && missWriteCount == 0) - { - this->transmissionActive = false; - this->transmissionListMode = false; - transmissionListSizeKnown.clear(); - foreach (int key, transmissionMissingPackets.keys()) - { - transmissionMissingPackets.value(key)->clear(); - } - - // Expand visual tree - tree->expandItem(tree->topLevelItem(0)); - } + return childItem; } -/** - * @param uas System which has the component - * @param component id of the component - * @param parameterName human friendly name of the parameter - */ -void QGCParamWidget::addParameter(int uas, int component, QString parameterName, QVariant value) +QTreeWidgetItem* QGCParamWidget::getParentWidgetItemForParam(int compId, const QString& paramName) { - //qDebug() << "PARAM WIDGET GOT PARAM:" << value; - Q_UNUSED(uas); - // Reference to item in tree - QTreeWidgetItem* parameterItem = NULL; - - // Get component - if (!components->contains(component)) - { - // QString componentName; - // switch (component) - // { - // case MAV_COMP_ID_CAMERA: - // componentName = tr("Camera (#%1)").arg(component); - // break; - // case MAV_COMP_ID_IMU: - // componentName = tr("IMU (#%1)").arg(component); - // break; - // default: - // componentName = tr("Component #").arg(component); - // break; - // } - QString componentName = tr("Component #%1").arg(component); - addComponent(uas, component, componentName); - } - - // Replace value in map - - // FIXME - if (parameters.value(component)->contains(parameterName)) parameters.value(component)->remove(parameterName); - parameters.value(component)->insert(parameterName, value); - + QTreeWidgetItem* parentItem = componentItems->value(compId); QString splitToken = "_"; // Check if auto-grouping can work - if (parameterName.contains(splitToken)) - { - QString parent = parameterName.section(splitToken, 0, 0, QString::SectionSkipEmpty); - QMap* compParamGroups = paramGroups.value(component); - if (!compParamGroups->contains(parent)) - { + if (paramName.contains(splitToken)) { + QString parentStr = paramName.section(splitToken, 0, 0, QString::SectionSkipEmpty); + QMap* compParamGroups = paramGroups.value(compId); + if (!compParamGroups->contains(parentStr)) { // Insert group item QStringList glist; - glist.append(parent); - QTreeWidgetItem* item = new QTreeWidgetItem(glist); - compParamGroups->insert(parent, item); - components->value(component)->addChild(item); - } + glist.append(parentStr); + QTreeWidgetItem* groupItem = new QTreeWidgetItem(glist); - // Append child to group - bool found = false; - QTreeWidgetItem* parentItem = compParamGroups->value(parent); - for (int i = 0; i < parentItem->childCount(); i++) { - QTreeWidgetItem* child = parentItem->child(i); - QString key = child->data(0, Qt::DisplayRole).toString(); - if (key == parameterName) - { - //qDebug() << "UPDATED CHILD"; - parameterItem = child; - if (value.type() == QVariant::Char) - { - parameterItem->setData(1, Qt::DisplayRole, value.toUInt()); - } - else - { - parameterItem->setData(1, Qt::DisplayRole, value); - } - found = true; - } - } + compParamGroups->insert(parentStr, groupItem); - if (!found) - { - // Insert parameter into map - QStringList plist; - plist.append(parameterName); - // CREATE PARAMETER ITEM - parameterItem = new QTreeWidgetItem(plist); - // CONFIGURE PARAMETER ITEM - if (value.type() == QVariant::Char) - { - parameterItem->setData(1, Qt::DisplayRole, value.toUInt()); - } - else - { - parameterItem->setData(1, Qt::DisplayRole, value); - } - - compParamGroups->value(parent)->addChild(parameterItem); - parameterItem->setFlags(parameterItem->flags() | Qt::ItemIsEditable); - } - } - else - { - bool found = false; - QTreeWidgetItem* parent = components->value(component); - for (int i = 0; i < parent->childCount(); i++) - { - QTreeWidgetItem* child = parent->child(i); - QString key = child->data(0, Qt::DisplayRole).toString(); - if (key == parameterName) - { - //qDebug() << "UPDATED CHILD"; - parameterItem = child; - parameterItem->setData(1, Qt::DisplayRole, value); - found = true; - } + // insert new group alphabetized + QList groupKeys = compParamGroups->uniqueKeys(); + int insertIdx = groupKeys.indexOf(parentStr); + componentItems->value(compId)->insertChild(insertIdx,groupItem); } - if (!found) - { - // Insert parameter into map - QStringList plist; - plist.append(parameterName); - // CREATE PARAMETER ITEM - parameterItem = new QTreeWidgetItem(plist); - // CONFIGURE PARAMETER ITEM - parameterItem->setData(1, Qt::DisplayRole, value); - - components->value(component)->addChild(parameterItem); - parameterItem->setFlags(parameterItem->flags() | Qt::ItemIsEditable); - } - //tree->expandAll(); + //parent item for this parameter item will be a group widget item + parentItem = compParamGroups->value(parentStr); } - // Reset background color - parameterItem->setBackground(0, Qt::NoBrush); - parameterItem->setBackground(1, Qt::NoBrush); - // Add tooltip - QString tooltipFormat; - if (paramDefault.contains(parameterName)) - { - tooltipFormat = tr("Default: %1, %2"); - tooltipFormat = tooltipFormat.arg(paramDefault.value(parameterName, 0.0f)).arg(paramToolTips.value(parameterName, "")); + else { + //parent item for this parameter will be the top level (component) widget item + parentItem = componentItems->value(compId); } - else - { - tooltipFormat = paramToolTips.value(parameterName, ""); - } - parameterItem->setToolTip(0, tooltipFormat); - parameterItem->setToolTip(1, tooltipFormat); - //tree->update(); - if (changedValues.contains(component)) changedValues.value(component)->remove(parameterName); + return parentItem; } -/** - * Send a request to deliver the list of onboard parameters - * to the MAV. - */ -void QGCParamWidget::requestParameterList() +QTreeWidgetItem* QGCParamWidget::updateParameterDisplay(int compId, QString parameterName, QVariant value) { - if (!mav) return; - // FIXME This call does not belong here - // Once the comm handling is moved to a new - // Param manager class the settings can be directly - // loaded from MAVLink protocol - loadSettings(); - // End of FIXME - - // Clear view and request param list - clear(); - parameters.clear(); - received.clear(); - // Clear transmission state - transmissionListMode = true; - transmissionListSizeKnown.clear(); - foreach (int key, transmissionMissingPackets.keys()) - { - transmissionMissingPackets.value(key)->clear(); - } - transmissionActive = true; - - // Set status text - statusLabel->setText(tr("Requested param list.. waiting")); + //qDebug() << "QGCParamWidget::updateParameterDisplay" << parameterName; - mav->requestParameters(); -} + // Reference to item in tree + QTreeWidgetItem* paramItem = NULL; -void QGCParamWidget::parameterItemChanged(QTreeWidgetItem* current, int column) -{ - if (current && column > 0) { - QTreeWidgetItem* parent = current->parent(); - while (parent->parent() != NULL) { - parent = parent->parent(); - } - // Parent is now top-level component - int key = components->key(parent); - if (!changedValues.contains(key)) { - changedValues.insert(key, new QMap()); - } - QMap* map = changedValues.value(key, NULL); - if (map) { - QString str = current->data(0, Qt::DisplayRole).toString(); - QVariant value = current->data(1, Qt::DisplayRole); - // Set parameter on changed list to be transmitted to MAV - QPalette pal = statusLabel->palette(); - pal.setColor(backgroundRole(), QGC::colorOrange); - statusLabel->setPalette(pal); - statusLabel->setText(tr("Transmit pend. %1:%2: %3").arg(key).arg(str).arg(value.toFloat(), 5, 'f', 1, QChar(' '))); - //qDebug() << "PARAM CHANGED: COMP:" << key << "KEY:" << str << "VALUE:" << value; - // Changed values list - if (map->contains(str)) map->remove(str); - map->insert(str, value); - - // Check if the value was numerically changed - if (!parameters.value(key)->contains(str) || parameters.value(key)->value(str, value.toDouble()-1) != value) { - current->setBackground(0, QBrush(QColor(QGC::colorOrange))); - current->setBackground(1, QBrush(QColor(QGC::colorOrange))); - } + // Add component item if necessary + if (!componentItems->contains(compId)) { + QString componentName = tr("Component #%1").arg(compId); + addComponentItem(compId, componentName); + } - switch ((int)parameters.value(key)->value(str).type()) - { - case QVariant::Int: - { - QVariant fixedValue(value.toInt()); - parameters.value(key)->insert(str, fixedValue); - } - break; - case QVariant::UInt: - { - QVariant fixedValue(value.toUInt()); - parameters.value(key)->insert(str, fixedValue); - } - break; - case QMetaType::Float: - { - QVariant fixedValue(value.toFloat()); - parameters.value(key)->insert(str, fixedValue); + //default parent item for this parameter widget item will be the top level component item + QTreeWidgetItem* parentItem = getParentWidgetItemForParam(compId,parameterName); + if (parentItem) { + paramItem = findChildWidgetItemForParam(parentItem,parameterName); + if (!paramItem) { + // Insert parameter into map + QStringList plist; + plist.append(parameterName); + // CREATE PARAMETER ITEM + paramItem = new QTreeWidgetItem(plist); + // CONFIGURE PARAMETER ITEM + if (value.type() == QVariant::Char) { + paramItem->setData(1, Qt::DisplayRole, value.toUInt()); } - break; - case QMetaType::QChar: - { - QVariant fixedValue(QChar((unsigned char)value.toUInt())); - parameters.value(key)->insert(str, fixedValue); + else { + paramItem->setData(1, Qt::DisplayRole, value); } - break; - default: - qCritical() << "ABORTED PARAM UPDATE, NO VALID QVARIANT TYPE"; - return; + paramItem->setFlags(paramItem->flags() | Qt::ItemIsEditable); + + //TODO insert alphabetically + parentItem->addChild(paramItem); + + //only add the tooltip when the parameter item is first added + QString paramDesc = paramMgr->dataModel()->getParamDescription(parameterName); + if (!paramDesc.isEmpty()) { + QString tooltipFormat; + if (paramMgr->dataModel()->isParamDefaultKnown(parameterName)) { + tooltipFormat = tr("Default: %1, %2"); + double paramDefValue = paramMgr->dataModel()->getParamDefault(parameterName); + tooltipFormat = tooltipFormat.arg(paramDefValue).arg(paramDesc); + } + else { + tooltipFormat = paramDesc; + } + paramItem->setToolTip(0, tooltipFormat); + paramItem->setToolTip(1, tooltipFormat); } } - } -} - -void QGCParamWidget::saveParameters() -{ - if (!mav) return; - QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "./parameters.txt", tr("Parameter File (*.txt)")); - QFile file(fileName); - if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { - return; - } - QTextStream in(&file); - - in << "# Onboard parameters for system " << mav->getUASName() << "\n"; - in << "#\n"; - in << "# MAV ID COMPONENT ID PARAM NAME VALUE (FLOAT)\n"; - - // Iterate through all components, through all parameters and emit them - QMap*>::iterator i; - for (i = parameters.begin(); i != parameters.end(); ++i) { - // Iterate through the parameters of the component - int compid = i.key(); - QMap* comp = i.value(); - { - QMap::iterator j; - for (j = comp->begin(); j != comp->end(); ++j) - { - QString paramValue("%1"); - QString paramType("%1"); - switch ((int)j.value().type()) - { - case QVariant::Int: - paramValue = paramValue.arg(j.value().toInt()); - paramType = paramType.arg(MAV_PARAM_TYPE_INT32); - break; - case QVariant::UInt: - paramValue = paramValue.arg(j.value().toUInt()); - paramType = paramType.arg(MAV_PARAM_TYPE_UINT32); - break; - case QMetaType::Float: - // We store parameters as floats, with only 6 digits of precision guaranteed for decimal string conversion - // (see IEEE 754, 32 bit single-precision) - paramValue = paramValue.arg((double)j.value().toFloat(), 25, 'g', 6); - paramType = paramType.arg(MAV_PARAM_TYPE_REAL32); - break; - default: - qCritical() << "ABORTED PARAM WRITE TO FILE, NO VALID QVARIANT TYPE" << j.value(); - return; - } - in << mav->getUASID() << "\t" << compid << "\t" << j.key() << "\t" << paramValue << "\t" << paramType << "\n"; - in.flush(); - } + //update the parameterItem's data + if (value.type() == QVariant::Char) { + paramItem->setData(1, Qt::DisplayRole, value.toUInt()); + } + else { + paramItem->setData(1, Qt::DisplayRole, value); } + } - file.close(); -} -void QGCParamWidget::loadParameters() -{ - if (!mav) return; - QString fileName = QFileDialog::getOpenFileName(this, tr("Load File"), ".", tr("Parameter file (*.txt)")); - QFile file(fileName); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) - return; + if (paramItem) { + // Reset background color + paramItem->setBackground(0, Qt::NoBrush); + paramItem->setBackground(1, Qt::NoBrush); - bool userWarned = false; - - QTextStream in(&file); - while (!in.atEnd()) { - QString line = in.readLine(); - if (!line.startsWith("#")) { - QStringList wpParams = line.split("\t"); - if (wpParams.size() == 5) { - // Only load parameters for right mav - if (!userWarned && (mav->getUASID() != wpParams.at(0).toInt())) { - MainWindow::instance()->showCriticalMessage(tr("Parameter loading warning"), tr("The parameters from the file %1 have been saved from system %2, but the currently selected system has the ID %3. If this is unintentional, please click on to revert to the parameters that are currently onboard").arg(fileName).arg(wpParams.at(0).toInt()).arg(mav->getUASID())); - userWarned = true; - } + paramItem->setTextColor(0, QGC::colorDarkWhite); + paramItem->setTextColor(1, QGC::colorDarkWhite); - bool changed = false; - int component = wpParams.at(1).toInt(); - QString parameterName = wpParams.at(2); - if (!parameters.contains(component) || - fabs((static_cast(parameters.value(component)->value(parameterName, wpParams.at(3).toDouble()).toDouble())) - (wpParams.at(3).toDouble())) > 2.0f * FLT_EPSILON) { - changed = true; - qDebug() << "Changed" << parameterName << "VAL" << wpParams.at(3).toDouble(); - } + if (paramItem == tree->currentItem()) { + //need to unset current item to clear highlighting (green by default) + tree->setCurrentItem(NULL); //clear the selected line + } - // Set parameter value + } - // Create changed values data structure if necessary - if (changed && !changedValues.contains(wpParams.at(1).toInt())) { - changedValues.insert(wpParams.at(1).toInt(), new QMap()); - } + return paramItem; +} - // Add to changed values - if (changed && changedValues.value(wpParams.at(1).toInt())->contains(wpParams.at(2))) { - changedValues.value(wpParams.at(1).toInt())->remove(wpParams.at(2)); - } - switch (wpParams.at(4).toUInt()) - { - case (int)MAV_PARAM_TYPE_REAL32: - addParameter(wpParams.at(0).toInt(), wpParams.at(1).toInt(), wpParams.at(2), wpParams.at(3).toFloat()); - if (changed) { - changedValues.value(wpParams.at(1).toInt())->insert(wpParams.at(2), wpParams.at(3).toFloat()); - setParameter(wpParams.at(1).toInt(), wpParams.at(2), wpParams.at(3).toFloat()); - qDebug() << "FLOAT PARAM CHANGED"; - } - break; - case (int)MAV_PARAM_TYPE_UINT32: - addParameter(wpParams.at(0).toInt(), wpParams.at(1).toInt(), wpParams.at(2), wpParams.at(3).toUInt()); - if (changed) { - changedValues.value(wpParams.at(1).toInt())->insert(wpParams.at(2), wpParams.at(3).toUInt()); - setParameter(wpParams.at(1).toInt(), wpParams.at(2), QVariant(wpParams.at(3).toUInt())); - } - break; - case (int)MAV_PARAM_TYPE_INT32: - addParameter(wpParams.at(0).toInt(), wpParams.at(1).toInt(), wpParams.at(2), wpParams.at(3).toInt()); - if (changed) { - changedValues.value(wpParams.at(1).toInt())->insert(wpParams.at(2), wpParams.at(3).toInt()); - setParameter(wpParams.at(1).toInt(), wpParams.at(2), QVariant(wpParams.at(3).toInt())); - } - break; - default: - qDebug() << "FAILED LOADING PARAM" << wpParams.at(2) << "NO KNOWN DATA TYPE"; - } - //qDebug() << "MARKING COMP" << wpParams.at(1).toInt() << "PARAM" << wpParams.at(2) << "VALUE" << (float)wpParams.at(3).toDouble() << "AS CHANGED"; +void QGCParamWidget::parameterItemChanged(QTreeWidgetItem* paramItem, int column) +{ + if (paramItem && column > 0) { - // Mark in UI + QString key = paramItem->data(0, Qt::DisplayRole).toString(); + //qDebug() << "parameterItemChanged:" << key << "with updatingParamNameLock:" << updatingParamNameLock; + if (key == updatingParamNameLock) { + //qDebug() << "parameterItemChanged ignoring bounce from " << key; + return; + } + else { + updatingParamNameLock = key; + } - } + QTreeWidgetItem* parent = paramItem->parent(); + while (parent->parent() != NULL) { + parent = parent->parent(); } - } - file.close(); + // Parent is now top-level component + int componentId = componentItems->key(parent); + QVariant value = paramItem->data(1, Qt::DisplayRole); -} -/** - * Enabling the retransmission guard enables the parameter widget to track - * dropped parameters and to re-request them. This works for both individual - * parameter reads as well for whole list requests. - * - * @param enabled True if retransmission checking should be enabled, false else - */ -void QGCParamWidget::setRetransmissionGuardEnabled(bool enabled) -{ - if (enabled) { - retransmissionTimer.start(retransmissionTimeout); - } else { - retransmissionTimer.stop(); - } -} + bool pending = paramMgr->dataModel()->updatePendingParamWithValue(componentId,key,value); -void QGCParamWidget::retransmissionGuardTick() -{ - if (transmissionActive) { - //qDebug() << __FILE__ << __LINE__ << "RETRANSMISSION GUARD ACTIVE, CHECKING FOR DROPS.."; - - // Check for timeout - // stop retransmission attempts on timeout - if (QGC::groundTimeMilliseconds() > transmissionTimeout) { - setRetransmissionGuardEnabled(false); - transmissionActive = false; - - // Empty read retransmission list - // Empty write retransmission list - int missingReadCount = 0; - QList readKeys = transmissionMissingPackets.keys(); - foreach (int component, readKeys) { - missingReadCount += transmissionMissingPackets.value(component)->count(); - transmissionMissingPackets.value(component)->clear(); - } + // If the value will result in an update + if (pending) { + // Set parameter on changed list to be transmitted to MAV + statusLabel->setText(tr("Pending: %1:%2: %3").arg(componentId).arg(key).arg(value.toFloat(), 5, 'f', 1, QChar(' '))); - // Empty write retransmission list - int missingWriteCount = 0; - QList writeKeys = transmissionMissingWriteAckPackets.keys(); - foreach (int component, writeKeys) { - missingWriteCount += transmissionMissingWriteAckPackets.value(component)->count(); - transmissionMissingWriteAckPackets.value(component)->clear(); - } - statusLabel->setText(tr("TIMEOUT! MISSING: %1 read, %2 write.").arg(missingReadCount).arg(missingWriteCount)); + paramItem->setBackground(0, QBrush(QColor(QGC::colorOrange))); + paramItem->setBackground(1, QBrush(QColor(QGC::colorOrange))); } - - // Re-request at maximum retransmissionBurstRequestSize parameters at once - // to prevent link flooding - QMap*>::iterator i; - for (i = parameters.begin(); i != parameters.end(); ++i) { - // Iterate through the parameters of the component - int component = i.key(); - // Request n parameters from this component (at maximum) - QList * paramList = transmissionMissingPackets.value(component, NULL); - if (paramList) { - int count = 0; - foreach (int id, *paramList) { - if (count < retransmissionBurstRequestSize) { - //qDebug() << __FILE__ << __LINE__ << "RETRANSMISSION GUARD REQUESTS RETRANSMISSION OF PARAM #" << id << "FROM COMPONENT #" << component; - emit requestParameter(component, id); - statusLabel->setText(tr("Requested retransmission of #%1").arg(id+1)); - count++; - } else { - break; - } - } - } + else { + QMap* pendingParams = paramMgr->dataModel()->getPendingParamsForComponent(componentId); + int pendingCount = pendingParams->count(); + statusLabel->setText(tr("Pending items: %1").arg(pendingCount)); + paramItem->setBackground(0, Qt::NoBrush); + paramItem->setBackground(1, Qt::NoBrush); } - // Re-request at maximum retransmissionBurstRequestSize parameters at once - // to prevent write-request link flooding - // Empty write retransmission list - QList writeKeys = transmissionMissingWriteAckPackets.keys(); - foreach (int component, writeKeys) { - int count = 0; - QMap * missingParams = transmissionMissingWriteAckPackets.value(component); - foreach (QString key, missingParams->keys()) { - if (count < retransmissionBurstRequestSize) { - // Re-request write operation - QVariant value = missingParams->value(key); - switch ((int)parameters.value(component)->value(key).type()) - { - case QVariant::Int: - { - QVariant fixedValue(value.toInt()); - emit parameterChanged(component, key, fixedValue); - } - break; - case QVariant::UInt: - { - QVariant fixedValue(value.toUInt()); - emit parameterChanged(component, key, fixedValue); - } - break; - case QMetaType::Float: - { - QVariant fixedValue(value.toFloat()); - emit parameterChanged(component, key, fixedValue); - } - break; - default: - //qCritical() << "ABORTED PARAM RETRANSMISSION, NO VALID QVARIANT TYPE"; - return; - } - statusLabel->setText(tr("Requested rewrite of: %1: %2").arg(key).arg(missingParams->value(key).toDouble())); - count++; - } else { - break; - } - } + + if (paramItem == tree->currentItem()) { + //need to unset current item to clear highlighting (green by default) + tree->setCurrentItem(NULL); //clear the selected line } - } else { - //qDebug() << __FILE__ << __LINE__ << "STOPPING RETRANSMISSION GUARD GRACEFULLY"; - setRetransmissionGuardEnabled(false); + + updatingParamNameLock.clear(); } } -/** - * The .. signal is emitted - */ -void QGCParamWidget::requestParameterUpdate(int component, const QString& parameter) +void QGCParamWidget::setParameterStatusMsg(const QString& msg) { - if (mav) mav->requestParameter(component, parameter); + statusLabel->setText(msg); } -/** - * @param component the subsystem which has the parameter - * @param parameterName name of the parameter, as delivered by the system - * @param value value of the parameter - */ -void QGCParamWidget::setParameter(int component, QString parameterName, QVariant value) +void QGCParamWidget::clearOnboardParamDisplay() { - if (paramMin.contains(parameterName) && value.toDouble() < paramMin.value(parameterName)) - { - statusLabel->setText(tr("REJ. %1 < min").arg(value.toDouble())); - return; - } - if (paramMax.contains(parameterName) && value.toDouble() > paramMax.value(parameterName)) - { - statusLabel->setText(tr("REJ. %1 > max").arg(value.toDouble())); - return; - } - - switch ((int)parameters.value(component)->value(parameterName).type()) - { - case QVariant::Char: - { - QVariant fixedValue(QChar((unsigned char)value.toInt())); - emit parameterChanged(component, parameterName, fixedValue); - //qDebug() << "PARAM WIDGET SENT:" << fixedValue; - } - break; - case QVariant::Int: - { - QVariant fixedValue(value.toInt()); - emit parameterChanged(component, parameterName, fixedValue); - //qDebug() << "PARAM WIDGET SENT:" << fixedValue; - } - break; - case QVariant::UInt: - { - QVariant fixedValue(value.toUInt()); - emit parameterChanged(component, parameterName, fixedValue); - //qDebug() << "PARAM WIDGET SENT:" << fixedValue; - } - break; - case QMetaType::Float: - { - QVariant fixedValue(value.toFloat()); - emit parameterChanged(component, parameterName, fixedValue); - //qDebug() << "PARAM WIDGET SENT:" << fixedValue; - } - break; - default: - qCritical() << "ABORTED PARAM SEND, NO VALID QVARIANT TYPE"; - return; - } - - // Wait for parameter to be written back - // mark it therefore as missing - if (!transmissionMissingWriteAckPackets.contains(component)) - { - transmissionMissingWriteAckPackets.insert(component, new QMap()); - } - - // Insert it in missing write ACK list - transmissionMissingWriteAckPackets.value(component)->insert(parameterName, value); - - // Set timeouts - if (transmissionActive) - { - transmissionTimeout += rewriteTimeout; - } - else - { - quint64 newTransmissionTimeout = QGC::groundTimeMilliseconds() + rewriteTimeout; - if (newTransmissionTimeout > transmissionTimeout) - { - transmissionTimeout = newTransmissionTimeout; - } - transmissionActive = true; - } - - // Enable guard / reset timeouts - setRetransmissionGuardEnabled(true); + tree->clear(); + componentItems->clear(); } -/** - * Set all parameter in the parameter tree on the MAV - */ -void QGCParamWidget::setParameters() +void QGCParamWidget::clearPendingParamDisplay() { - // Iterate through all components, through all parameters and emit them - int parametersSent = 0; - QMap*>::iterator i; - for (i = changedValues.begin(); i != changedValues.end(); ++i) { - // Iterate through the parameters of the component - int compid = i.key(); - QMap* comp = i.value(); - { - QMap::iterator j; - for (j = comp->begin(); j != comp->end(); ++j) { - setParameter(compid, j.key(), j.value()); - parametersSent++; - } - } - } - - // Change transmission status if necessary - if (parametersSent == 0) { - statusLabel->setText(tr("No transmission: No changed values.")); - } else { - statusLabel->setText(tr("Transmitting %1 parameters.").arg(parametersSent)); - // Set timeouts - if (transmissionActive) - { - transmissionTimeout += parametersSent*rewriteTimeout; - } - else - { - transmissionActive = true; - quint64 newTransmissionTimeout = QGC::groundTimeMilliseconds() + parametersSent*rewriteTimeout; - if (newTransmissionTimeout > transmissionTimeout) { - transmissionTimeout = newTransmissionTimeout; - } - } - // Enable guard - setRetransmissionGuardEnabled(true); - } + tree->clear(); + componentItems->clear(); } -/** - * Write the current onboard parameters from RAM into - * permanent storage, e.g. EEPROM or harddisk - */ -void QGCParamWidget::writeParameters() -{ - int changedParamCount = 0; - QMap*>::iterator i; - for (i = changedValues.begin(); i != changedValues.end(); ++i) - { - // Iterate through the parameters of the component - QMap* comp = i.value(); - { - QMap::iterator j; - for (j = comp->begin(); j != comp->end(); ++j) - { - changedParamCount++; - } - } - } - - if (changedParamCount > 0) - { - QMessageBox msgBox; - msgBox.setText(tr("There are locally changed parameters. Please transmit them first () or update them with the onboard values () before storing onboard from RAM to ROM.")); - msgBox.exec(); +void QGCParamWidget::handleParamStatusMsgUpdate(QString msg, int level) +{ + QColor bgColor = QGC::colorGreen; + if ((int)UASParameterCommsMgr::ParamCommsStatusLevel_Warning == level) { + bgColor = QGC::colorOrange; } - else - { - if (!mav) return; - mav->writeParametersToStorage(); + else if ((int)UASParameterCommsMgr::ParamCommsStatusLevel_Error == level) { + bgColor = QGC::colorRed; } -} - -void QGCParamWidget::readParameters() -{ - if (!mav) return; - mav->readParametersFromStorage(); -} -/** - * Clear all data in the parameter widget - */ -void QGCParamWidget::clear() -{ - tree->clear(); - components->clear(); + QPalette pal = statusLabel->palette(); + pal.setColor(backgroundRole(), bgColor); + statusLabel->setPalette(pal); + statusLabel->setText(msg); } diff --git a/src/ui/QGCParamWidget.h b/src/ui/QGCParamWidget.h index f62227d015ddc7079443ea4e3c5fe31182c52a2e..83787de1d43193de0684c93972791865ed0c8216 100644 --- a/src/ui/QGCParamWidget.h +++ b/src/ui/QGCParamWidget.h @@ -37,87 +37,66 @@ This file is part of the QGROUNDCONTROL project #include #include -#include "QGCUASParamManager.h" -#include "UASInterface.h" +#include "QGCBaseParamWidget.h" + + +//forward declarations +class QGridLayout; +class UASInterface; /** * @brief Widget to read/set onboard parameters */ -class QGCParamWidget : public QGCUASParamManager +class QGCParamWidget : public QGCBaseParamWidget { Q_OBJECT public: - QGCParamWidget(UASInterface* uas, QWidget *parent = 0); - /** @brief Get the UAS of this widget */ - UASInterface* getUAS(); - - bool isParamMinKnown(const QString& param) { return paramMin.contains(param); } - bool isParamMaxKnown(const QString& param) { return paramMax.contains(param); } - bool isParamDefaultKnown(const QString& param) { return paramDefault.contains(param); } - double getParamMin(const QString& param) { return paramMin.value(param, 0.0f); } - double getParamMax(const QString& param) { return paramMax.value(param, 0.0f); } - double getParamDefault(const QString& param) { return paramDefault.value(param, 0.0f); } - QString getParamInfo(const QString& param) { return paramToolTips.value(param, ""); } - void setParamInfo(const QMap& param) { paramToolTips = param; } + QGCParamWidget(QWidget *parent = 0); + +protected: + virtual void setParameterStatusMsg(const QString& msg); + virtual void layoutWidget();///< Layout the appearance of this widget + virtual void connectViewSignalsAndSlots();///< Connect view signals/slots as needed + virtual void disconnectViewSignalsAndSlots();///< Connect view signals/slots as needed + + virtual QTreeWidgetItem* getParentWidgetItemForParam(int compId, const QString& paramName); + virtual QTreeWidgetItem* findChildWidgetItemForParam(QTreeWidgetItem* parentItem, const QString& paramName); + + /** @brief Add a component item as a child of this widget + * @param compId Component id of the component + * @param compName Human friendly name of the component + */ + void addComponentItem(int compId, QString compName); + + virtual void addActionButtonsToLayout(QGridLayout* layout); + signals: - /** @brief A parameter was changed in the widget, NOT onboard */ - //void parameterChanged(int component, QString parametername, float value); // defined in QGCUASParamManager already - /** @brief Request a single parameter */ - void requestParameter(int component, int parameter); - /** @brief Request a single parameter by name */ - void requestParameter(int component, const QString& parameter); + + public slots: - /** @brief Add a component to the list */ - void addComponent(int uas, int component, QString componentName); - /** @brief Add a parameter to the list with retransmission / safety checks */ - void addParameter(int uas, int component, int paramCount, int paramId, QString parameterName, QVariant value); - /** @brief Add a parameter to the list */ - void addParameter(int uas, int component, QString parameterName, QVariant value); - /** @brief Request list of parameters from MAV */ - void requestParameterList(); - /** @brief Request one single parameter */ - void requestParameterUpdate(int component, const QString& parameter); - /** @brief Set one parameter, changes value in RAM of MAV */ - void setParameter(int component, QString parameterName, QVariant value); - /** @brief Set all parameters, changes the value in RAM of MAV */ - void setParameters(); - /** @brief Write the current parameters to permanent storage (EEPROM/HDD) */ - void writeParameters(); - /** @brief Read the parameters from permanent storage to RAM */ - void readParameters(); - /** @brief Clear the parameter list */ - void clear(); + virtual void handleOnboardParamUpdate(int component,const QString& parameterName, QVariant value); + virtual void handlePendingParamUpdate(int compId, const QString& paramName, QVariant value, bool isPending); + virtual void handleOnboardParameterListUpToDate(); + virtual void handleParamStatusMsgUpdate(QString msg, int level); + + virtual void clearOnboardParamDisplay(); + virtual void clearPendingParamDisplay(); + + /** @brief Ensure that view of parameter matches data in the model */ + QTreeWidgetItem* updateParameterDisplay(int component, QString parameterName, QVariant value); + + /** @brief Update when user changes parameters */ void parameterItemChanged(QTreeWidgetItem* prev, int column); - /** @brief Store parameters to a file */ - void saveParameters(); - /** @brief Load parameters from a file */ - void loadParameters(); - - /** @brief Check for missing parameters */ - void retransmissionGuardTick(); protected: + QMap* componentItems; ///< The tree of component items, stored by component ID + QMap* > paramGroups; ///< Parameter groups to organize component items + QLabel* statusLabel; ///< User-facing parameter status label QTreeWidget* tree; ///< The parameter tree - QLabel* statusLabel; ///< Parameter transmission label - QMap* components; ///< The list of components - QMap* > paramGroups; ///< Parameter groups - - // Tooltip data structures - QMap paramToolTips; ///< Tooltip values - // Min / Default / Max data structures - QMap paramMin; ///< Minimum param values - QMap paramDefault; ///< Default param values - QMap paramMax; ///< Minimum param values - - /** @brief Activate / deactivate parameter retransmission */ - void setRetransmissionGuardEnabled(bool enabled); - /** @brief Load settings */ - void loadSettings(); - /** @brief Load meta information from CSV */ - void loadParameterInfoCSV(const QString& autopilot, const QString& airframe); + }; #endif // QGCPARAMWIDGET_H diff --git a/src/ui/QGCPendingParamWidget.cc b/src/ui/QGCPendingParamWidget.cc new file mode 100644 index 0000000000000000000000000000000000000000..aaafc42192cc32157000a9a12b6112a711c14eaa --- /dev/null +++ b/src/ui/QGCPendingParamWidget.cc @@ -0,0 +1,130 @@ +#include "QGCPendingParamWidget.h" + +#include +#include + +#include "UASManager.h" +#include "UASParameterCommsMgr.h" + + +QGCPendingParamWidget::QGCPendingParamWidget(QObject *parent) : + QGCParamWidget((QWidget*)parent) +{ + //this subclass doesn't display status updates + statusLabel->hide(); +} + + +void QGCPendingParamWidget::connectToParamManager() +{ + paramMgr = mav->getParamManager(); + + // Listen to updated param signals from the data model + connect(paramMgr, SIGNAL(pendingParamUpdate(int , const QString&, QVariant , bool )), + this, SLOT(handlePendingParamUpdate(int , const QString& , QVariant, bool ))); +} + + +void QGCPendingParamWidget::disconnectFromParamManager() +{ + // Listen to updated param signals from the data model + disconnect(paramMgr, SIGNAL(pendingParamUpdate(int , const QString&, QVariant , bool )), + this, SLOT(handlePendingParamUpdate(int , const QString& , QVariant, bool ))); + + paramMgr = NULL; +} + + +void QGCPendingParamWidget::disconnectViewSignalsAndSlots() +{ + //we ignore edits from the tree view +} + + +void QGCPendingParamWidget::connectViewSignalsAndSlots() +{ + //we ignore edits from the tree view +} + +void QGCPendingParamWidget::handlePendingParamUpdate(int compId, const QString& paramName, QVariant value, bool isPending) +{ + // qDebug() << "handlePendingParamUpdate:" << paramName << "with updatingParamNameLock:" << updatingParamNameLock; + + if (updatingParamNameLock == paramName) { + //qDebug() << "ignoring bounce from " << paramName; + return; + } + else { + updatingParamNameLock = paramName; + } + + QTreeWidgetItem* paramItem = updateParameterDisplay(compId,paramName,value); + + if (isPending) { + QTreeWidgetItem* paramItem = updateParameterDisplay(compId,paramName,value); + paramItem->setFlags(paramItem->flags() & ~Qt::ItemIsEditable); //disallow editing + paramItem->setBackground(0, QBrush(QColor(QGC::colorOrange))); + paramItem->setBackground(1, QBrush(QColor(QGC::colorOrange))); + tree->expandAll(); + } + else { + //we don't display non-pending items + QTreeWidgetItem* groupItem = paramItem->parent(); + if (NULL != groupItem) { + tree->setUpdatesEnabled(false); + QTreeWidgetItem* componentItem = NULL; + if (1 == groupItem->childCount()) { + componentItem = groupItem->parent(); + } + + //always remove the actual paramItem from its parent + groupItem->removeChild(paramItem); + + //now we may need to remove the groupItem if it has no more children + if (NULL != componentItem) { + //remove the group from our internal data structures + QMap* compParamGroups = paramGroups.value(compId); + QString groupStr = paramName.section("_", 0, 0, QString::SectionSkipEmpty); + compParamGroups->remove(groupStr); + //remove the group item from componentItems + componentItems->value(compId)->removeChild(groupItem); + // remove the group item from the tree widget itself + componentItem->removeChild(groupItem); + + if (0 == componentItem->childCount()) { + //the component itself no longer has any pending changes: remove it + paramGroups.remove(compId); + componentItems->remove(compId); + QTreeWidgetItem* compTop = tree->takeTopLevelItem(tree->indexOfTopLevelItem(componentItem)); + delete compTop; //we own it after take + } + } + tree->setUpdatesEnabled(true); + tree->update(); + + } + } + + updatingParamNameLock.clear(); + +} + +void QGCPendingParamWidget::addActionButtonsToLayout(QGridLayout* layout) +{ + + QPushButton* setButton = new QPushButton(tr("Set")); + setButton->setToolTip(tr("Send pending parameters to volatile onboard memory")); + setButton->setWhatsThis(tr("Send pending parameters to volatile onboard memory")); + connect(setButton, SIGNAL(clicked()), + paramMgr, SLOT(sendPendingParameters())); + layout->addWidget(setButton, 2, 0); + + QPushButton* clearButton = new QPushButton(tr("Clear")); + clearButton->setToolTip(tr("Clear pending parameters without sending")); + clearButton->setWhatsThis(tr("Clear pending parameters without sending")); + connect(clearButton, SIGNAL(clicked()), + paramMgr, SLOT(clearAllPendingParams())); + layout->addWidget(clearButton, 2, 1); + + +} diff --git a/src/ui/QGCPendingParamWidget.h b/src/ui/QGCPendingParamWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..31b0d758d88c2b0e74a4bb8eb06c0d75f8c1b245 --- /dev/null +++ b/src/ui/QGCPendingParamWidget.h @@ -0,0 +1,33 @@ +#ifndef QGCPENDINGPARAMWIDGET_H +#define QGCPENDINGPARAMWIDGET_H + + +#include "QGCParamWidget.h" + +class QGridLayout; + +class QGCPendingParamWidget : public QGCParamWidget +{ + Q_OBJECT + +public: + explicit QGCPendingParamWidget(QObject* parent); + +protected: + virtual void connectToParamManager(); + virtual void disconnectFromParamManager(); + + virtual void connectViewSignalsAndSlots(); + virtual void disconnectViewSignalsAndSlots(); + + virtual void addActionButtonsToLayout(QGridLayout* layout); + + +signals: + +public slots: + virtual void handlePendingParamUpdate(int compId, const QString& paramName, QVariant value, bool isPending); + +}; + +#endif // QGCPENDINGPARAMWIDGET_H diff --git a/src/ui/QGCStatusBar.cc b/src/ui/QGCStatusBar.cc index 9d542615e7ae419dca58bf7029cd4f14ec574669..9e2fbacf1586079259a00721c01838cad52077dc 100644 --- a/src/ui/QGCStatusBar.cc +++ b/src/ui/QGCStatusBar.cc @@ -47,16 +47,11 @@ QGCStatusBar::QGCStatusBar(QWidget *parent) : void QGCStatusBar::paintEvent(QPaintEvent * event) { + Q_UNUSED(event); QPainter p(this); QStyleOption opt; opt.initFrom(this); style()->drawPrimitive(QStyle::PE_PanelStatusBar, &opt, &p, this); - //QStatusBar::paintEvent(event); -// if (currentMessage().length() == 0) { -// QStatusBar::paintEvent(event); -// } else { - -// } } void QGCStatusBar::setLogPlayer(QGCMAVLinkLogPlayer* player) @@ -64,12 +59,6 @@ void QGCStatusBar::setLogPlayer(QGCMAVLinkLogPlayer* player) this->player = player; addPermanentWidget(player); connect(toggleLoggingButton, SIGNAL(clicked(bool)), this, SLOT(logging(bool))); - //connect(MainWindow::instance()->getMAVLink(), SIGNAL(loggingChanged(bool)), toggleLoggingButton, SLOT(setChecked(bool))); - - // XXX Mutex issue if called like this -// toggleLoggingButton->blockSignals(true); -// toggleLoggingButton->setChecked(MainWindow::instance()->getMAVLink()->loggingEnabled()); -// toggleLoggingButton->blockSignals(false); } void QGCStatusBar::logging(bool checked) diff --git a/src/ui/QGCTCPLinkConfiguration.cc b/src/ui/QGCTCPLinkConfiguration.cc new file mode 100644 index 0000000000000000000000000000000000000000..7eb0f661ca83132e8e20d9abf17417560c34efb4 --- /dev/null +++ b/src/ui/QGCTCPLinkConfiguration.cc @@ -0,0 +1,35 @@ +#include + +#include "QGCTCPLinkConfiguration.h" +#include "ui_QGCTCPLinkConfiguration.h" + +QGCTCPLinkConfiguration::QGCTCPLinkConfiguration(TCPLink* link, QWidget *parent) : + QWidget(parent), + link(link), + ui(new Ui::QGCTCPLinkConfiguration) +{ + ui->setupUi(this); + quint16 port = link->getPort(); + ui->portSpinBox->setValue(port); + QString addr = link->getHostAddress().toString(); + ui->hostAddressLineEdit->setText(addr); + connect(ui->portSpinBox, SIGNAL(valueChanged(int)), link, SLOT(setPort(int))); + connect(ui->hostAddressLineEdit, SIGNAL(textChanged (const QString &)), link, SLOT(setAddress(const QString &))); +} + +QGCTCPLinkConfiguration::~QGCTCPLinkConfiguration() +{ + delete ui; +} + +void QGCTCPLinkConfiguration::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} diff --git a/src/ui/QGCTCPLinkConfiguration.h b/src/ui/QGCTCPLinkConfiguration.h new file mode 100644 index 0000000000000000000000000000000000000000..0d8eb33ad7e8d07862dd57400a0ba443f47a9a54 --- /dev/null +++ b/src/ui/QGCTCPLinkConfiguration.h @@ -0,0 +1,32 @@ +#ifndef QGCTCPLINKCONFIGURATION_H +#define QGCTCPLINKCONFIGURATION_H + +#include + +#include "TCPLink.h" + +namespace Ui +{ +class QGCTCPLinkConfiguration; +} + +class QGCTCPLinkConfiguration : public QWidget +{ + Q_OBJECT + +public: + explicit QGCTCPLinkConfiguration(TCPLink* link, QWidget *parent = 0); + ~QGCTCPLinkConfiguration(); + +public slots: + +protected: + void changeEvent(QEvent *e); + + TCPLink* link; ///< TCP link instance this widget configures + +private: + Ui::QGCTCPLinkConfiguration *ui; +}; + +#endif // QGCTCPLINKCONFIGURATION_H diff --git a/src/ui/QGCTCPLinkConfiguration.ui b/src/ui/QGCTCPLinkConfiguration.ui new file mode 100644 index 0000000000000000000000000000000000000000..416e587970589d09aed7aba76722040fce971440 --- /dev/null +++ b/src/ui/QGCTCPLinkConfiguration.ui @@ -0,0 +1,51 @@ + + + QGCTCPLinkConfiguration + + + + 0 + 0 + 400 + 300 + + + + Form + + + + QFormLayout::FieldsStayAtSizeHint + + + + + TCP Port + + + + + + + 3000 + + + 100000 + + + + + + + Host Address + + + + + + + + + + + diff --git a/src/ui/QGCTabbedInfoView.cpp b/src/ui/QGCTabbedInfoView.cpp index e319471386ee593485a33fc0d4bdc1ddba147b2a..3247548a90429d056e8f918b926dd0d21ef575c6 100644 --- a/src/ui/QGCTabbedInfoView.cpp +++ b/src/ui/QGCTabbedInfoView.cpp @@ -4,18 +4,18 @@ QGCTabbedInfoView::QGCTabbedInfoView(QWidget *parent) : QWidget(parent) { ui.setupUi(this); messageView = new QGCMessageView(this); - actionsWidget = new UASActionsWidget(this); + //actionsWidget = new UASActionsWidget(this); quickView = new UASQuickView(this); - rawView = new UASRawStatusView(this); - ui.tabWidget->addTab(messageView,"Messages"); + //rawView = new UASRawStatusView(this); ui.tabWidget->addTab(quickView,"Quick"); - ui.tabWidget->addTab(actionsWidget,"Actions"); - ui.tabWidget->addTab(rawView,"Status"); + //ui.tabWidget->addTab(actionsWidget,"Actions"); + //ui.tabWidget->addTab(rawView,"Status"); + ui.tabWidget->addTab(messageView,"Messages"); } void QGCTabbedInfoView::addSource(MAVLinkDecoder *decoder) { m_decoder = decoder; - rawView->addSource(decoder); + //rawView->addSource(decoder); quickView->addSource(decoder); } diff --git a/src/ui/QGCToolBar.cc b/src/ui/QGCToolBar.cc index 8577cdd3373c39bcdfa438d9d0a898daf1275497..8bda720b1abb8d7567a953e13404ef54250ae61d 100644 --- a/src/ui/QGCToolBar.cc +++ b/src/ui/QGCToolBar.cc @@ -24,6 +24,7 @@ This file is part of the QGROUNDCONTROL project #include #include #include +#include "SerialLink.h" #include "QGCToolBar.h" #include "UASManager.h" #include "MainWindow.h" @@ -31,6 +32,8 @@ This file is part of the QGROUNDCONTROL project QGCToolBar::QGCToolBar(QWidget *parent) : QToolBar(parent), mav(NULL), + userBaudChoice(false), + userPortChoice(false), changed(true), batteryPercent(0), batteryVoltage(0), @@ -74,6 +77,8 @@ void QGCToolBar::heartbeatTimeout(bool timeout, unsigned int ms) } toolBarTimeoutLabel->setText(tr("CONNECTION LOST: %1 s").arg((ms / 1000.0f), 2, 'f', 1, ' ')); toolBarTimeoutAction->setVisible(true); + toolBarMessageAction->setVisible(false); + toolBarBatteryBarAction->setVisible(false); } else { @@ -81,6 +86,8 @@ void QGCToolBar::heartbeatTimeout(bool timeout, unsigned int ms) if (toolBarTimeoutAction->isVisible()) { toolBarTimeoutAction->setVisible(false); + toolBarMessageAction->setVisible(true); + toolBarBatteryBarAction->setVisible(true); } } } @@ -117,11 +124,11 @@ void QGCToolBar::createUI() toolBarModeLabel->setAlignment(Qt::AlignCenter); addWidget(toolBarModeLabel); - toolBarStateLabel = new QLabel(this); - toolBarStateLabel->setToolTip(tr("Vehicle state")); - toolBarStateLabel->setObjectName("toolBarStateLabel"); - toolBarStateLabel->setAlignment(Qt::AlignCenter); - addWidget(toolBarStateLabel); +// toolBarStateLabel = new QLabel(this); +// toolBarStateLabel->setToolTip(tr("Vehicle state")); +// toolBarStateLabel->setObjectName("toolBarStateLabel"); +// toolBarStateLabel->setAlignment(Qt::AlignCenter); +// addWidget(toolBarStateLabel); toolBarBatteryBar = new QProgressBar(this); toolBarBatteryBar->setMinimum(0); @@ -131,34 +138,53 @@ void QGCToolBar::createUI() toolBarBatteryBar->setToolTip(tr("Battery charge level")); toolBarBatteryBar->setObjectName("toolBarBatteryBar"); toolBarBatteryBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::MinimumExpanding); - addWidget(toolBarBatteryBar); + toolBarBatteryBarAction = addWidget(toolBarBatteryBar); toolBarBatteryVoltageLabel = new QLabel(this); toolBarBatteryVoltageLabel->setToolTip(tr("Battery voltage")); toolBarBatteryVoltageLabel->setObjectName("toolBarBatteryVoltageLabel"); toolBarBatteryVoltageLabel->setAlignment(Qt::AlignCenter); - addWidget(toolBarBatteryVoltageLabel); + toolBarBatteryVoltageAction = addWidget(toolBarBatteryVoltageLabel); toolBarWpLabel = new QLabel(this); toolBarWpLabel->setToolTip(tr("Current waypoint")); toolBarWpLabel->setObjectName("toolBarWpLabel"); toolBarWpLabel->setAlignment(Qt::AlignCenter); - addWidget(toolBarWpLabel); - - toolBarDistLabel = new QLabel(this); - toolBarDistLabel->setToolTip(tr("Distance to current waypoint")); - toolBarDistLabel->setAlignment(Qt::AlignCenter); - addWidget(toolBarDistLabel); + toolBarWpAction = addWidget(toolBarWpLabel); toolBarMessageLabel = new QLabel(this); toolBarMessageLabel->setToolTip(tr("Most recent system message")); toolBarMessageLabel->setObjectName("toolBarMessageLabel"); - addWidget(toolBarMessageLabel); + toolBarMessageAction = addWidget(toolBarMessageLabel); QWidget* spacer = new QWidget(); spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); addWidget(spacer); + portComboBox = new QComboBox(this); + portComboBox->setToolTip(tr("Choose the COM port to use")); + portComboBox->setEnabled(true); + portComboBox->setMinimumWidth(100); + toolBarPortAction = addWidget(portComboBox); + + baudcomboBox = new QComboBox(this); + baudcomboBox->setToolTip(tr("Choose what baud rate to use")); + baudcomboBox->setEnabled(true); + baudcomboBox->setMinimumWidth(40); + baudcomboBox->addItem("9600", 9600); + baudcomboBox->addItem("14400", 14400); + baudcomboBox->addItem("19200", 19200); + baudcomboBox->addItem("38400", 38400); + baudcomboBox->addItem("57600", 57600); + baudcomboBox->addItem("115200", 115200); + baudcomboBox->addItem("230400", 230400); + baudcomboBox->addItem("460800", 460800); + baudcomboBox->addItem("921600", 921600); + baudcomboBox->setCurrentIndex(baudcomboBox->findData(57600)); + toolBarBaudAction = addWidget(baudcomboBox); + connect(baudcomboBox, SIGNAL(activated(int)), this, SLOT(baudSelected(int))); + connect(portComboBox, SIGNAL(activated(int)), this, SLOT(portSelected(int))); + connectButton = new QPushButton(tr("Connect"), this); connectButton->setObjectName("connectButton"); connectButton->setToolTip(tr("Connect wireless link to MAV")); @@ -176,20 +202,33 @@ void QGCToolBar::createUI() // Configure the toolbar for the current default UAS setActiveUAS(UASManager::instance()->getActiveUAS()); connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*))); + qDebug() << "LINK COUNT" << LinkManager::instance()->getLinks().count(); + // Update label if required + if (LinkManager::instance()->getSerialLinks().count() < 1) { + connectButton->setText(tr("New Serial Link")); + toolBarPortAction->setVisible(false); + toolBarBaudAction->setVisible(false); + } else { - if (LinkManager::instance()->getLinks().count() > 2) - addLink(LinkManager::instance()->getLinks().last()); - // XXX implies that connect button is always active for the last used link - connect(LinkManager::instance(), SIGNAL(newLink(LinkInterface*)), this, SLOT(addLink(LinkInterface*))); - connect(LinkManager::instance(), SIGNAL(linkRemoved(LinkInterface*)), this, SLOT(removeLink(LinkInterface*))); + QList links = LinkManager::instance()->getSerialLinks(); - // Update label if required - if (LinkManager::instance()->getLinks().count() < 3) { - connectButton->setText(tr("New Link")); + foreach(SerialLink* slink, links) + { + addLink(slink); + } } + connect(LinkManager::instance(), SIGNAL(newLink(LinkInterface*)), this, SLOT(addLink(LinkInterface*))); + connect(LinkManager::instance(), SIGNAL(linkRemoved(LinkInterface*)), this, SLOT(removeLink(LinkInterface*))); + loadSettings(); + connect(&portBoxTimer, SIGNAL(timeout()), this, SLOT(updateComboBox())); + portBoxTimer.start(500); + + toolBarMessageAction->setVisible(false); + toolBarBatteryBarAction->setVisible(false); + changed = false; } @@ -205,17 +244,30 @@ void QGCToolBar::resetToolbarUI() //toolBarTimeoutLabel->show(); toolBarSafetyLabel->setText("----"); toolBarModeLabel->setText("------"); - toolBarStateLabel->setText("------"); +// toolBarStateLabel->setText("------"); toolBarBatteryBar->setValue(0); toolBarBatteryBar->setDisabled(true); toolBarBatteryVoltageLabel->setText("xx.x V"); toolBarWpLabel->setText("WP--"); - toolBarDistLabel->setText("--- ---- m"); toolBarMessageLabel->clear(); lastSystemMessage = ""; lastSystemMessageTimeMs = 0; symbolLabel->setStyleSheet(""); symbolLabel->clear(); + toolBarMessageAction->setVisible(false); + toolBarBatteryBarAction->setVisible(false); +} + +void QGCToolBar::baudSelected(int index) +{ + Q_UNUSED(index); + userBaudChoice = true; +} + +void QGCToolBar::portSelected(int index) +{ + Q_UNUSED(index); + userPortChoice = true; } void QGCToolBar::setPerspectiveChangeActions(const QList &actions) @@ -232,9 +284,13 @@ void QGCToolBar::setPerspectiveChangeActions(const QList &actions) first->setToolTip(actions.first()->toolTip()); first->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); first->setCheckable(true); + connect(first, SIGNAL(clicked(bool)), actions.first(), SIGNAL(triggered(bool))); connect(actions.first(),SIGNAL(triggered(bool)),first,SLOT(setChecked(bool))); + first->setObjectName("firstAction"); + + //first->setStyleSheet("QToolButton { min-height: 24px; max-height: 24px; min-width: 60px; color: #222222; background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #A2A3A4, stop: 1 #B6B7B8); margin-left: 8px; margin-right: 0px; padding-left: 4px; padding-right: 8px; border-radius: 0px; border : 0px solid blue; border-bottom-left-radius: 6px; border-top-left-radius: 6px; border-left: 1px solid #484848; border-top: 1px solid #484848; border-bottom: 1px solid #484848; } QToolButton:checked { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #555555, stop: 1 #787878); color: #DDDDDD; }"); addWidget(first); group->addButton(first); @@ -350,15 +406,17 @@ void QGCToolBar::setActiveUAS(UASInterface* active) // Update all values once systemName = mav->getUASName(); systemArmed = mav->isArmed(); - toolBarNameLabel->setText(mav->getUASName()); + toolBarNameLabel->setText(mav->getUASName().replace("MAV", "")); toolBarNameLabel->setStyleSheet(QString("QLabel {color: %1;}").arg(mav->getColor().name())); symbolLabel->setStyleSheet(QString("QWidget {background-color: %1;}").arg(mav->getColor().name())); - toolBarModeLabel->setText(mav->getShortMode()); - toolBarStateLabel->setText(mav->getShortState()); + QString shortMode = mav->getShortMode(); + shortMode = shortMode.replace("D|", ""); + shortMode = shortMode.replace("A|", ""); + toolBarModeLabel->setText(shortMode); +// toolBarStateLabel->setText(mav->getShortState()); toolBarTimeoutAction->setVisible(false); toolBarMessageLabel->clear(); lastSystemMessageTimeMs = 0; - toolBarDistLabel->clear(); toolBarBatteryBar->setEnabled(true); setSystemType(mav, mav->getSystemType()); } @@ -380,40 +438,49 @@ void QGCToolBar::updateArmingState(bool armed) void QGCToolBar::updateView() { if (!changed) return; - //toolBarDistLabel->setText(tr("%1 m").arg(wpDistance, 6, 'f', 2, '0')); - // XXX add also rel altitude - toolBarDistLabel->setText(QString("%1 m MSL").arg(altitudeMSL, 6, 'f', 2, '0')); - toolBarWpLabel->setText(tr("WP%1").arg(wpId)); - toolBarBatteryBar->setValue(batteryPercent); - if (batteryPercent < 30 && toolBarBatteryBar->value() >= 30) { - if (MainWindow::instance()->getStyle() == MainWindow::QGC_MAINWINDOW_STYLE_LIGHT) - { - toolBarBatteryBar->setStyleSheet("QProgressBar {color: #FFF} QProgressBar::chunk { background-color: #008000}"); - } - else - { - toolBarBatteryBar->setStyleSheet("QProgressBar {color: #000} QProgressBar QProgressBar::chunk { background-color: #0F0}"); - } - } else if (batteryPercent >= 30 && toolBarBatteryBar->value() < 30){ - if (MainWindow::instance()->getStyle() == MainWindow::QGC_MAINWINDOW_STYLE_LIGHT) - { - toolBarBatteryBar->setStyleSheet("QProgressBar {color: #FFF} QProgressBar::chunk { background-color: #808000}"); - } - else - { - toolBarBatteryBar->setStyleSheet("QProgressBar {color: #000} QProgressBar QProgressBar::chunk { background-color: #FF0}"); + if (toolBarWpAction->isVisible()) + toolBarWpLabel->setText(tr("WP%1").arg(wpId)); + + if (toolBarBatteryBarAction->isVisible()) { + toolBarBatteryBar->setValue(batteryPercent); + + if (batteryPercent < 30 && toolBarBatteryBar->value() >= 30) { + if (MainWindow::instance()->getStyle() == MainWindow::QGC_MAINWINDOW_STYLE_LIGHT) + { + toolBarBatteryBar->setStyleSheet("QProgressBar {color: #FFF} QProgressBar::chunk { background-color: #008000}"); + } + else + { + toolBarBatteryBar->setStyleSheet("QProgressBar {color: #000} QProgressBar QProgressBar::chunk { background-color: #0F0}"); + } + } else if (batteryPercent >= 30 && toolBarBatteryBar->value() < 30){ + if (MainWindow::instance()->getStyle() == MainWindow::QGC_MAINWINDOW_STYLE_LIGHT) + { + toolBarBatteryBar->setStyleSheet("QProgressBar {color: #FFF} QProgressBar::chunk { background-color: #808000}"); + } + else + { + toolBarBatteryBar->setStyleSheet("QProgressBar {color: #000} QProgressBar QProgressBar::chunk { background-color: #FF0}"); + } } + + } + if (toolBarBatteryVoltageLabel->isVisible()) { + toolBarBatteryVoltageLabel->setText(tr("%1 V").arg(batteryVoltage, 4, 'f', 1, ' ')); } - toolBarBatteryVoltageLabel->setText(tr("%1 V").arg(batteryVoltage, 4, 'f', 1, ' ')); - toolBarStateLabel->setText(QString("%1").arg(state)); + +// toolBarStateLabel->setText(QString("%1").arg(state)); toolBarModeLabel->setText(QString("%1").arg(mode)); toolBarNameLabel->setText(systemName); // expire after 15 seconds - if (QGC::groundTimeMilliseconds() - lastSystemMessageTimeMs < 15000) { - toolBarMessageLabel->setText(QString("%1").arg(lastSystemMessage)); - } else { - toolBarMessageLabel->clear(); + + if (toolBarMessageAction->isVisible()) { + if (QGC::groundTimeMilliseconds() - lastSystemMessageTimeMs < 15000) { + toolBarMessageLabel->setText(QString("%1").arg(lastSystemMessage)); + } else { + toolBarMessageLabel->clear(); + } } // Display the system armed state with a red-on-yellow background if armed or green text if safe. @@ -432,7 +499,7 @@ void QGCToolBar::updateView() { toolBarSafetyLabel->setStyleSheet("QLabel {color: #14C814; font-size: 15pt;}"); } - toolBarSafetyLabel->setText(tr("SAFE")); + toolBarSafetyLabel->setText(tr("DISARMED")); } changed = false; @@ -455,6 +522,7 @@ void QGCToolBar::updateBatteryRemaining(UASInterface* uas, double voltage, doubl Q_UNUSED(uas); Q_UNUSED(seconds); Q_UNUSED(current); + if (batteryPercent != percent || batteryVoltage != voltage) changed = true; batteryPercent = percent; batteryVoltage = voltage; @@ -574,11 +642,21 @@ void QGCToolBar::receiveTextMessage(int uasid, int componentid, int severity, QS void QGCToolBar::addLink(LinkInterface* link) { - // XXX magic number - if (LinkManager::instance()->getLinks().count() > 2) { + // Accept only serial links as current link + SerialLink* serial = qobject_cast(link); + + if (serial && !currentLink) + { + toolBarPortAction->setVisible(true); + toolBarBaudAction->setVisible(true); + currentLink = link; connect(currentLink, SIGNAL(connected(bool)), this, SLOT(updateLinkState(bool))); updateLinkState(link->isConnected()); + + qDebug() << "ADD LINK"; + + updateComboBox(); } } @@ -586,12 +664,68 @@ void QGCToolBar::removeLink(LinkInterface* link) { if (link == currentLink) { currentLink = NULL; - // XXX magic number - if (LinkManager::instance()->getLinks().count() > 2) { - currentLink = LinkManager::instance()->getLinks().last(); + + // Try to get a new serial link + foreach (SerialLink* s, LinkManager::instance()->getSerialLinks()) + { + addLink(s); + } + + // Update GUI according to scan result + if (currentLink) { updateLinkState(currentLink->isConnected()); } else { - connectButton->setText(tr("New Link")); + connectButton->setText(tr("New Serial Link")); + portComboBox->hide(); + baudcomboBox->hide(); + } + } + updateComboBox(); +} +void QGCToolBar::updateComboBox() +{ + if (currentLink && !currentLink->isConnected()) + { + // Do not update if not visible + if (!portComboBox->isVisible()) + return; + + SerialLink *slink = qobject_cast(currentLink); + QList portlist = slink->getCurrentPorts(); + foreach (QString port, portlist) + { + if (portComboBox->findText(port) == -1) + { + portComboBox->addItem(port, port); + } + } + + if (!userPortChoice) { + if (slink->getPortName().trimmed().length() > 0) + { + int portIndex = portComboBox->findData(slink->getPortName()); + if (portIndex >= 0) { + portComboBox->setCurrentIndex(portIndex); + portComboBox->setEditText(slink->getPortName()); + } + } + else + { + if (portlist.length() > 0) + { + portComboBox->setEditText(portlist.last()); + } + else + { + portComboBox->setEditText(tr("No serial port found")); + } + } + } + + if (!userBaudChoice) { + int index = baudcomboBox->findData(slink->getBaudRate()); + if (index >= 0) + baudcomboBox->setCurrentIndex(index); } } } @@ -599,12 +733,16 @@ void QGCToolBar::removeLink(LinkInterface* link) void QGCToolBar::updateLinkState(bool connected) { Q_UNUSED(connected); - if (currentLink && currentLink->isConnected()) + if (currentLink && currentLink->isConnected() && portComboBox->isVisible()) { connectButton->setText(tr("Disconnect")); connectButton->blockSignals(true); connectButton->setChecked(true); connectButton->blockSignals(false); + toolBarPortAction->setVisible(false); + toolBarBaudAction->setVisible(false); + toolBarMessageAction->setVisible(true); + toolBarWpAction->setVisible(true); } else { @@ -612,20 +750,32 @@ void QGCToolBar::updateLinkState(bool connected) connectButton->blockSignals(true); connectButton->setChecked(false); connectButton->blockSignals(false); + toolBarPortAction->setVisible(true); + toolBarBaudAction->setVisible(true); + toolBarMessageAction->setVisible(false); + toolBarWpAction->setVisible(false); } } void QGCToolBar::connectLink(bool connect) { // No serial port yet present - // XXX magic number - if (connect && LinkManager::instance()->getLinks().count() < 3) + if (connect && LinkManager::instance()->getSerialLinks().count() == 0) { MainWindow::instance()->addLink(); + currentLink = LinkManager::instance()->getLinks().last(); } else if (connect) { - LinkManager::instance()->getLinks().last()->connect(); - } else if (!connect && LinkManager::instance()->getLinks().count() > 2) { - LinkManager::instance()->getLinks().last()->disconnect(); + SerialLink *link = qobject_cast(currentLink); + if (link) + { + link->setPortName(portComboBox->itemData(portComboBox->currentIndex()).toString().trimmed()); + int baud = baudcomboBox->currentText().toInt(); + link->setBaudRate(baud); + link->connect(); + } + + } else if (!connect && currentLink) { + currentLink->disconnect(); } } diff --git a/src/ui/QGCToolBar.h b/src/ui/QGCToolBar.h index ac7141ff02f3141871db6c0eeecb0a470aee848d..e161bcc9d887ae699da0a75f7e60ac7593efe0d9 100644 --- a/src/ui/QGCToolBar.h +++ b/src/ui/QGCToolBar.h @@ -30,8 +30,11 @@ This file is part of the QGROUNDCONTROL project #include #include #include +#include +#include #include "UASInterface.h" #include "QGCMAVLinkLogPlayer.h" +#include "SerialLink.h" class QGCToolBar : public QToolBar { @@ -82,27 +85,51 @@ public slots: void clearStatusString(); /** @brief Set an activity action as checked in menu */ void advancedActivityTriggered(QAction* action); + void updateComboBox(); + + /** + * @brief User selected baud rate + * @param index The current index of the combo box + */ + void baudSelected(int index); + + /** + * @brief User selected port + * @param index The current index of the combo box + */ + void portSelected(int index); protected: void storeSettings(); void loadSettings(); void createUI(); void resetToolbarUI(); - UASInterface* mav; QLabel* symbolLabel; QLabel* toolBarNameLabel; QLabel* toolBarTimeoutLabel; QAction* toolBarTimeoutAction; ///< Needed to set label (in)visible. + QAction* toolBarMessageAction; + QAction* toolBarPortAction; + QAction* toolBarBaudAction; + QAction* toolBarWpAction; + QAction* toolBarBatteryBarAction; + QAction* toolBarBatteryVoltageAction; QLabel* toolBarSafetyLabel; QLabel* toolBarModeLabel; QLabel* toolBarStateLabel; QLabel* toolBarWpLabel; - QLabel* toolBarDistLabel; QLabel* toolBarMessageLabel; QPushButton* connectButton; QProgressBar* toolBarBatteryBar; QLabel* toolBarBatteryVoltageLabel; + + QGCMAVLinkLogPlayer* player; + QComboBox *portComboBox; + QComboBox *baudcomboBox; + QTimer portBoxTimer; + bool userBaudChoice; + bool userPortChoice; bool changed; float batteryPercent; float batteryVoltage; diff --git a/src/ui/QGCVehicleConfig.cc b/src/ui/QGCVehicleConfig.cc index b99535bccbaf2a24a9f17f2eef59dbe199c4b036..98ce31537d5521ee61a6c0a074d8aea33a5d2c74 100644 --- a/src/ui/QGCVehicleConfig.cc +++ b/src/ui/QGCVehicleConfig.cc @@ -13,9 +13,11 @@ #include #include "QGCVehicleConfig.h" -#include "UASManager.h" + #include "QGC.h" #include "QGCToolWidget.h" +#include "UASManager.h" +#include "UASParameterCommsMgr.h" #include "ui_QGCVehicleConfig.h" QGCVehicleConfig::QGCVehicleConfig(QWidget *parent) : @@ -259,7 +261,7 @@ void QGCVehicleConfig::loadQgcConfig(bool primary) { if (file.toLower().endsWith(".qgw")) { QWidget* parent = left?ui->generalLeftContents:ui->generalRightContents; - tool = new QGCToolWidget("", parent); + tool = new QGCToolWidget("", "", parent); if (tool->loadSettings(generaldir.absoluteFilePath(file), false)) { toolWidgets.append(tool); @@ -289,7 +291,7 @@ void QGCVehicleConfig::loadQgcConfig(bool primary) { if (file.toLower().endsWith(".qgw")) { QWidget* parent = left?ui->advancedLeftContents:ui->advancedRightContents; - tool = new QGCToolWidget("", parent); + tool = new QGCToolWidget("", "", parent); if (tool->loadSettings(vehicledir.absoluteFilePath(file), false)) { toolWidgets.append(tool); @@ -340,7 +342,7 @@ void QGCVehicleConfig::loadQgcConfig(bool primary) foreach (QString file,newdir.entryList(QDir::Files| QDir::NoDotAndDotDot)) { if (file.toLower().endsWith(".qgw")) { - tool = new QGCToolWidget("", tab); + tool = new QGCToolWidget("", "", tab); if (tool->loadSettings(newdir.absoluteFilePath(file), false)) { toolWidgets.append(tool); @@ -387,7 +389,7 @@ void QGCVehicleConfig::loadQgcConfig(bool primary) foreach (QString file,newdir.entryList(QDir::Files| QDir::NoDotAndDotDot)) { if (file.toLower().endsWith(".qgw")) { - tool = new QGCToolWidget("", tab); + tool = new QGCToolWidget("","", tab); tool->addUAS(mav); if (tool->loadSettings(newdir.absoluteFilePath(file), false)) { @@ -409,7 +411,7 @@ void QGCVehicleConfig::loadQgcConfig(bool primary) // Load general calibration for autopilot //TODO: Handle this more gracefully, maybe have it scan the directory for multiple calibration entries? - tool = new QGCToolWidget("", ui->sensorContents); + tool = new QGCToolWidget("", "", ui->sensorContents); tool->addUAS(mav); if (tool->loadSettings(autopilotdir.absolutePath() + "/general/calibration/calibration.qgw", false)) { @@ -424,7 +426,7 @@ void QGCVehicleConfig::loadQgcConfig(bool primary) } // Load vehicle-specific autopilot configuration - tool = new QGCToolWidget("", ui->sensorContents); + tool = new QGCToolWidget("", "", ui->sensorContents); tool->addUAS(mav); if (tool->loadSettings(autopilotdir.absolutePath() + "/" + mav->getSystemTypeName().toLower() + "/calibration/calibration.qgw", false)) { @@ -679,10 +681,8 @@ void QGCVehicleConfig::loadConfig() { parent = ui->generalRightContents; } - tool = new QGCToolWidget("", parent); + tool = new QGCToolWidget(parametersname, parametersname, parent); tool->addUAS(mav); - tool->setTitle(parametersname); - tool->setObjectName(parametersname); tool->setSettings(genset); QList paramlist = tool->getParamList(); for (int i=0;igeneralRightContents; } - tool = new QGCToolWidget("", parent); + tool = new QGCToolWidget(parametersname, parametersname, parent); tool->addUAS(mav); - tool->setTitle(parametersname); - tool->setObjectName(parametersname); tool->setSettings(advset); QList paramlist = tool->getParamList(); for (int i=0;igetParamManager()->setParamInfo(paramTooltips); + if (!paramTooltips.isEmpty()) { + paramMgr->setParamDescriptions(paramTooltips); + } doneLoadingConfig = true; - mav->requestParameters(); //Config is finished, lets do a parameter request to ensure none are missed if someone else started requesting before we were finished. + //Config is finished, lets do a parameter request to ensure none are missed if someone else started requesting before we were finished. + paramMgr->requestParameterListIfEmpty(); } void QGCVehicleConfig::setActiveUAS(UASInterface* active) @@ -859,6 +860,7 @@ void QGCVehicleConfig::setActiveUAS(UASInterface* active) // Connect new system mav = active; + paramMgr = mav->getParamManager(); // Reset current state resetCalibrationRC(); @@ -888,7 +890,7 @@ void QGCVehicleConfig::setActiveUAS(UASInterface* active) if (!paramTooltips.isEmpty()) { - mav->getParamManager()->setParamInfo(paramTooltips); + mav->getParamManager()->setParamDescriptions(paramTooltips); } qDebug() << "CALIBRATION!! System Type Name:" << mav->getSystemTypeName(); @@ -929,6 +931,8 @@ void QGCVehicleConfig::writeCalibrationRC() { if (!mav) return; + setTrimPositions(); + QString minTpl("RC%1_MIN"); QString maxTpl("RC%1_MAX"); QString trimTpl("RC%1_TRIM"); @@ -937,6 +941,7 @@ void QGCVehicleConfig::writeCalibrationRC() // Do not write the RC type, as these values depend on this // active onboard parameter + //TODO consolidate RC param sending in the UAS comms mgr for (unsigned int i = 0; i < chanCount; ++i) { //qDebug() << "SENDING" << minTpl.arg(i+1) << rcMin[i]; @@ -971,33 +976,14 @@ void QGCVehicleConfig::writeCalibrationRC() void QGCVehicleConfig::requestCalibrationRC() { - if (!mav) return; - - QString minTpl("RC%1_MIN"); - QString maxTpl("RC%1_MAX"); - QString trimTpl("RC%1_TRIM"); - QString revTpl("RC%1_REV"); - - // Do not request the RC type, as these values depend on this - // active onboard parameter - - for (unsigned int i = 0; i < chanMax; ++i) - { - mav->requestParameter(0, minTpl.arg(i+1)); - QGC::SLEEP::usleep(5000); - mav->requestParameter(0, trimTpl.arg(i+1)); - QGC::SLEEP::usleep(5000); - mav->requestParameter(0, maxTpl.arg(i+1)); - QGC::SLEEP::usleep(5000); - mav->requestParameter(0, revTpl.arg(i+1)); - QGC::SLEEP::usleep(5000); - } + paramMgr->requestRcCalibrationParamsUpdate(); } void QGCVehicleConfig::writeParameters() { updateStatus(tr("Writing all onboard parameters.")); writeCalibrationRC(); + mav->writeParametersToStorage(); } @@ -1030,12 +1016,10 @@ void QGCVehicleConfig::remoteControlChannelRawChanged(int chan, float val) // Normalized value float normalized; - if (val >= rcTrim[chan]) - { + if (val >= rcTrim[chan]) { normalized = (val - rcTrim[chan])/(rcMax[chan] - rcTrim[chan]); } - else - { + else { normalized = -(rcTrim[chan] - val)/(rcTrim[chan] - rcMin[chan]); } @@ -1044,22 +1028,18 @@ void QGCVehicleConfig::remoteControlChannelRawChanged(int chan, float val) // Invert normalized = (rcRev[chan]) ? -1.0f*normalized : normalized; - if (chan == rcMapping[0]) - { + if (chan == rcMapping[0]) { // ROLL rcRoll = normalized; } - if (chan == rcMapping[1]) - { + if (chan == rcMapping[1]) { // PITCH rcPitch = normalized; } - if (chan == rcMapping[2]) - { + if (chan == rcMapping[2]) { rcYaw = normalized; } - if (chan == rcMapping[3]) - { + if (chan == rcMapping[3]) { // THROTTLE if (rcRev[chan]) { rcThrottle = 1.0f + normalized; @@ -1069,23 +1049,19 @@ void QGCVehicleConfig::remoteControlChannelRawChanged(int chan, float val) rcThrottle = qBound(0.0f, rcThrottle, 1.0f); } - if (chan == rcMapping[4]) - { + if (chan == rcMapping[4]) { // MODE SWITCH rcMode = normalized; } - if (chan == rcMapping[5]) - { + if (chan == rcMapping[5]) { // AUX1 rcAux1 = normalized; } - if (chan == rcMapping[6]) - { + if (chan == rcMapping[6]) { // AUX2 rcAux2 = normalized; } - if (chan == rcMapping[7]) - { + if (chan == rcMapping[7]) { // AUX3 rcAux3 = normalized; } @@ -1195,14 +1171,12 @@ void QGCVehicleConfig::parameterChanged(int uas, int component, QString paramete } // Create the tool, attaching it to the QGroupBox - QGCToolWidget *tool = new QGCToolWidget("", parent); QString tooltitle = parameterName; if (parameterName.split("_").size() > 1) { tooltitle = parameterName.split("_")[0] + "_"; } - tool->setTitle(tooltitle); - tool->setObjectName(tooltitle); + QGCToolWidget *tool = new QGCToolWidget(tooltitle, tooltitle, parent); //tool->setSettings(set); libParamToWidgetMap.insert(parameterName,tool); toolWidgets.append(tool); @@ -1525,14 +1499,14 @@ void QGCVehicleConfig::updateView() ui->throttleWidget->setValue(rcValue[2]); ui->yawWidget->setValue(rcValue[3]); - ui->rollWidget->setMin(rcMin[0]); - ui->rollWidget->setMax(rcMax[0]); - ui->pitchWidget->setMin(rcMin[1]); - ui->pitchWidget->setMax(rcMax[1]); - ui->throttleWidget->setMin(rcMin[2]); - ui->throttleWidget->setMax(rcMax[2]); - ui->yawWidget->setMin(rcMin[3]); - ui->yawWidget->setMax(rcMax[3]); + ui->rollWidget->setMin(800); + ui->rollWidget->setMax(2200); + ui->pitchWidget->setMin(800); + ui->pitchWidget->setMax(2200); + ui->throttleWidget->setMin(800); + ui->throttleWidget->setMax(2200); + ui->yawWidget->setMin(800); + ui->yawWidget->setMax(2200); } ui->chanLabel->setText(QString("%1/%2").arg(rcValue[rcMapping[0]]).arg(rcRoll, 5, 'f', 2, QChar(' '))); diff --git a/src/ui/QGCVehicleConfig.h b/src/ui/QGCVehicleConfig.h index 4db21ed1c850eecbfe6f615baa84758f427937ce..d63e32f4fefbe6b6ba184832adb5a6e0f119f4ed 100644 --- a/src/ui/QGCVehicleConfig.h +++ b/src/ui/QGCVehicleConfig.h @@ -158,6 +158,7 @@ protected slots: protected: bool doneLoadingConfig; UASInterface* mav; ///< The current MAV + QGCUASParamManager* paramMgr; ///< params mgr for the mav static const unsigned int chanMax = 8; ///< Maximum number of channels unsigned int chanCount; ///< Actual channels int rcType; ///< Type of the remote control diff --git a/src/ui/SerialConfigurationWindow.cc b/src/ui/SerialConfigurationWindow.cc index 499188ea2d5d5c459d10eac3657cdfac88672e89..338e2d3283f7ce66995857d72bdc7df6fd5f011d 100644 --- a/src/ui/SerialConfigurationWindow.cc +++ b/src/ui/SerialConfigurationWindow.cc @@ -129,10 +129,13 @@ SerialConfigurationWindow::SerialConfigurationWindow(LinkInterface* link, QWidge connect(ui.parEven, SIGNAL(toggled(bool)), this, SLOT(setParityEven(bool))); connect(ui.dataBitsSpinBox, SIGNAL(valueChanged(int)), this->link, SLOT(setDataBits(int))); connect(ui.stopBitsSpinBox, SIGNAL(valueChanged(int)), this->link, SLOT(setStopBits(int))); + connect(ui.advCheckBox,SIGNAL(clicked(bool)),ui.advGroupBox,SLOT(setShown(bool))); + ui.advCheckBox->setChecked(false); + ui.advGroupBox->setVisible(false); //connect(this->link, SIGNAL(connected(bool)), this, SLOT()); - ui.portName->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); - ui.baudRate->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); + //ui.portName->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); + //ui.baudRate->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); switch(this->link->getParityType()) { case 0: @@ -216,23 +219,23 @@ void SerialConfigurationWindow::setupPortList() if (!link) return; // Get the ports available on this system - QVector* ports = link->getCurrentPorts(); + QList ports = link->getCurrentPorts(); QString storedName = this->link->getPortName(); bool storedFound = false; // Add the ports in reverse order, because we prepend them to the list - for (int i = ports->size() - 1; i >= 0; --i) + for (int i = ports.count() - 1; i >= 0; --i) { // Prepend newly found port to the list - if (ui.portName->findText(ports->at(i)) == -1) + if (ui.portName->findText(ports[i]) == -1) { - ui.portName->insertItem(0, ports->at(i)); - if (!userConfigured) ui.portName->setEditText(ports->at(i)); + ui.portName->insertItem(0, ports[i]); + if (!userConfigured) ui.portName->setEditText(ports[i]); } // Check if the stored link name is still present - if (ports->at(i).contains(storedName) || storedName.contains(ports->at(i))) + if (ports[i].contains(storedName) || storedName.contains(ports[i])) storedFound = true; } @@ -259,7 +262,7 @@ void SerialConfigurationWindow::setParityNone(bool accept) void SerialConfigurationWindow::setParityOdd(bool accept) { - if (accept) link->setParityType(1); + if (accept) link->setParityType(1); // [TODO] This needs to be Fixed [BB] } void SerialConfigurationWindow::setParityEven(bool accept) diff --git a/src/ui/SerialSettings.ui b/src/ui/SerialSettings.ui index 605672000966dcfa538ecfe1144b806638f3ff2a..2a23c835ff171a57ff1e8cda16e295ee658236d2 100644 --- a/src/ui/SerialSettings.ui +++ b/src/ui/SerialSettings.ui @@ -6,379 +6,445 @@ 0 0 - 304 - 283 + 234 + 354 Form - - - 6 - - - - - Serial Port - - - - - - - The serial port to which the system is connected. All ports listed here should work. - - - The serial port to which the system is connected. All ports listed here should work. - - - The serial port to which the system is connected. All ports listed here should work. - - - true - - - QComboBox::AdjustToContents - - - - - - - - - - - - Baud Rate - - - - - - - The data transmission rate. If unsure 57600 and 115200 are very common rates. - - - The data transmission rate. If unsure 57600 and 115200 are very common rates. - - - The data transmission rate. If unsure 57600 and 115200 are very common rates. - - - false - - - QComboBox::AdjustToContents - - - - 50 - - - - - 75 - - - - - 110 - - - - - 134 - - - - - 150 - - - - - 200 - - - - - 300 - - - - - 600 - - - - - 1200 - - - - - 1800 - - - - - 2400 - - - - - 4800 - - - - - 9600 - - - - - 14400 - - - - - 19200 - - - - - 38400 - - - - - 56000 - - - - - 57600 - - - - - 76800 - - - - - 115200 - - - - - 128000 - - - - - 230400 - - - - - 256000 - - - - - 460800 - - + + + - - 921600 - + + + Serial Port + + - - - - - - Flow Control - - - - - - - Activate / deactivate hardware flow control. Commonly deactivated - - - Activate / deactivate hardware flow control. Commonly deactivated - - - Activate / deactivate hardware flow control. Commonly deactivated - - - Active - - - - - - - Parity - - - - - - + + + + 100 + 0 + + - Set the parity. In most cases no parity (None) is used. + The serial port to which the system is connected. All ports listed here should work. - Set the parity. In most cases no parity (None) is used. + The serial port to which the system is connected. All ports listed here should work. - Set the parity. In most cases no parity (None) is used. - - - None + The serial port to which the system is connected. All ports listed here should work. - + true + + QComboBox::AdjustToContents + + + + + + + + + + - - - Set the parity. In most cases no parity (None) is used. - - - Set the parity. In most cases no parity (None) is used. - - - Set the parity. In most cases no parity (None) is used. - + - Odd + Baud Rate - + + + + 100 + 0 + + - Set the parity. In most cases no parity (None) is used. + The data transmission rate. If unsure 57600 and 115200 are very common rates. - Set the parity. In most cases no parity (None) is used. + The data transmission rate. If unsure 57600 and 115200 are very common rates. - Set the parity. In most cases no parity (None) is used. + The data transmission rate. If unsure 57600 and 115200 are very common rates. - - Even + + false + + + QComboBox::AdjustToContents + + + 50 + + + + + 75 + + + + + 110 + + + + + 134 + + + + + 150 + + + + + 200 + + + + + 300 + + + + + 600 + + + + + 1200 + + + + + 1800 + + + + + 2400 + + + + + 4800 + + + + + 9600 + + + + + 14400 + + + + + 19200 + + + + + 38400 + + + + + 56000 + + + + + 57600 + + + + + 76800 + + + + + 115200 + + + + + 128000 + + + + + 230400 + + + + + 256000 + + + + + 460800 + + + + + 921600 + + - - - - - 0 - 0 - - - - - 0 - 0 - - - - Number of data bits per symbol. This is almost always 8. - - - Number of data bits per symbol. This is almost always 8. - - - Number of data bits per symbol. This is almost always 8. - - - 5 - - - 8 - - - 5 - - - - - + + - Stop bits + Show Advanced Port Settings - - - - - 0 - 0 - - - - Number of stop bits per symbol. This is almost always 2. - - - Number of stop bits per symbol. This is almost always 2. - - - Number of stop bits per symbol. This is almost always 2. - - - true - - - false - - - 1 - - - 2 - - - 2 - - + + + + + + Advanced + + + + + + + + Flow Control + + + + + + + Activate / deactivate hardware flow control. Commonly deactivated + + + Activate / deactivate hardware flow control. Commonly deactivated + + + Activate / deactivate hardware flow control. Commonly deactivated + + + Active + + + + + + + + + + + Parity + + + + + + + + + Set the parity. In most cases no parity (None) is used. + + + Set the parity. In most cases no parity (None) is used. + + + Set the parity. In most cases no parity (None) is used. + + + None + + + true + + + + + + + Set the parity. In most cases no parity (None) is used. + + + Set the parity. In most cases no parity (None) is used. + + + Set the parity. In most cases no parity (None) is used. + + + Odd + + + + + + + Set the parity. In most cases no parity (None) is used. + + + Set the parity. In most cases no parity (None) is used. + + + Set the parity. In most cases no parity (None) is used. + + + Even + + + + + + + + + + + + + Data bits + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + Number of data bits per symbol. This is almost always 8. + + + Number of data bits per symbol. This is almost always 8. + + + Number of data bits per symbol. This is almost always 8. + + + 5 + + + 8 + + + 5 + + + + + + + + + + + Stop bits + + + + + + + + 0 + 0 + + + + Number of stop bits per symbol. This is almost always 2. + + + Number of stop bits per symbol. This is almost always 2. + + + Number of stop bits per symbol. This is almost always 2. + + + true + + + false + + + 1 + + + 2 + + + 2 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - + Qt::Vertical - 0 - 0 + 20 + 40 - - - - Data bits - - - diff --git a/src/ui/UASRawStatusView.cpp b/src/ui/UASRawStatusView.cpp index 51c48191bf33379445777da242058d91bb014dbc..b46af50268e2c84ac6c9f09d81f2642047713dde 100644 --- a/src/ui/UASRawStatusView.cpp +++ b/src/ui/UASRawStatusView.cpp @@ -20,51 +20,20 @@ UASRawStatusView::UASRawStatusView(QWidget *parent) : QWidget(parent) } void UASRawStatusView::addSource(MAVLinkDecoder *decoder) { - connect(decoder,SIGNAL(valueChanged(int,QString,QString,double,quint64)),this,SLOT(valueChanged(int,QString,QString,double,quint64))); - connect(decoder,SIGNAL(valueChanged(int,QString,QString,qint8,quint64)),this,SLOT(valueChanged(int,QString,QString,qint8,quint64))); - connect(decoder,SIGNAL(valueChanged(int,QString,QString,qint16,quint64)),this,SLOT(valueChanged(int,QString,QString,qint16,quint64))); - connect(decoder,SIGNAL(valueChanged(int,QString,QString,qint32,quint64)),this,SLOT(valueChanged(int,QString,QString,qint32,quint64))); - connect(decoder,SIGNAL(valueChanged(int,QString,QString,qint64,quint64)),this,SLOT(valueChanged(int,QString,QString,qint64,quint64))); - connect(decoder,SIGNAL(valueChanged(int,QString,QString,quint8,quint64)),this,SLOT(valueChanged(int,QString,QString,quint8,quint64))); - connect(decoder,SIGNAL(valueChanged(int,QString,QString,qint16,quint64)),this,SLOT(valueChanged(int,QString,QString,qint16,quint64))); - connect(decoder,SIGNAL(valueChanged(int,QString,QString,quint32,quint64)),this,SLOT(valueChanged(int,QString,QString,quint32,quint64))); - connect(decoder,SIGNAL(valueChanged(int,QString,QString,quint64,quint64)),this,SLOT(valueChanged(int,QString,QString,quint64,quint64))); + connect(decoder,SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)),this,SLOT(valueChanged(int,QString,QString,QVariant,quint64))); } -void UASRawStatusView::valueChanged(const int uasId, const QString& name, const QString& unit, const quint8 value, const quint64 msec) +void UASRawStatusView::valueChanged(const int uasId, const QString& name, const QString& unit, const QVariant &variant, const quint64 msec) { - valueChanged(uasId,name,unit,(double)value,msec); -} -void UASRawStatusView::valueChanged(const int uasId, const QString& name, const QString& unit, const qint8 value, const quint64 msec) -{ - valueChanged(uasId,name,unit,(double)value,msec); -} -void UASRawStatusView::valueChanged(const int uasId, const QString& name, const QString& unit, const quint16 value, const quint64 msec) -{ - valueChanged(uasId,name,unit,(double)value,msec); -} -void UASRawStatusView::valueChanged(const int uasId, const QString& name, const QString& unit, const qint16 value, const quint64 msec) -{ - valueChanged(uasId,name,unit,(double)value,msec); -} -void UASRawStatusView::valueChanged(const int uasId, const QString& name, const QString& unit, const quint32 value, const quint64 msec) -{ - valueChanged(uasId,name,unit,(double)value,msec); -} -void UASRawStatusView::valueChanged(const int uasId, const QString& name, const QString& unit, const qint32 value, const quint64 msec) -{ - valueChanged(uasId,name,unit,(double)value,msec); -} -void UASRawStatusView::valueChanged(const int uasId, const QString& name, const QString& unit, const quint64 value, const quint64 msec) -{ - valueChanged(uasId,name,unit,(double)value,msec); -} -void UASRawStatusView::valueChanged(const int uasId, const QString& name, const QString& unit, const qint64 value, const quint64 msec) -{ - valueChanged(uasId,name,unit,(double)value,msec); -} + Q_UNUSED(uasId); + Q_UNUSED(unit); + Q_UNUSED(msec); + + bool ok; + double value = variant.toDouble(&ok); + QMetaType::Type type = static_cast(variant.type()); + if(!ok || type == QMetaType::QString || type == QMetaType::QByteArray) + return; -void UASRawStatusView::valueChanged(const int uasId, const QString& name, const QString& unit, const double value, const quint64 msec) -{ valueMap[name] = value; if (nameToUpdateWidgetMap.contains(name)) { @@ -122,6 +91,7 @@ void UASRawStatusView::updateTableTimerTick() //We're over what we can do. Add a column and continue. columncount+=2; broke = true; + i = valueMap.constEnd(); // Ensure loop breakout. break; } } diff --git a/src/ui/UASRawStatusView.h b/src/ui/UASRawStatusView.h index cc3828152d00b3a1e845e39a2fc4b8d789e0e806..2da632c33a50ec28ed2019fcab8c71399e62f209 100644 --- a/src/ui/UASRawStatusView.h +++ b/src/ui/UASRawStatusView.h @@ -15,15 +15,7 @@ public: void addSource(MAVLinkDecoder *decoder); private slots: void updateTableTimerTick(); - void valueChanged(const int uasId, const QString& name, const QString& unit, const quint8 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const qint8 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const quint16 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const qint16 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const quint32 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const qint32 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const quint64 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const qint64 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const double value, const quint64 msec); + void valueChanged(const int uasId, const QString& name, const QString& unit, const QVariant& value, const quint64 msec); protected: void resizeEvent(QResizeEvent *event); private: diff --git a/src/ui/XbeeConfigurationWindow.cpp b/src/ui/XbeeConfigurationWindow.cpp index 7be847ac651f6300758dc7ee8355238d5803045c..72104bffd966b65cd69d67a0a754bf826bf202bf 100644 --- a/src/ui/XbeeConfigurationWindow.cpp +++ b/src/ui/XbeeConfigurationWindow.cpp @@ -8,7 +8,8 @@ #include #ifdef _WIN32 -#include +//#include +#include #endif #if defined (__APPLE__) && defined (__MACH__) @@ -368,11 +369,12 @@ void XbeeConfigurationWindow::setupPortList() #ifdef _WIN32 // Get the ports available on this system - QList ports = QextSerialEnumerator::getPorts(); + QList ports = QSerialPortInfo::availablePorts(); + //QList ports = QextSerialEnumerator::getPorts(); // Add the ports in reverse order, because we prepend them to the list for (int i = ports.size() - 1; i >= 0; i--) { - QString portString = QString(ports.at(i).portName.toLocal8Bit().constData()) + " - " + QString(ports.at(i).friendName.toLocal8Bit().constData()).split("(").first(); + QString portString = QString(ports.at(i).portName().toLocal8Bit().constData()); // Prepend newly found port to the list if (portBox->findText(portString) == -1) { portBox->insertItem(0, portString); diff --git a/src/ui/apmtoolbar.cpp b/src/ui/apmtoolbar.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b82aa8641fa89cf42fbd8ef7fb5efdd907ad49d --- /dev/null +++ b/src/ui/apmtoolbar.cpp @@ -0,0 +1,218 @@ +#include +#include +#include +#include "LinkManager.h" +#include "MainWindow.h" + +#include "apmtoolbar.h" + +APMToolBar::APMToolBar(QWidget *parent): + QDeclarativeView(parent), m_uas(0) +{ + // Configure our QML object + + // Hack to fix QTBUG 34300 on OSX where QDir::currentPath has changed behavior. This causes + // relative paths to inside the .app package to fail. +#ifdef Q_OS_MAC + QString qmlFile = QApplication::applicationDirPath(); + qmlFile.append("/qml/ApmToolBar.qml"); + setSource(QUrl::fromLocalFile(qmlFile)); +#else + setSource(QUrl::fromLocalFile("qml/ApmToolBar.qml")); +#endif + setResizeMode(QDeclarativeView::SizeRootObjectToView); + this->rootContext()->setContextProperty("globalObj", this); + connect(LinkManager::instance(),SIGNAL(newLink(LinkInterface*)), + this, SLOT(updateLinkDisplay(LinkInterface*))); + + if (LinkManager::instance()->getLinks().count()>=3) { + updateLinkDisplay(LinkManager::instance()->getLinks().last()); + } + + setConnection(false); + + connect(UASManager::instance(),SIGNAL(activeUASSet(UASInterface*)),this,SLOT(activeUasSet(UASInterface*))); + activeUasSet(UASManager::instance()->getActiveUAS()); +} +void APMToolBar::activeUasSet(UASInterface *uas) +{ + if (!uas) + { + return; + } + if (m_uas) + { + disconnect(m_uas,SIGNAL(armingChanged(bool)), + this,SLOT(armingChanged(bool))); + disconnect(uas,SIGNAL(armingChanged(int, QString)), + this,SLOT(armingChanged(int, QString))); + } + connect(uas,SIGNAL(armingChanged(bool)), + this,SLOT(armingChanged(bool))); + connect(uas,SIGNAL(armingChanged(int, QString)), + this,SLOT(armingChanged(int, QString))); + +} +void APMToolBar::armingChanged(bool armed) +{ + this->rootObject()->setProperty("armed",armed); +} + +void APMToolBar::armingChanged(int sysId, QString armingState) +{ + qDebug() << "APMToolBar: sysid " << sysId << " armState" << armingState; +} + +void APMToolBar::setFlightViewAction(QAction *action) +{ + connect(this, SIGNAL(triggerFlightView()), action, SIGNAL(triggered())); +} + +void APMToolBar::setFlightPlanViewAction(QAction *action) +{ + connect(this, SIGNAL(triggerFlightPlanView()), action, SIGNAL(triggered())); +} + +void APMToolBar::setHardwareViewAction(QAction *action) +{ + connect(this, SIGNAL(triggerHardwareView()), action, SIGNAL(triggered())); +} + +void APMToolBar::setSoftwareViewAction(QAction *action) +{ + connect(this, SIGNAL(triggerSoftwareView()), action, SIGNAL(triggered())); +} + +void APMToolBar::setSimulationViewAction(QAction *action) +{ + connect(this, SIGNAL(triggerSimulationView()), action, SIGNAL(triggered())); +} + +void APMToolBar::setTerminalViewAction(QAction *action) +{ + connect(this, SIGNAL(triggerTerminalView()), action, SIGNAL(triggered())); +} + +void APMToolBar::setConnectMAVAction(QAction *action) +{ + connect(this, SIGNAL(connectMAV()), action, SIGNAL(triggered())); +} + +void APMToolBar::selectFlightView() +{ + qDebug() << "APMToolBar: SelectFlightView"; + emit triggerFlightView(); +} + +void APMToolBar::selectFlightPlanView() +{ + qDebug() << "APMToolBar: SelectFlightPlanView"; + emit triggerFlightPlanView(); +} + +void APMToolBar::selectHardwareView() +{ + qDebug() << "APMToolBar: selectHardwareView"; + emit triggerHardwareView(); +} + +void APMToolBar::selectSoftwareView() +{ + qDebug() << "APMToolBar: selectSoftwareView"; + emit triggerSoftwareView(); +} + +void APMToolBar::selectSimulationView() +{ + qDebug() << "APMToolBar: selectSimulationView"; +} + +void APMToolBar::selectTerminalView() +{ + qDebug() << "APMToolBar: selectTerminalView"; +} + +void APMToolBar::connectMAV() +{ + qDebug() << "APMToolBar: connectMAV "; + + bool connected = false; + if (LinkManager::instance()->getSerialLinks().count() > 0) + connected = LinkManager::instance()->getSerialLinks().last()->isConnected(); + bool result; + + if (!connected && LinkManager::instance()->getSerialLinks().count() == 0) + { + // No Link so prompt to connect one + MainWindow::instance()->addLink(); + } else if (!connected) { + // Need to Connect Link + result = LinkManager::instance()->getSerialLinks().last()->connect(); + + } else if (connected && LinkManager::instance()->getSerialLinks().count() > 0) { + // result need to be the opposite of success. + result = !LinkManager::instance()->getSerialLinks().last()->disconnect(); + } + qDebug() << "result = " << result; + + // Change the image to represent the state + setConnection(result); + + emit MAVConnected(result); +} + +void APMToolBar::setConnection(bool connection) +{ + // Change the image to represent the state + QObject *object = rootObject(); + object->setProperty("connected", connection); +} + +APMToolBar::~APMToolBar() +{ + qDebug() << "Destory APM Toolbar"; +} + +void APMToolBar::showConnectionDialog() +{ + // Displays a UI where the user can select a MAV Link. + qDebug() << "APMToolBar: showConnectionDialog link count =" + << LinkManager::instance()->getLinks().count(); + + bool result; + + if (LinkManager::instance()->getSerialLinks().count() > 0) + { + SerialLink *link = LinkManager::instance()->getSerialLinks().last(); + // Serial Link so prompt to config it + connect(link, SIGNAL(updateLink(LinkInterface*)), + this, SLOT(updateLinkDisplay(LinkInterface*))); + result = MainWindow::instance()->configLink(link); + + if (!result) + qDebug() << "Link Config Failed!"; + } else { + // No Link so prompt to create one + MainWindow::instance()->addLink(); + } + +} + +void APMToolBar::updateLinkDisplay(LinkInterface* newLink) +{ + qDebug() << "APMToolBar: updateLinkDisplay"; + QObject *object = rootObject(); + + if (newLink && object){ + qint64 baudrate = newLink->getNominalDataRate(); + object->setProperty("baudrateLabel", QString::number(baudrate)); + + QString linkName = newLink->getName(); + object->setProperty("linkNameLabel", linkName); + + connect(newLink, SIGNAL(connected(bool)), + this, SLOT(setConnection(bool))); + + setConnection(newLink->isConnected()); + } +} diff --git a/src/ui/apmtoolbar.h b/src/ui/apmtoolbar.h new file mode 100644 index 0000000000000000000000000000000000000000..5bed5a224e0fb9e802f325cbe64d1b3ad2f9e310 --- /dev/null +++ b/src/ui/apmtoolbar.h @@ -0,0 +1,57 @@ +#ifndef APMTOOLBAR_H +#define APMTOOLBAR_H + +#include +#include +#include "UASInterface.h" + +class LinkInterface; + +class APMToolBar : public QDeclarativeView +{ + Q_OBJECT +public: + explicit APMToolBar(QWidget *parent = 0); + ~APMToolBar(); + + void setFlightViewAction(QAction *action); + void setFlightPlanViewAction(QAction *action); + void setHardwareViewAction(QAction *action); + void setSoftwareViewAction(QAction *action); + void setSimulationViewAction(QAction *action); + void setTerminalViewAction(QAction *action); + void setConnectMAVAction(QAction *action); + +signals: + void triggerFlightView(); + void triggerFlightPlanView(); + void triggerHardwareView(); + void triggerSoftwareView(); + void triggerSimulationView(); + void triggerTerminalView(); + + void MAVConnected(bool connected); + +public slots: + void selectFlightView(); + void selectFlightPlanView(); + void selectHardwareView(); + void selectSoftwareView(); + void selectSimulationView(); + void selectTerminalView(); + + void connectMAV(); + void showConnectionDialog(); + void setConnection(bool connection); + + void activeUasSet(UASInterface *uas); + void armingChanged(int sysId, QString armingState); + void armingChanged(bool armed); + + void updateLinkDisplay(LinkInterface *newLink); + +private: + UASInterface *m_uas; +}; + +#endif // APMTOOLBAR_H diff --git a/src/ui/configuration/AP2ConfigWidget.cc b/src/ui/configuration/AP2ConfigWidget.cc new file mode 100644 index 0000000000000000000000000000000000000000..3ce8751b72423c7abb0383c63f617c7d51399250 --- /dev/null +++ b/src/ui/configuration/AP2ConfigWidget.cc @@ -0,0 +1,33 @@ +#include +#include "AP2ConfigWidget.h" + +AP2ConfigWidget::AP2ConfigWidget(QWidget *parent) : QWidget(parent) +{ + m_uas = 0; +} +void AP2ConfigWidget::initConnections() +{ + connect(UASManager::instance(),SIGNAL(activeUASSet(UASInterface*)),this,SLOT(activeUASSet(UASInterface*))); + activeUASSet(UASManager::instance()->getActiveUAS()); +} + +void AP2ConfigWidget::activeUASSet(UASInterface *uas) +{ + if (m_uas) + { + disconnect(m_uas,SIGNAL(parameterChanged(int,int,QString,QVariant)),this,SLOT(parameterChanged(int,int,QString,QVariant))); + m_uas = 0; + } + if (!uas) return; + m_uas = uas; + connect(m_uas,SIGNAL(parameterChanged(int,int,QString,QVariant)),this,SLOT(parameterChanged(int,int,QString,QVariant))); +} + +void AP2ConfigWidget::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + +} +void AP2ConfigWidget::showNullMAVErrorMessageBox() +{ + QMessageBox::information(0,tr("Error"),tr("Please connect to a MAV before attempting to set configuration")); +} diff --git a/src/ui/configuration/AP2ConfigWidget.h b/src/ui/configuration/AP2ConfigWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..b8a397dd249e346f4a3d036692a3887382525db2 --- /dev/null +++ b/src/ui/configuration/AP2ConfigWidget.h @@ -0,0 +1,23 @@ +#ifndef AP2CONFIGWIDGET_H +#define AP2CONFIGWIDGET_H + +#include +#include "UASManager.h" +#include "UASInterface.h" +class AP2ConfigWidget : public QWidget +{ + Q_OBJECT +public: + explicit AP2ConfigWidget(QWidget *parent = 0); +protected: + UASInterface *m_uas; + void showNullMAVErrorMessageBox(); + void initConnections(); +signals: + +public slots: + virtual void activeUASSet(UASInterface *uas); + virtual void parameterChanged(int uas, int component, QString parameterName, QVariant value); +}; + +#endif // AP2CONFIGWIDGET_H diff --git a/src/ui/configuration/AccelCalibrationConfig.cc b/src/ui/configuration/AccelCalibrationConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..f552580d1f9ed9032cc70b9cb3f987ac01d35ca5 --- /dev/null +++ b/src/ui/configuration/AccelCalibrationConfig.cc @@ -0,0 +1,127 @@ +#include "AccelCalibrationConfig.h" + + +AccelCalibrationConfig::AccelCalibrationConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + connect(ui.calibrateAccelButton,SIGNAL(clicked()),this,SLOT(calibrateButtonClicked())); + + m_accelAckCount=0; + initConnections(); +} + +AccelCalibrationConfig::~AccelCalibrationConfig() +{ +} +void AccelCalibrationConfig::activeUASSet(UASInterface *uas) +{ + if (m_uas) + { + disconnect(m_uas,SIGNAL(textMessageReceived(int,int,int,QString)),this,SLOT(uasTextMessageReceived(int,int,int,QString))); + } + AP2ConfigWidget::activeUASSet(uas); + if (!uas) + { + return; + } + connect(m_uas,SIGNAL(textMessageReceived(int,int,int,QString)),this,SLOT(uasTextMessageReceived(int,int,int,QString))); + +} + +void AccelCalibrationConfig::calibrateButtonClicked() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (m_accelAckCount == 0) + { + MAV_CMD command = MAV_CMD_PREFLIGHT_CALIBRATION; + int confirm = 0; + float param1 = 0.0; + float param2 = 0.0; + float param3 = 0.0; + float param4 = 0.0; + float param5 = 1.0; + float param6 = 0.0; + float param7 = 0.0; + int component = 1; + m_uas->executeCommand(command, confirm, param1, param2, param3, param4, param5, param6, param7, component); + } + else if (m_accelAckCount <= 5) + { + m_uas->executeCommandAck(m_accelAckCount++,true); + } + else + { + m_uas->executeCommandAck(m_accelAckCount++,true); + ui.calibrateAccelButton->setText("Calibrate\nAccelerometer"); + if (m_accelAckCount > 8) + { + //We've clicked too many times! Reset. + for (int i=0;i<8;i++) + { + m_uas->executeCommandAck(i,true); + } + m_accelAckCount = 0; + } + } + +} +void AccelCalibrationConfig::hideEvent(QHideEvent *evt) +{ + if (!m_uas || !m_accelAckCount) + { + return; + } + for (int i=m_accelAckCount;i<8;i++) + { + m_uas->executeCommandAck(i,true); //Clear out extra commands. + } +} +void AccelCalibrationConfig::uasTextMessageReceived(int uasid, int componentid, int severity, QString text) +{ + //command received: " Severity 1 + //Place APM Level and press any key" severity 5 + if (severity == 5) + { + //This is a calibration instruction + if (m_accelAckCount == 0) + { + //Calibration Sucessful\r" + ui.calibrateAccelButton->setText("Continue"); + m_accelAckCount++; + } + if (m_accelAckCount == 7) + { + //All finished + //ui.outputLabel->setText(ui.outputLabel->text() + "\n" + text); + ui.outputLabel->setText(text); + m_accelAckCount++; + } + if (m_accelAckCount == 8) + { + if (text.contains("Calibration") && text.contains("successful")) + { + m_accelAckCount = 0; + } + else if (text.contains("Calibration") && text.contains("FAILED")) //Failure + { + m_accelAckCount = 0; + } + ui.outputLabel->setText(ui.outputLabel->text() + "\n" + text); + } + else + { + ui.outputLabel->setText(text.replace("press any key","click Continue below")); + if (!this->isVisible()) + { + //Clear out! + m_uas->executeCommandAck(m_accelAckCount++,true); + ui.calibrateAccelButton->setText("Calibrate\nAccelerometer"); + } + } + } + +} diff --git a/src/ui/configuration/AccelCalibrationConfig.h b/src/ui/configuration/AccelCalibrationConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..152656253405c78df81c81b3a68a93f65fa86683 --- /dev/null +++ b/src/ui/configuration/AccelCalibrationConfig.h @@ -0,0 +1,28 @@ +#ifndef ACCELCALIBRATIONCONFIG_H +#define ACCELCALIBRATIONCONFIG_H + +#include +#include "ui_AccelCalibrationConfig.h" +#include "UASManager.h" +#include "UASInterface.h" +#include "AP2ConfigWidget.h" + +class AccelCalibrationConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit AccelCalibrationConfig(QWidget *parent = 0); + ~AccelCalibrationConfig(); +protected: + void hideEvent(QHideEvent *evt); +private slots: + void activeUASSet(UASInterface *uas); + void calibrateButtonClicked(); + void uasTextMessageReceived(int uasid, int componentid, int severity, QString text); +private: + int m_accelAckCount; + Ui::AccelCalibrationConfig ui; +}; + +#endif // ACCELCALIBRATIONCONFIG_H diff --git a/src/ui/configuration/AccelCalibrationConfig.ui b/src/ui/configuration/AccelCalibrationConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..6555a572584b14a77a048a68d7d8cb0a2ccd2c13 --- /dev/null +++ b/src/ui/configuration/AccelCalibrationConfig.ui @@ -0,0 +1,62 @@ + + + AccelCalibrationConfig + + + + 0 + 0 + 576 + 354 + + + + Form + + + + + 10 + 0 + 231 + 31 + + + + <h2>Accelerometer Calibration</h2> + + + false + + + + + + 70 + 160 + 111 + 41 + + + + Calibrate +Accelerometer + + + + + + 20 + 50 + 311 + 101 + + + + + + + + + + diff --git a/src/ui/configuration/AdvParameterList.cc b/src/ui/configuration/AdvParameterList.cc new file mode 100644 index 0000000000000000000000000000000000000000..24a5bc384e146e91954e7da57caedd6892bd6e14 --- /dev/null +++ b/src/ui/configuration/AdvParameterList.cc @@ -0,0 +1,53 @@ +#include "AdvParameterList.h" + + +AdvParameterList::AdvParameterList(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + ui.tableWidget->setColumnCount(4); + ui.tableWidget->horizontalHeader()->hide(); + ui.tableWidget->verticalHeader()->hide(); + ui.tableWidget->setColumnWidth(0,200); + ui.tableWidget->setColumnWidth(1,100); + ui.tableWidget->setColumnWidth(2,200); + ui.tableWidget->setColumnWidth(3,800); + initConnections(); +} + +AdvParameterList::~AdvParameterList() +{ +} +void AdvParameterList::setParameterMetaData(QString name,QString humanname,QString description) +{ + m_paramToNameMap[name] = humanname; + m_paramToDescriptionMap[name] = description; +} + +void AdvParameterList::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + + if (!m_paramValueMap.contains(parameterName)) + { + ui.tableWidget->setRowCount(ui.tableWidget->rowCount()+1); + if (m_paramToNameMap.contains(parameterName)) + { + ui.tableWidget->setItem(ui.tableWidget->rowCount()-1,0,new QTableWidgetItem(m_paramToNameMap[parameterName])); + } + else + { + ui.tableWidget->setItem(ui.tableWidget->rowCount()-1,0,new QTableWidgetItem("Unknown")); + } + ui.tableWidget->setItem(ui.tableWidget->rowCount()-1,1,new QTableWidgetItem(QString::number(value.toFloat(),'f',2))); + ui.tableWidget->setItem(ui.tableWidget->rowCount()-1,2,new QTableWidgetItem(parameterName)); + if (m_paramToDescriptionMap.contains(parameterName)) + { + ui.tableWidget->setItem(ui.tableWidget->rowCount()-1,3,new QTableWidgetItem(m_paramToDescriptionMap[parameterName])); + } + else + { + ui.tableWidget->setItem(ui.tableWidget->rowCount()-1,3,new QTableWidgetItem("Unknown")); + } + m_paramValueMap[parameterName] = ui.tableWidget->item(ui.tableWidget->rowCount()-1,1); + } + m_paramValueMap[parameterName]->setText(QString::number(value.toFloat(),'f',2)); +} diff --git a/src/ui/configuration/AdvParameterList.h b/src/ui/configuration/AdvParameterList.h new file mode 100644 index 0000000000000000000000000000000000000000..6ff55a22ff28b105f82f780436805539a88d3628 --- /dev/null +++ b/src/ui/configuration/AdvParameterList.h @@ -0,0 +1,25 @@ +#ifndef ADVPARAMETERLIST_H +#define ADVPARAMETERLIST_H + +#include +#include "ui_AdvParameterList.h" +#include "AP2ConfigWidget.h" + +class AdvParameterList : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit AdvParameterList(QWidget *parent = 0); + void setParameterMetaData(QString name,QString humanname,QString description); + ~AdvParameterList(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); +private: + QMap m_paramValueMap; + QMap m_paramToNameMap; + QMap m_paramToDescriptionMap; + Ui::AdvParameterList ui; +}; + +#endif // ADVPARAMETERLIST_H diff --git a/src/ui/configuration/AdvParameterList.ui b/src/ui/configuration/AdvParameterList.ui new file mode 100644 index 0000000000000000000000000000000000000000..3b18893d2779326a068dca7fbd15ced27f7f1b0a --- /dev/null +++ b/src/ui/configuration/AdvParameterList.ui @@ -0,0 +1,31 @@ + + + AdvParameterList + + + + 0 + 0 + 666 + 497 + + + + Form + + + + + + <h2>Full Parameter List</h2> + + + + + + + + + + + diff --git a/src/ui/configuration/AdvancedParamConfig.cc b/src/ui/configuration/AdvancedParamConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..98f0c1c62e4df6cca8798dc05b15c1df7fe96da1 --- /dev/null +++ b/src/ui/configuration/AdvancedParamConfig.cc @@ -0,0 +1,64 @@ +#include "AdvancedParamConfig.h" + + +AdvancedParamConfig::AdvancedParamConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + initConnections(); +} + +AdvancedParamConfig::~AdvancedParamConfig() +{ +} +void AdvancedParamConfig::addRange(QString title,QString description,QString param,double min,double max) +{ + ParamWidget *widget = new ParamWidget(param,ui.scrollAreaWidgetContents); + connect(widget,SIGNAL(doubleValueChanged(QString,double)),this,SLOT(doubleValueChanged(QString,double))); + connect(widget,SIGNAL(intValueChanged(QString,int)),this,SLOT(intValueChanged(QString,int))); + m_paramToWidgetMap[param] = widget; + widget->setupDouble(title + "(" + param + ")",description,0,min,max); + ui.verticalLayout->addWidget(widget); + widget->show(); +} + +void AdvancedParamConfig::addCombo(QString title,QString description,QString param,QList > valuelist) +{ + ParamWidget *widget = new ParamWidget(param,ui.scrollAreaWidgetContents); + connect(widget,SIGNAL(doubleValueChanged(QString,double)),this,SLOT(doubleValueChanged(QString,double))); + connect(widget,SIGNAL(intValueChanged(QString,int)),this,SLOT(intValueChanged(QString,int))); + m_paramToWidgetMap[param] = widget; + widget->setupCombo(title + "(" + param + ")",description,valuelist); + ui.verticalLayout->addWidget(widget); + widget->show(); +} +void AdvancedParamConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (m_paramToWidgetMap.contains(parameterName)) + { + if (value.type() == QVariant::Double) + { + m_paramToWidgetMap[parameterName]->setValue(value.toDouble()); + } + else + { + m_paramToWidgetMap[parameterName]->setValue(value.toInt()); + } + } +} +void AdvancedParamConfig::doubleValueChanged(QString param,double value) +{ + if (!m_uas) + { + this->showNullMAVErrorMessageBox(); + } + m_uas->getParamManager()->setParameter(1,param,value); +} + +void AdvancedParamConfig::intValueChanged(QString param,int value) +{ + if (!m_uas) + { + this->showNullMAVErrorMessageBox(); + } + m_uas->getParamManager()->setParameter(1,param,value); +} diff --git a/src/ui/configuration/AdvancedParamConfig.h b/src/ui/configuration/AdvancedParamConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..07e55d61d1d697e360861cc9814afaada7f2bdb1 --- /dev/null +++ b/src/ui/configuration/AdvancedParamConfig.h @@ -0,0 +1,26 @@ +#ifndef ADVANCEDPARAMCONFIG_H +#define ADVANCEDPARAMCONFIG_H + +#include +#include "ui_AdvancedParamConfig.h" +#include "AP2ConfigWidget.h" +#include "ParamWidget.h" +class AdvancedParamConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit AdvancedParamConfig(QWidget *parent = 0); + ~AdvancedParamConfig(); + void addRange(QString title,QString description,QString param,double min,double max); + void addCombo(QString title,QString description,QString param,QList > valuelist); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void doubleValueChanged(QString param,double value); + void intValueChanged(QString param,int value); +private: + QMap m_paramToWidgetMap; + Ui::AdvancedParamConfig ui; +}; + +#endif // ADVANCEDPARAMCONFIG_H diff --git a/src/ui/configuration/AdvancedParamConfig.ui b/src/ui/configuration/AdvancedParamConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..596861a3a2aeb2ea2792cc74ea184cf89ee3dae1 --- /dev/null +++ b/src/ui/configuration/AdvancedParamConfig.ui @@ -0,0 +1,50 @@ + + + AdvancedParamConfig + + + + 0 + 0 + 725 + 632 + + + + Form + + + + + + <h2>Advanced Params</h2> + + + + + + + true + + + + + 0 + 0 + 705 + 585 + + + + + + + + + + + + + + + diff --git a/src/ui/configuration/AirspeedConfig.cc b/src/ui/configuration/AirspeedConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..27699996b103dec27c5dc40e2169d609a1a85e2e --- /dev/null +++ b/src/ui/configuration/AirspeedConfig.cc @@ -0,0 +1,83 @@ +#include "AirspeedConfig.h" +#include + +AirspeedConfig::AirspeedConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + connect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(enableCheckBoxClicked(bool))); + connect(ui.useAirspeedCheckBox,SIGNAL(toggled(bool)),this,SLOT(useCheckBoxClicked(bool))); + initConnections(); +} + +AirspeedConfig::~AirspeedConfig() +{ +} +void AirspeedConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (parameterName == "ARSPD_ENABLE") + { + if (value.toInt() == 0) + { + disconnect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(enableCheckBoxClicked(bool))); + ui.enableCheckBox->setChecked(false); + connect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(enableCheckBoxClicked(bool))); + ui.useAirspeedCheckBox->setEnabled(false); + } + else + { + disconnect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(enableCheckBoxClicked(bool))); + ui.enableCheckBox->setChecked(true); + connect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(enableCheckBoxClicked(bool))); + ui.useAirspeedCheckBox->setEnabled(true); + } + } + else if (parameterName == "ARSPD_USE") + { + if (value.toInt() == 0) + { + disconnect(ui.useAirspeedCheckBox,SIGNAL(toggled(bool)),this,SLOT(useCheckBoxClicked(bool))); + ui.useAirspeedCheckBox->setChecked(false); + connect(ui.useAirspeedCheckBox,SIGNAL(toggled(bool)),this,SLOT(useCheckBoxClicked(bool))); + } + else + { + disconnect(ui.useAirspeedCheckBox,SIGNAL(toggled(bool)),this,SLOT(useCheckBoxClicked(bool))); + ui.useAirspeedCheckBox->setChecked(true); + connect(ui.useAirspeedCheckBox,SIGNAL(toggled(bool)),this,SLOT(useCheckBoxClicked(bool))); + } + } +} + +void AirspeedConfig::useCheckBoxClicked(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (checked) + { + m_uas->getParamManager()->setParameter(1,"ARSPD_USE",1); + } + else + { + m_uas->getParamManager()->setParameter(1,"ARSPD_USE",0); + } +} + +void AirspeedConfig::enableCheckBoxClicked(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (checked) + { + m_uas->getParamManager()->setParameter(1,"ARSPD_ENABLE",1); + } + else + { + m_uas->getParamManager()->setParameter(1,"ARSPD_ENABLE",0); + } +} diff --git a/src/ui/configuration/AirspeedConfig.h b/src/ui/configuration/AirspeedConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..1646b36759fa0154eb23120203edc0873ead70bc --- /dev/null +++ b/src/ui/configuration/AirspeedConfig.h @@ -0,0 +1,23 @@ +#ifndef AIRSPEEDCONFIG_H +#define AIRSPEEDCONFIG_H + +#include +#include "AP2ConfigWidget.h" +#include "ui_AirspeedConfig.h" + +class AirspeedConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit AirspeedConfig(QWidget *parent = 0); + ~AirspeedConfig(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void useCheckBoxClicked(bool checked); + void enableCheckBoxClicked(bool checked); +private: + Ui::AirspeedConfig ui; +}; + +#endif // AIRSPEEDCONFIG_H diff --git a/src/ui/configuration/AirspeedConfig.ui b/src/ui/configuration/AirspeedConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..7d33cae3664b7dec1d1e5ce1bbf64beca2735ed7 --- /dev/null +++ b/src/ui/configuration/AirspeedConfig.ui @@ -0,0 +1,82 @@ + + + AirspeedConfig + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + 20 + 20 + 131 + 31 + + + + <h2>Airspeed</h2> + + + false + + + + + + 20 + 60 + 71 + 71 + + + + + + + :/files/images/devices/BR-0004-03-2.jpg + + + true + + + + + + 110 + 70 + 70 + 17 + + + + Enable + + + + + + 110 + 100 + 91 + 17 + + + + Use Airspeed + + + + + + + + diff --git a/src/ui/configuration/AntennaTrackerConfig.cc b/src/ui/configuration/AntennaTrackerConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..6b406da474fe3a268c47a42eee4255ca83f4c037 --- /dev/null +++ b/src/ui/configuration/AntennaTrackerConfig.cc @@ -0,0 +1,11 @@ +#include "AntennaTrackerConfig.h" + + +AntennaTrackerConfig::AntennaTrackerConfig(QWidget *parent) : QWidget(parent) +{ + ui.setupUi(this); +} + +AntennaTrackerConfig::~AntennaTrackerConfig() +{ +} diff --git a/src/ui/configuration/AntennaTrackerConfig.h b/src/ui/configuration/AntennaTrackerConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..35271cb288b08e58252f7599c6f65cee07062017 --- /dev/null +++ b/src/ui/configuration/AntennaTrackerConfig.h @@ -0,0 +1,19 @@ +#ifndef ANTENNATRACKERCONFIG_H +#define ANTENNATRACKERCONFIG_H + +#include +#include "ui_AntennaTrackerConfig.h" + +class AntennaTrackerConfig : public QWidget +{ + Q_OBJECT + +public: + explicit AntennaTrackerConfig(QWidget *parent = 0); + ~AntennaTrackerConfig(); + +private: + Ui::AntennaTrackerConfig ui; +}; + +#endif // ANTENNATRACKERCONFIG_H diff --git a/src/ui/configuration/AntennaTrackerConfig.ui b/src/ui/configuration/AntennaTrackerConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..f355fc4ca95baf26f51d6789540354c27152e04d --- /dev/null +++ b/src/ui/configuration/AntennaTrackerConfig.ui @@ -0,0 +1,311 @@ + + + AntennaTrackerConfig + + + + 0 + 0 + 1171 + 560 + + + + Form + + + + + 20 + 10 + 151 + 31 + + + + <h2>Antenna Tracker</h2> + + + false + + + + + + 20 + 50 + 46 + 13 + + + + Interface + + + + + + 80 + 50 + 69 + 22 + + + + + + + 160 + 50 + 69 + 22 + + + + + + + 240 + 50 + 69 + 22 + + + + + + + 320 + 50 + 75 + 23 + + + + Connect + + + + + + 20 + 80 + 581 + 131 + + + + Pan + + + + + + + + + + Angle + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + PWM + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Center PWM + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + + + + + + + + + + + Trim + + + Qt::AlignCenter + + + + + + + -180 + + + 0 + + + Qt::Horizontal + + + + + + + 0 + + + Qt::AlignCenter + + + + + + + + + Rev + + + + + + + + + + + 20 + 220 + 581 + 131 + + + + Tilt + + + + + + + + + + Angle + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + PWM + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Center PWM + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + + + + + + + + + + + Trim + + + Qt::AlignCenter + + + + + + + -180 + + + 180 + + + Qt::Horizontal + + + + + + + 0 + + + Qt::AlignCenter + + + + + + + + + Rev + + + + + + + + + + + diff --git a/src/ui/configuration/ApmFirmwareConfig.cc b/src/ui/configuration/ApmFirmwareConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..4ef8950d592de49ba3cc094d28cb3263ad5e5492 --- /dev/null +++ b/src/ui/configuration/ApmFirmwareConfig.cc @@ -0,0 +1,461 @@ +#include + +#include "LinkManager.h" +#include "LinkInterface.h" +#include "qserialport.h" +#include "qserialportinfo.h" +#include "SerialLink.h" + +#include "ApmFirmwareConfig.h" + +ApmFirmwareConfig::ApmFirmwareConfig(QWidget *parent) : QWidget(parent) +{ + ui.setupUi(this); + //firmwareStatus = 0; + m_betaFirmwareChecked = false; + m_tempFirmwareFile=0; + // + + //QNetworkRequest req(QUrl("https://raw.github.com/diydrones/binary/master/Firmware/firmware2.xml")); + + + + m_networkManager = new QNetworkAccessManager(this); + + connect(ui.roverPushButton,SIGNAL(clicked()),this,SLOT(flashButtonClicked())); + connect(ui.planePushButton,SIGNAL(clicked()),this,SLOT(flashButtonClicked())); + connect(ui.copterPushButton,SIGNAL(clicked()),this,SLOT(flashButtonClicked())); + connect(ui.hexaPushButton,SIGNAL(clicked()),this,SLOT(flashButtonClicked())); + connect(ui.octaQuadPushButton,SIGNAL(clicked()),this,SLOT(flashButtonClicked())); + connect(ui.octaPushButton,SIGNAL(clicked()),this,SLOT(flashButtonClicked())); + connect(ui.quadPushButton,SIGNAL(clicked()),this,SLOT(flashButtonClicked())); + connect(ui.triPushButton,SIGNAL(clicked()),this,SLOT(flashButtonClicked())); + connect(ui.y6PushButton,SIGNAL(clicked()),this,SLOT(flashButtonClicked())); + QTimer::singleShot(10000,this,SLOT(requestFirmwares())); + connect(ui.betaFirmwareButton,SIGNAL(clicked(bool)),this,SLOT(betaFirmwareButtonClicked(bool))); + + ui.progressBar->setMaximum(100); + ui.progressBar->setValue(0); + + ui.textBrowser->setVisible(false); + connect(ui.showOutputCheckBox,SIGNAL(clicked(bool)),ui.textBrowser,SLOT(setShown(bool))); + + /*addBetaLabel(ui.roverPushButton); + addBetaLabel(ui.planePushButton); + addBetaLabel(ui.copterPushButton); + addBetaLabel(ui.quadPushButton); + addBetaLabel(ui.hexaPushButton); + addBetaLabel(ui.octaQuadPushButton); + addBetaLabel(ui.octaPushButton); + addBetaLabel(ui.triPushButton); + addBetaLabel(ui.y6PushButton);*/ + +} +void ApmFirmwareConfig::hideBetaLabels() +{ + for (int i=0;ihide(); + } + ui.warningLabel->hide(); +} + +void ApmFirmwareConfig::showBetaLabels() +{ + for (int i=0;ishow(); + } + ui.warningLabel->show(); +} + +void ApmFirmwareConfig::addBetaLabel(QWidget *parent) +{ + QLabel *label = new QLabel(parent); + QVBoxLayout *layout = new QVBoxLayout(); + parent->setLayout(layout); + label->setAlignment(Qt::AlignRight | Qt::AlignBottom); + label->setText("

BETA

"); + layout->addWidget(label); + m_betaButtonLabelList.append(label); +} + +void ApmFirmwareConfig::requestBetaFirmwares() +{ + m_betaFirmwareChecked = true; + showBetaLabels(); + QNetworkReply *reply1 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/beta/apm2-heli/git-version.txt"))); + QNetworkReply *reply2 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/beta/apm2-quad/git-version.txt"))); + QNetworkReply *reply3 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/beta/apm2-hexa/git-version.txt"))); + QNetworkReply *reply4 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/beta/apm2-octa/git-version.txt"))); + QNetworkReply *reply5 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/beta/apm2-octa-quad/git-version.txt"))); + QNetworkReply *reply6 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/beta/apm2-tri/git-version.txt"))); + QNetworkReply *reply7 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/beta/apm2-y6/git-version.txt"))); + QNetworkReply *reply8 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Plane/beta/apm2/git-version.txt"))); + QNetworkReply *reply9 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Rover/beta/apm2/git-version.txt"))); + + m_buttonToUrlMap[ui.roverPushButton] = "http://firmware.diydrones.com/Rover/beta/apm2/APMrover2.hex"; + m_buttonToUrlMap[ui.planePushButton] = "http://firmware.diydrones.com/Plane/beta/apm2/ArduPlane.hex"; + m_buttonToUrlMap[ui.copterPushButton] = "http://firmware.diydrones.com/Copter/beta/apm2-heli/ArduCopter.hex"; + m_buttonToUrlMap[ui.hexaPushButton] = "http://firmware.diydrones.com/Copter/beta/apm2-hexa/ArduCopter.hex"; + m_buttonToUrlMap[ui.octaQuadPushButton] = "http://firmware.diydrones.com/Copter/beta/apm2-octa-quad/ArduCopter.hex"; + m_buttonToUrlMap[ui.octaPushButton] = "http://firmware.diydrones.com/Copter/beta/apm2-octa/ArduCopter.hex"; + m_buttonToUrlMap[ui.quadPushButton] = "http://firmware.diydrones.com/Copter/beta/apm2-quad/ArduCopter.hex"; + m_buttonToUrlMap[ui.triPushButton] = "http://firmware.diydrones.com/Copter/beta/apm2-tri/ArduCopter.hex"; + m_buttonToUrlMap[ui.y6PushButton] = "http://firmware.diydrones.com/Copter/beta/apm2-y6/ArduCopter.hex"; + + //http://firmware.diydrones.com/Plane/stable/apm2/ArduPlane.hex + connect(reply1,SIGNAL(finished()),this,SLOT(firmwareListFinished())); + connect(reply1,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + connect(reply2,SIGNAL(finished()),this,SLOT(firmwareListFinished())); + connect(reply2,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + connect(reply3,SIGNAL(finished()),this,SLOT(firmwareListFinished())); + connect(reply3,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + connect(reply4,SIGNAL(finished()),this,SLOT(firmwareListFinished())); + connect(reply4,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + connect(reply5,SIGNAL(finished()),this,SLOT(firmwareListFinished())); + connect(reply5,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + connect(reply6,SIGNAL(finished()),this,SLOT(firmwareListFinished())); + connect(reply6,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + connect(reply7,SIGNAL(finished()),this,SLOT(firmwareListFinished())); + connect(reply7,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + connect(reply8,SIGNAL(finished()),this,SLOT(firmwareListFinished())); + connect(reply8,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + connect(reply9,SIGNAL(finished()),this,SLOT(firmwareListFinished())); + connect(reply9,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + qDebug() << "Getting Beta firmware..."; +} + +void ApmFirmwareConfig::requestFirmwares() +{ + m_betaFirmwareChecked = false; + hideBetaLabels(); + QNetworkReply *reply1 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/stable/apm2-heli/git-version.txt"))); + QNetworkReply *reply2 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/stable/apm2-quad/git-version.txt"))); + QNetworkReply *reply3 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/stable/apm2-hexa/git-version.txt"))); + QNetworkReply *reply4 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/stable/apm2-octa/git-version.txt"))); + QNetworkReply *reply5 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/stable/apm2-octa-quad/git-version.txt"))); + QNetworkReply *reply6 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/stable/apm2-tri/git-version.txt"))); + QNetworkReply *reply7 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/stable/apm2-y6/git-version.txt"))); + QNetworkReply *reply8 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Plane/stable/apm2/git-version.txt"))); + QNetworkReply *reply9 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Rover/stable/apm2/git-version.txt"))); + + m_buttonToUrlMap[ui.roverPushButton] = "http://firmware.diydrones.com/Rover/stable/apm2/APMrover2.hex"; + m_buttonToUrlMap[ui.planePushButton] = "http://firmware.diydrones.com/Plane/stable/apm2/ArduPlane.hex"; + m_buttonToUrlMap[ui.copterPushButton] = "http://firmware.diydrones.com/Copter/stable/apm2-heli/ArduCopter.hex"; + m_buttonToUrlMap[ui.hexaPushButton] = "http://firmware.diydrones.com/Copter/stable/apm2-hexa/ArduCopter.hex"; + m_buttonToUrlMap[ui.octaQuadPushButton] = "http://firmware.diydrones.com/Copter/stable/apm2-octa-quad/ArduCopter.hex"; + m_buttonToUrlMap[ui.octaPushButton] = "http://firmware.diydrones.com/Copter/stable/apm2-octa/ArduCopter.hex"; + m_buttonToUrlMap[ui.quadPushButton] = "http://firmware.diydrones.com/Copter/stable/apm2-quad/ArduCopter.hex"; + m_buttonToUrlMap[ui.triPushButton] = "http://firmware.diydrones.com/Copter/stable/apm2-tri/ArduCopter.hex"; + m_buttonToUrlMap[ui.y6PushButton] = "http://firmware.diydrones.com/Copter/stable/apm2-y6/ArduCopter.hex"; + + //http://firmware.diydrones.com/Plane/stable/apm2/ArduPlane.hex + connect(reply1,SIGNAL(finished()),this,SLOT(firmwareListFinished())); + connect(reply1,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + connect(reply2,SIGNAL(finished()),this,SLOT(firmwareListFinished())); + connect(reply2,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + connect(reply3,SIGNAL(finished()),this,SLOT(firmwareListFinished())); + connect(reply3,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + connect(reply4,SIGNAL(finished()),this,SLOT(firmwareListFinished())); + connect(reply4,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + connect(reply5,SIGNAL(finished()),this,SLOT(firmwareListFinished())); + connect(reply5,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + connect(reply6,SIGNAL(finished()),this,SLOT(firmwareListFinished())); + connect(reply6,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + connect(reply7,SIGNAL(finished()),this,SLOT(firmwareListFinished())); + connect(reply7,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + connect(reply8,SIGNAL(finished()),this,SLOT(firmwareListFinished())); + connect(reply8,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + connect(reply9,SIGNAL(finished()),this,SLOT(firmwareListFinished())); + connect(reply9,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + qDebug() << "Getting Stable firmware..."; +} + +void ApmFirmwareConfig::betaFirmwareButtonClicked(bool betafirmwareenabled) +{ + if (betafirmwareenabled) + { + ui.label->setText(tr("

Beta Firmware

")); + ui.betaFirmwareButton->setText(tr("Stable Firmware")); + requestBetaFirmwares(); + } + else + { + ui.label->setText(tr("

Firmware

")); + ui.betaFirmwareButton->setText(tr("Beta Firmware")); + requestFirmwares(); + } +} +void ApmFirmwareConfig::firmwareProcessFinished(int status) +{ + QProcess *proc = qobject_cast(sender()); + if (!proc) + { + return; + } + if (status != 0) + { + //Error of some kind + QMessageBox::information(0,tr("Error"),tr("An error has occured during the upload process. See window for details")); + ui.textBrowser->setVisible(true); + ui.showOutputCheckBox->setChecked(true); + ui.textBrowser->setPlainText(ui.textBrowser->toPlainText().append("\n\nERROR!!\n" + proc->errorString())); + QScrollBar *sb = ui.textBrowser->verticalScrollBar(); + if (sb) + { + sb->setValue(sb->maximum()); + } + ui.statusLabel->setText(tr("Error during upload")); + } + else + { + //Ensure we're reading 100% + ui.progressBar->setValue(100); + ui.statusLabel->setText(tr("Upload complete")); + } + //qDebug() << "Upload finished!" << QString::number(status); + m_tempFirmwareFile->deleteLater(); //This will remove the temporary file. + m_tempFirmwareFile = 0; + +} +void ApmFirmwareConfig::firmwareProcessReadyRead() +{ + QProcess *proc = qobject_cast(sender()); + if (!proc) + { + return; + } + QString output = proc->readAllStandardError() + proc->readAllStandardOutput(); + if (output.contains("Writing")) + { + //firmwareStatus->resetProgress(); + ui.progressBar->setValue(0); + } + else if (output.contains("Reading")) + { + ui.progressBar->setValue(50); + } + if (output.startsWith("#")) + { + ui.progressBar->setValue(ui.progressBar->value()+1); + + ui.textBrowser->setPlainText(ui.textBrowser->toPlainText().append(output)); + QScrollBar *sb = ui.textBrowser->verticalScrollBar(); + if (sb) + { + sb->setValue(sb->maximum()); + } + } + else + { + ui.textBrowser->setPlainText(ui.textBrowser->toPlainText().append(output + "\n")); + QScrollBar *sb = ui.textBrowser->verticalScrollBar(); + if (sb) + { + sb->setValue(sb->maximum()); + } + } + + qDebug() << "E:" << output; + //qDebug() << "AVR Output:" << proc->readAllStandardOutput(); + //qDebug() << "AVR Output:" << proc->readAllStandardError(); +} + +void ApmFirmwareConfig::downloadFinished() +{ + qDebug() << "Download finished, flashing firmware"; + QNetworkReply *reply = qobject_cast(sender()); + if (!reply) + { + return; + } + QByteArray hex = reply->readAll(); + m_tempFirmwareFile = new QTemporaryFile(); + m_tempFirmwareFile->open(); + m_tempFirmwareFile->write(hex); + m_tempFirmwareFile->flush(); + m_tempFirmwareFile->close(); + //tempfirmware.fileName() + QProcess *process = new QProcess(this); + connect(process,SIGNAL(finished(int)),this,SLOT(firmwareProcessFinished(int))); + connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(firmwareProcessReadyRead())); + connect(process,SIGNAL(readyReadStandardError()),this,SLOT(firmwareProcessReadyRead())); + connect(process,SIGNAL(error(QProcess::ProcessError)),this,SLOT(firmwareProcessError(QProcess::ProcessError))); + QList portList = QSerialPortInfo::availablePorts(); + + + foreach (const QSerialPortInfo &info, portList) + { + qDebug() << "PortName : " << info.portName() + << "Description : " << info.description(); + qDebug() << "Manufacturer: " << info.manufacturer(); + + + } + + //info.manufacturer() == "Arduino LLC (www.arduino.cc)" + //info.description() == "%mega2560.name%" + + qDebug() << "Attempting to reset port"; + + QSerialPort port; + + port.setPortName(m_detectedComPort); + port.open(QIODevice::ReadWrite); + port.setDataTerminalReady(true); + port.waitForBytesWritten(250); + port.setDataTerminalReady(false); + port.close(); + + QString avrdudeExecutable; + QStringList stringList; + + ui.statusLabel->setText(tr("Flashing")); +#ifdef Q_OS_WIN + stringList = QStringList() << "-Cavrdude/avrdude.conf" << "-pm2560" + << "-cstk500" << QString("-P").append(m_detectedComPort) + << QString("-Uflash:w:").append(m_tempFirmwareFile->fileName()).append(":i"); + + avrdudeExecutable = "avrdude/avrdude.exe"; +#endif +#ifdef Q_OS_MAC + stringList = QStringList() << "-v" << "-pm2560" + << "-cstk500" << QString("-P/dev/cu.").append(m_detectedComPort) + << QString("-Uflash:w:").append(m_tempFirmwareFile->fileName()).append(":i"); + avrdudeExecutable = "/usr/local/CrossPack-AVR/bin/avrdude"; +#endif + + // Start the Flashing + qDebug() << avrdudeExecutable << stringList; + process->start(avrdudeExecutable,stringList); +} +void ApmFirmwareConfig::firmwareProcessError(QProcess::ProcessError error) +{ + qDebug() << "Error:" << error; +} +void ApmFirmwareConfig::firmwareDownloadProgress(qint64 received,qint64 total) +{ + ui.progressBar->setValue( 100.0 * ((double)received/(double)total)); +} + +void ApmFirmwareConfig::flashButtonClicked() +{ + QPushButton *senderbtn = qobject_cast(sender()); + if (m_buttonToUrlMap.contains(senderbtn)) + { + bool foundconnected = false; + for (int i=0;igetLinks().size();i++) + { + if (LinkManager::instance()->getLinks()[i]->isConnected()) + { + //This is likely the serial link we want. + SerialLink *link = qobject_cast(LinkManager::instance()->getLinks()[i]); + if (!link) + { + qDebug() << "Eror, trying to program over a non serial link. This should not happen"; + return; + } + if (!(QMessageBox::question(this,tr("WARNING"),tr("You are about to upload new firmware to your board. This will disconnect you if you are currently connected. Be sure the MAV is on the ground, and connected over USB/Serial link.\n\nDo you wish to proceed?"),QMessageBox::Yes,QMessageBox::No) == QMessageBox::Yes)) + { + return; + } + + m_detectedComPort = link->getPortName(); + link->requestReset(); + foundconnected = true; + link->disconnect(); + link->wait(1000); // Wait 1 second for it to disconnect. + } + } + if (!foundconnected) + { + QMessageBox::information(0,tr("Error"),tr("You must be connected to a MAV over serial link to flash firmware. Please connect to a MAV then try again")); + return; + } + + qDebug() << "Go download:" << m_buttonToUrlMap[senderbtn]; + QNetworkReply *reply = m_networkManager->get(QNetworkRequest(QUrl(m_buttonToUrlMap[senderbtn]))); + //http://firmware.diydrones.com/Plane/stable/apm2/ArduPlane.hex + connect(reply,SIGNAL(finished()),this,SLOT(downloadFinished())); + + connect(reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); + connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(firmwareDownloadProgress(qint64,qint64))); + ui.statusLabel->setText("Downloading"); + } +} + +void ApmFirmwareConfig::firmwareListError(QNetworkReply::NetworkError error) +{ + QNetworkReply *reply = qobject_cast(sender()); + qDebug() << "Error!" << reply->errorString(); +} +bool ApmFirmwareConfig::stripVersionFromGitReply(QString url, QString reply,QString type,QString stable,QString *out) +{ + if (url.contains(type) && url.contains("git-version.txt") && url.contains(stable)) + { + QString version = reply.mid(reply.indexOf("APMVERSION:")+12).replace("\n","").replace("\r","").trimmed(); + *out = version; + return true; + } + return false; + +} + +void ApmFirmwareConfig::firmwareListFinished() +{ + QNetworkReply *reply = qobject_cast(sender()); + QString replystr = reply->readAll(); + QString outstr = ""; + if (stripVersionFromGitReply(reply->url().toString(),replystr,"apm2-heli",(m_betaFirmwareChecked ? "beta" : "stable"),&outstr)) + { + ui.copterLabel->setText((m_betaFirmwareChecked ? "BETA " : "") + outstr); + return; + } + if (stripVersionFromGitReply(reply->url().toString(),replystr,"apm2-quad",(m_betaFirmwareChecked ? "beta" : "stable"),&outstr)) + { + ui.quadLabel->setText((m_betaFirmwareChecked ? "BETA " : "") + outstr); + return; + } + if (stripVersionFromGitReply(reply->url().toString(),replystr,"apm2-hexa",(m_betaFirmwareChecked ? "beta" : "stable"),&outstr)) + { + ui.hexaLabel->setText((m_betaFirmwareChecked ? "BETA " : "") + outstr); + return; + } + if (stripVersionFromGitReply(reply->url().toString(),replystr,"apm2-octa-quad",(m_betaFirmwareChecked ? "beta" : "stable"),&outstr)) + { + ui.octaQuadLabel->setText((m_betaFirmwareChecked ? "BETA " : "") + outstr); + return; + } + if (stripVersionFromGitReply(reply->url().toString(),replystr,"apm2-octa",(m_betaFirmwareChecked ? "beta" : "stable"),&outstr)) + { + ui.octaLabel->setText((m_betaFirmwareChecked ? "BETA " : "") + outstr); + return; + } + if (stripVersionFromGitReply(reply->url().toString(),replystr,"apm2-tri",(m_betaFirmwareChecked ? "beta" : "stable"),&outstr)) + { + ui.triLabel->setText((m_betaFirmwareChecked ? "BETA " : "") + outstr); + return; + } + if (stripVersionFromGitReply(reply->url().toString(),replystr,"apm2-y6",(m_betaFirmwareChecked ? "beta" : "stable"),&outstr)) + { + ui.y6Label->setText((m_betaFirmwareChecked ? "BETA " : "") + outstr); + return; + } + if (stripVersionFromGitReply(reply->url().toString(),replystr,"Plane",(m_betaFirmwareChecked ? "beta" : "stable"),&outstr)) + { + ui.planeLabel->setText((m_betaFirmwareChecked ? "BETA " : "") + outstr); + return; + } + if (stripVersionFromGitReply(reply->url().toString(),replystr,"Rover",(m_betaFirmwareChecked ? "beta" : "stable"),&outstr)) + { + ui.roverLabel->setText((m_betaFirmwareChecked ? "BETA " : "") + outstr); + return; + } + //qDebug() << "Match not found for:" << reply->url(); + //qDebug() << "Git version line:" << replystr; +} + +ApmFirmwareConfig::~ApmFirmwareConfig() +{ +} diff --git a/src/ui/configuration/ApmFirmwareConfig.h b/src/ui/configuration/ApmFirmwareConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..07c1fa9b15a8553e1ea2fadf85b091ec55d3416b --- /dev/null +++ b/src/ui/configuration/ApmFirmwareConfig.h @@ -0,0 +1,66 @@ +#ifndef APMFIRMWARECONFIG_H +#define APMFIRMWARECONFIG_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qserialport.h" +#include "ui_ApmFirmwareConfig.h" + +class ApmFirmwareConfig : public QWidget +{ + Q_OBJECT + +public: + explicit ApmFirmwareConfig(QWidget *parent = 0); + ~ApmFirmwareConfig(); +private slots: + void firmwareListFinished(); + void firmwareListError(QNetworkReply::NetworkError error); + void flashButtonClicked(); + void betaFirmwareButtonClicked(bool betafirmwareenabled); + void downloadFinished(); + void firmwareProcessFinished(int status); + void firmwareProcessReadyRead(); + void firmwareProcessError(QProcess::ProcessError error); + void firmwareDownloadProgress(qint64 received,qint64 total); + void requestFirmwares(); + void requestBetaFirmwares(); +private: + void addBetaLabel(QWidget *parent); + void hideBetaLabels(); + void showBetaLabels(); + //ApmFirmwareStatus *firmwareStatus; + QString m_detectedComPort; + QTemporaryFile *m_tempFirmwareFile; + QNetworkAccessManager *m_networkManager; + QList m_betaButtonLabelList; + bool stripVersionFromGitReply(QString url,QString reply,QString type,QString stable,QString *out); + bool m_betaFirmwareChecked; + QMap m_buttonToUrlMap; + Ui::ApmFirmwareConfig ui; + class FirmwareDef + { + public: + QString url; + QString url2560; + QString url25602; + QString urlpx4; + QString type; + QString name; + QString desc; + int version; + }; + QList m_firmwareList; +}; + +#endif // APMFIRMWARECONFIG_H diff --git a/src/ui/configuration/ApmFirmwareConfig.ui b/src/ui/configuration/ApmFirmwareConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..4350d71e9c8ce8ccb33617e9695548f1125666a8 --- /dev/null +++ b/src/ui/configuration/ApmFirmwareConfig.ui @@ -0,0 +1,514 @@ + + + ApmFirmwareConfig + + + + 0 + 0 + 868 + 684 + + + + Form + + + + + 10 + 20 + 211 + 31 + + + + <h2>Firmware</h2> + + + + + + 30 + 60 + 801 + 371 + + + + + + + + + + 150 + 150 + + + + + 150 + 150 + + + + + + + + :/files/images/firmware/heli.png:/files/images/firmware/heli.png + + + + 150 + 150 + + + + + + + + ArduCopter vX.XX + + + Qt::AlignCenter + + + + + + + + + + + + 150 + 150 + + + + + 150 + 150 + + + + + + + + :/files/images/firmware/quadplus.png:/files/images/firmware/quadplus.png + + + + 150 + 150 + + + + + + + + ArduCopter vX.XX + + + Qt::AlignCenter + + + + + + + + + + + + 150 + 150 + + + + + 150 + 150 + + + + + + + + :/files/images/firmware/plane.png:/files/images/firmware/plane.png + + + + 150 + 150 + + + + + + + + ArduPlane vX.XX + + + Qt::AlignCenter + + + + + + + + + + + + 150 + 150 + + + + + 150 + 150 + + + + + + + + :/files/images/firmware/triy.png:/files/images/firmware/triy.png + + + + 150 + 150 + + + + + + + + ArduCopter vX.XX + + + Qt::AlignCenter + + + + + + + + + + + + 150 + 150 + + + + + 150 + 150 + + + + + + + + :/files/images/firmware/hexay.png:/files/images/firmware/hexay.png + + + + 150 + 150 + + + + + + + + ArduCopter vX.XX + + + Qt::AlignCenter + + + + + + + + + + + + 150 + 150 + + + + + 150 + 150 + + + + + + + + :/files/images/firmware/rover.png:/files/images/firmware/rover.png + + + + 150 + 150 + + + + + + + + ArduRover vX.XX + + + Qt::AlignCenter + + + + + + + + + + + + 150 + 150 + + + + + 150 + 150 + + + + + + + + :/files/images/firmware/octaplus.png:/files/images/firmware/octaplus.png + + + + 150 + 150 + + + + + + + + ArduCopter vX.XX + + + Qt::AlignCenter + + + + + + + + + + + + 150 + 150 + + + + + 150 + 150 + + + + + + + + :/files/images/firmware/octx.png:/files/images/firmware/octx.png + + + + 150 + 150 + + + + + + + + ArduCopter vX.XX + + + Qt::AlignCenter + + + + + + + + + + + + 150 + 150 + + + + + 150 + 150 + + + + + + + + :/files/images/firmware/hexaplus.png:/files/images/firmware/hexaplus.png + + + + 150 + 150 + + + + + + + + ArduCopter vX.XX + + + Qt::AlignCenter + + + + + + + + + + + 700 + 440 + 131 + 23 + + + + Beta firmware + + + true + + + false + + + + + + 30 + 490 + 801 + 23 + + + + 24 + + + + + + 30 + 520 + 801 + 151 + + + + + + + 710 + 470 + 101 + 17 + + + + Show Output + + + + + + 30 + 440 + 141 + 21 + + + + Status + + + + + + 180 + 440 + 491 + 16 + + + + <html><head/><body><p><span style=" font-size:large; font-weight:600; color:#e90000;">WARNING:</span><span style=" font-size:large; font-weight:600; color:#ffaa00;"> Only install BETA firmware if you are an experienced tester.</span></p></body></html> + + + + + + + + diff --git a/src/ui/configuration/ApmHardwareConfig.cc b/src/ui/configuration/ApmHardwareConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..f576e6fa07ae9013016295f0e4ee8260036b4458 --- /dev/null +++ b/src/ui/configuration/ApmHardwareConfig.cc @@ -0,0 +1,187 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2013 Michael Carpenter (malcom2073@gmail.com) + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL 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 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief APM Hardware Configuration widget source. + * + * @author Michael Carpenter + * + */ +#include "ApmHardwareConfig.h" + +ApmHardwareConfig::ApmHardwareConfig(QWidget *parent) : QWidget(parent) +{ + ui.setupUi(this); + + + ui.manditoryHardware->setVisible(false); + ui.frameTypeButton->setVisible(false); + ui.compassButton->setVisible(false); + ui.accelCalibrateButton->setVisible(false); + ui.arduPlaneLevelButton->setVisible(false); + ui.radioCalibrateButton->setVisible(false); + ui.optionalHardwareButton->setVisible(false); + ui.batteryMonitorButton->setVisible(false); + ui.sonarButton->setVisible(false); + ui.airspeedButton->setVisible(false); + ui.opticalFlowButton->setVisible(false); + ui.osdButton->setVisible(false); + ui.cameraGimbalButton->setVisible(false); + + connect(ui.optionalHardwareButton,SIGNAL(toggled(bool)),ui.radio3DRButton,SLOT(setShown(bool))); + connect(ui.optionalHardwareButton,SIGNAL(toggled(bool)),ui.batteryMonitorButton,SLOT(setShown(bool))); + connect(ui.optionalHardwareButton,SIGNAL(toggled(bool)),ui.sonarButton,SLOT(setShown(bool))); + connect(ui.optionalHardwareButton,SIGNAL(toggled(bool)),ui.opticalFlowButton,SLOT(setShown(bool))); + connect(ui.optionalHardwareButton,SIGNAL(toggled(bool)),ui.osdButton,SLOT(setShown(bool))); + connect(ui.optionalHardwareButton,SIGNAL(toggled(bool)),ui.cameraGimbalButton,SLOT(setShown(bool))); + connect(ui.optionalHardwareButton,SIGNAL(toggled(bool)),ui.antennaTrackerButton,SLOT(setShown(bool))); + + connect(ui.frameTypeButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + + m_apmFirmwareConfig = new ApmFirmwareConfig(this); + ui.stackedWidget->addWidget(m_apmFirmwareConfig); //Firmware placeholder. + m_buttonToConfigWidgetMap[ui.firmwareButton] = m_apmFirmwareConfig; + connect(ui.firmwareButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_frameConfig = new FrameTypeConfig(this); + ui.stackedWidget->addWidget(m_frameConfig); + m_buttonToConfigWidgetMap[ui.frameTypeButton] = m_frameConfig; + connect(ui.frameTypeButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_compassConfig = new CompassConfig(this); + ui.stackedWidget->addWidget(m_compassConfig); + m_buttonToConfigWidgetMap[ui.compassButton] = m_compassConfig; + connect(ui.compassButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_accelConfig = new AccelCalibrationConfig(this); + ui.stackedWidget->addWidget(m_accelConfig); + m_buttonToConfigWidgetMap[ui.accelCalibrateButton] = m_accelConfig; + connect(ui.accelCalibrateButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_planeLevel = new ApmPlaneLevel(this); + ui.stackedWidget->addWidget(m_planeLevel); + m_buttonToConfigWidgetMap[ui.arduPlaneLevelButton] = m_planeLevel; + connect(ui.arduPlaneLevelButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_radioConfig = new RadioCalibrationConfig(this); + ui.stackedWidget->addWidget(m_radioConfig); + m_buttonToConfigWidgetMap[ui.radioCalibrateButton] = m_radioConfig; + connect(ui.radioCalibrateButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + + m_radio3drConfig = new Radio3DRConfig(this); + ui.stackedWidget->addWidget(m_radio3drConfig); + m_buttonToConfigWidgetMap[ui.radio3DRButton] = m_radio3drConfig; + connect(ui.radio3DRButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_batteryConfig = new BatteryMonitorConfig(this); + ui.stackedWidget->addWidget(m_batteryConfig); + m_buttonToConfigWidgetMap[ui.batteryMonitorButton] = m_batteryConfig; + connect(ui.batteryMonitorButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_sonarConfig = new SonarConfig(this); + ui.stackedWidget->addWidget(m_sonarConfig); + m_buttonToConfigWidgetMap[ui.sonarButton] = m_sonarConfig; + connect(ui.sonarButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_airspeedConfig = new AirspeedConfig(this); + ui.stackedWidget->addWidget(m_airspeedConfig); + m_buttonToConfigWidgetMap[ui.airspeedButton] = m_airspeedConfig; + connect(ui.airspeedButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_opticalFlowConfig = new OpticalFlowConfig(this); + ui.stackedWidget->addWidget(m_opticalFlowConfig); + m_buttonToConfigWidgetMap[ui.opticalFlowButton] = m_opticalFlowConfig; + connect(ui.opticalFlowButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_osdConfig = new OsdConfig(this); + ui.stackedWidget->addWidget(m_osdConfig); + m_buttonToConfigWidgetMap[ui.osdButton] = m_osdConfig; + connect(ui.osdButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_cameraGimbalConfig = new CameraGimbalConfig(this); + ui.stackedWidget->addWidget(m_cameraGimbalConfig); + m_buttonToConfigWidgetMap[ui.cameraGimbalButton] = m_cameraGimbalConfig; + connect(ui.cameraGimbalButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_antennaTrackerConfig = new AntennaTrackerConfig(this); + ui.stackedWidget->addWidget(m_antennaTrackerConfig); + m_buttonToConfigWidgetMap[ui.antennaTrackerButton] = m_antennaTrackerConfig; + connect(ui.antennaTrackerButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + connect(UASManager::instance(),SIGNAL(activeUASSet(UASInterface*)),this,SLOT(activeUASSet(UASInterface*))); + if (UASManager::instance()->getActiveUAS()) + { + activeUASSet(UASManager::instance()->getActiveUAS()); + } +} +void ApmHardwareConfig::activateStackedWidget() +{ + if (m_buttonToConfigWidgetMap.contains(sender())) + { + ui.stackedWidget->setCurrentWidget(m_buttonToConfigWidgetMap[sender()]); + } +} + +ApmHardwareConfig::~ApmHardwareConfig() +{ +} + +void ApmHardwareConfig::activeUASSet(UASInterface *uas) +{ + if (!uas) + { + return; + } + if (uas->getSystemType() == MAV_TYPE_FIXED_WING) + { + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.compassButton,SLOT(setShown(bool))); + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.arduPlaneLevelButton,SLOT(setShown(bool))); + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.radioCalibrateButton,SLOT(setShown(bool))); + connect(ui.optionalHardwareButton,SIGNAL(toggled(bool)),ui.airspeedButton,SLOT(setShown(bool))); + } + else if (uas->getSystemType() == MAV_TYPE_QUADROTOR) + { + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.frameTypeButton,SLOT(setShown(bool))); + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.compassButton,SLOT(setShown(bool))); + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.accelCalibrateButton,SLOT(setShown(bool))); + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.radioCalibrateButton,SLOT(setShown(bool))); + } + else if (uas->getSystemType() == MAV_TYPE_GROUND_ROVER) + { + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.compassButton,SLOT(setShown(bool))); + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.radioCalibrateButton,SLOT(setShown(bool))); + } + else + { + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.compassButton,SLOT(setShown(bool))); + connect(ui.manditoryHardware,SIGNAL(toggled(bool)),ui.radioCalibrateButton,SLOT(setShown(bool))); + } + ui.firmwareButton->setVisible(true); + ui.manditoryHardware->setVisible(true); + ui.manditoryHardware->setChecked(true); + ui.optionalHardwareButton->setVisible(true); + ui.optionalHardwareButton->setChecked(true); +} diff --git a/src/ui/configuration/ApmHardwareConfig.h b/src/ui/configuration/ApmHardwareConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..427403b6d9ac8c1b35f8d6ea29b193503ae4bc48 --- /dev/null +++ b/src/ui/configuration/ApmHardwareConfig.h @@ -0,0 +1,88 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2013 Michael Carpenter (malcom2073@gmail.com) + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL 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 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief APM Hardware Configuration widget header. + * + * @author Michael Carpenter + * + */ + +#ifndef APMHARDWARECONFIG_H +#define APMHARDWARECONFIG_H + +#include +#include "ui_ApmHardwareConfig.h" +#include +#include +#include "FrameTypeConfig.h" +#include "CompassConfig.h" +#include "AccelCalibrationConfig.h" +#include "RadioCalibrationConfig.h" +#include "Radio3DRConfig.h" +#include "BatteryMonitorConfig.h" +#include "SonarConfig.h" +#include "AirspeedConfig.h" +#include "OpticalFlowConfig.h" +#include "OsdConfig.h" +#include "CameraGimbalConfig.h" +#include "AntennaTrackerConfig.h" +#include "ApmPlaneLevel.h" +#include "ApmFirmwareConfig.h" + +class ApmHardwareConfig : public QWidget +{ + Q_OBJECT + +public: + explicit ApmHardwareConfig(QWidget *parent = 0); + ~ApmHardwareConfig(); +private: + QPointer m_frameConfig; + QPointer m_compassConfig; + QPointer m_accelConfig; + QPointer m_radioConfig; + + QPointer m_apmFirmwareConfig; + QPointer m_radio3drConfig; + QPointer m_batteryConfig; + QPointer m_sonarConfig; + QPointer m_airspeedConfig; + QPointer m_opticalFlowConfig; + QPointer m_osdConfig; + QPointer m_cameraGimbalConfig; + QPointer m_antennaTrackerConfig; + QPointer m_planeLevel; + +private slots: + void activeUASSet(UASInterface *uas); + void activateStackedWidget(); +private: + Ui::ApmHardwareConfig ui; + + //This is a map between the buttons, and the widgets they should be displying + QMap m_buttonToConfigWidgetMap; +}; + +#endif // APMHARDWARECONFIG_H diff --git a/src/ui/configuration/ApmHardwareConfig.ui b/src/ui/configuration/ApmHardwareConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..e4a711b060d08d3c1cb58b395d54e9341587cb41 --- /dev/null +++ b/src/ui/configuration/ApmHardwareConfig.ui @@ -0,0 +1,330 @@ + + + ApmHardwareConfig + + + + 0 + 0 + 1225 + 827 + + + + Form + + + + + 0 + 20 + 175 + 531 + + + + + 175 + 0 + + + + + 175 + 16777215 + + + + true + + + + + 0 + 0 + 156 + 676 + + + + + + + QLayout::SetMinAndMaxSize + + + + + + 100 + 35 + + + + Install Firmware + + + + + + + + 0 + 35 + + + + >>> Manditory Hardware + + + true + + + + + + + + 0 + 35 + + + + Qt::LeftToRight + + + Frame Type + + + + + + + + 0 + 35 + + + + Compass + + + + + + + + 0 + 35 + + + + Qt::LeftToRight + + + false + + + Accel Calibration + + + + + + + + 0 + 35 + + + + Qt::LeftToRight + + + false + + + ArduPlane Level + + + + + + + + 100 + 35 + + + + + 16777215 + 16777215 + + + + Radio Calibration + + + false + + + false + + + + + + + + 0 + 35 + + + + >>> Optional Hardware + + + true + + + + + + + + 0 + 35 + + + + 3DR Radio + + + + + + + + 0 + 35 + + + + Battery Monitor + + + + + + + + 0 + 35 + + + + Sonar + + + + + + + + 0 + 35 + + + + Airspeed + + + + + + + + 0 + 35 + + + + Optical Flow + + + + + + + + 0 + 35 + + + + OSD + + + + + + + + 0 + 35 + + + + Camera Gimbal + + + + + + + + 0 + 35 + + + + Antenna Tracker + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + 200 + 30 + 921 + 761 + + + + -1 + + + + + + diff --git a/src/ui/configuration/ApmHighlighter.cc b/src/ui/configuration/ApmHighlighter.cc new file mode 100644 index 0000000000000000000000000000000000000000..8e09ac6f0e3d75a7a8e0ee919cdc50681e39c12e --- /dev/null +++ b/src/ui/configuration/ApmHighlighter.cc @@ -0,0 +1,53 @@ +/*===================================================================== + +APM_PLANNER Open Source Ground Control Station + +(c) 2013, Bill Bonney + +This file is part of the APM_PLANNER project + + APM_PLANNER 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 3 of the License, or + (at your option) any later version. + + APM_PLANNER 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 APM_PLANNER. If not, see . + +======================================================================*/ + +/** + * @file + * @brief APM Highligther for ArduPilot Console. + * + * @author Bill Bonney + * + */ + +#include "ApmHighlighter.h" + +APMHighlighter::APMHighlighter(QObject *parent) : + QSyntaxHighlighter(parent) +{ +} + +void APMHighlighter::highlightBlock(const QString &text) + { + QTextCharFormat myClassFormat; + myClassFormat.setFontWeight(QFont::Bold); + myClassFormat.setForeground(Qt::darkMagenta); + QString pattern = "^\\Ardu[A-Za-z]+\\b"; + + QRegExp expression(pattern); + int index = text.indexOf(expression); + while (index >= 0) { + int length = expression.matchedLength(); + setFormat(index, length, myClassFormat); + index = text.indexOf(expression, index + length); + } + } diff --git a/src/ui/configuration/ApmHighlighter.h b/src/ui/configuration/ApmHighlighter.h new file mode 100644 index 0000000000000000000000000000000000000000..e4f9b645f129995ff257bb3cf36d13b6c888abd4 --- /dev/null +++ b/src/ui/configuration/ApmHighlighter.h @@ -0,0 +1,51 @@ +/*===================================================================== + +APM_PLANNER Open Source Ground Control Station + +(c) 2013, Bill Bonney + +This file is part of the APM_PLANNER project + + APM_PLANNER 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 3 of the License, or + (at your option) any later version. + + APM_PLANNER 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 APM_PLANNER. If not, see . + +======================================================================*/ + +/** + * @file + * @brief APM Highligther for ArduPilot Console. + * + * @author Bill Bonney + * + */ + +#ifndef APMHIGHLIGHTER_H +#define APMHIGHLIGHTER_H + +#include "ApmHighlighter.h" +#include + +class APMHighlighter : public QSyntaxHighlighter +{ + Q_OBJECT +public: + explicit APMHighlighter(QObject *parent = 0); + void highlightBlock(const QString &text); + +signals: + +public slots: + +}; + +#endif // APMHIGHLIGHTER_H diff --git a/src/ui/configuration/ApmPlaneLevel.cc b/src/ui/configuration/ApmPlaneLevel.cc new file mode 100644 index 0000000000000000000000000000000000000000..49b1b20f5e1811f3744f6b73037f17a236251dd5 --- /dev/null +++ b/src/ui/configuration/ApmPlaneLevel.cc @@ -0,0 +1,66 @@ +#include "ApmPlaneLevel.h" +#include + +ApmPlaneLevel::ApmPlaneLevel(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + connect(ui.levelPushButton,SIGNAL(clicked()),this,SLOT(levelClicked())); + connect(ui.manualLevelCheckBox,SIGNAL(toggled(bool)),this,SLOT(manualCheckBoxToggled(bool))); + initConnections(); +} + +ApmPlaneLevel::~ApmPlaneLevel() +{ +} +void ApmPlaneLevel::levelClicked() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + QMessageBox::information(0,"Warning","Be sure the plane is completly level, then click ok"); + MAV_CMD command = MAV_CMD_PREFLIGHT_CALIBRATION; + int confirm = 0; + float param1 = 1.0; + float param2 = 0.0; + float param3 = 1.0; + float param4 = 0.0; + float param5 = 0.0; + float param6 = 0.0; + float param7 = 0.0; + int component = 1; + m_uas->executeCommand(command, confirm, param1, param2, param3, param4, param5, param6, param7, component); + QMessageBox::information(0,"Warning","Leveling completed"); +} + +void ApmPlaneLevel::manualCheckBoxToggled(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (checked) + { + m_uas->getParamManager()->setParameter(1,"MANUAL_LEVEL",1); + } + else + { + m_uas->getParamManager()->setParameter(1,"MANUAL_LEVEL",0); + } +} +void ApmPlaneLevel::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (parameterName == "MANUAL_LEVEL") + { + if (value.toInt() == 1) + { + ui.manualLevelCheckBox->setChecked(true); + } + else + { + ui.manualLevelCheckBox->setChecked(false); + } + } +} diff --git a/src/ui/configuration/ApmPlaneLevel.h b/src/ui/configuration/ApmPlaneLevel.h new file mode 100644 index 0000000000000000000000000000000000000000..a6a38078f3704b10a283126fc84a6aebfe8738bd --- /dev/null +++ b/src/ui/configuration/ApmPlaneLevel.h @@ -0,0 +1,23 @@ +#ifndef APMPLANELEVEL_H +#define APMPLANELEVEL_H + +#include +#include "ui_ApmPlaneLevel.h" +#include "AP2ConfigWidget.h" + +class ApmPlaneLevel : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit ApmPlaneLevel(QWidget *parent = 0); + ~ApmPlaneLevel(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void levelClicked(); + void manualCheckBoxToggled(bool checked); +private: + Ui::ApmPlaneLevel ui; +}; + +#endif // APMPLANELEVEL_H diff --git a/src/ui/configuration/ApmPlaneLevel.ui b/src/ui/configuration/ApmPlaneLevel.ui new file mode 100644 index 0000000000000000000000000000000000000000..ef22b19992f262acf776e84fbfca097e2074c997 --- /dev/null +++ b/src/ui/configuration/ApmPlaneLevel.ui @@ -0,0 +1,99 @@ + + + ApmPlaneLevel + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + 10 + 10 + 141 + 31 + + + + <h2>ArduPlane Level</h2> + + + + + + 50 + 70 + 271 + 41 + + + + By Default your plane will autolevel on every boot. +To disable this action you need to turn on manual +level and perform a level to calibrate the accel offsets. + + + + + + 50 + 150 + 291 + 16 + + + + Level your plane and click Level to set default accel offsets + + + + + + 160 + 180 + 75 + 23 + + + + Level + + + + + + 120 + 230 + 151 + 51 + + + + For advanced users ONLY + + + + + 30 + 20 + 91 + 17 + + + + Manual Level + + + + + + + diff --git a/src/ui/configuration/ApmSoftwareConfig.cc b/src/ui/configuration/ApmSoftwareConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..a5308dab76eeeb3c8080336a93e99a012d2679a0 --- /dev/null +++ b/src/ui/configuration/ApmSoftwareConfig.cc @@ -0,0 +1,368 @@ +#include +#include +#include + +#include "ApmSoftwareConfig.h" + + +ApmSoftwareConfig::ApmSoftwareConfig(QWidget *parent) : QWidget(parent) +{ + ui.setupUi(this); + + ui.flightModesButton->setVisible(false); + ui.standardParamButton->setVisible(false); + ui.failSafeButton->setVisible(false); + ui.advancedParamButton->setVisible(false); + ui.advParamListButton->setVisible(false); + ui.arduCopterPidButton->setVisible(false); + ui.arduRoverPidButton->setVisible(false); + ui.arduPlanePidButton->setVisible(false); + + m_flightConfig = new FlightModeConfig(this); + ui.stackedWidget->addWidget(m_flightConfig); + m_buttonToConfigWidgetMap[ui.flightModesButton] = m_flightConfig; + connect(ui.flightModesButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_standardParamConfig = new StandardParamConfig(this); + ui.stackedWidget->addWidget(m_standardParamConfig); + m_buttonToConfigWidgetMap[ui.standardParamButton] = m_standardParamConfig; + connect(ui.standardParamButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_failSafeConfig = new FailSafeConfig(this); + ui.stackedWidget->addWidget(m_failSafeConfig); + m_buttonToConfigWidgetMap[ui.failSafeButton] = m_failSafeConfig; + connect(ui.failSafeButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_advancedParamConfig = new AdvancedParamConfig(this); + ui.stackedWidget->addWidget(m_advancedParamConfig); + m_buttonToConfigWidgetMap[ui.advancedParamButton] = m_advancedParamConfig; + connect(ui.advancedParamButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_advParameterList = new AdvParameterList(this); + ui.stackedWidget->addWidget(m_advParameterList); + m_buttonToConfigWidgetMap[ui.advParamListButton] = m_advParameterList; + connect(ui.advParamListButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_arduCopterPidConfig = new ArduCopterPidConfig(this); + ui.stackedWidget->addWidget(m_arduCopterPidConfig); + m_buttonToConfigWidgetMap[ui.arduCopterPidButton] = m_arduCopterPidConfig; + connect(ui.arduCopterPidButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_arduPlanePidConfig = new ArduPlanePidConfig(this); + ui.stackedWidget->addWidget(m_arduPlanePidConfig); + m_buttonToConfigWidgetMap[ui.arduPlanePidButton] = m_arduPlanePidConfig; + connect(ui.arduPlanePidButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + m_arduRoverPidConfig = new ArduRoverPidConfig(this); + ui.stackedWidget->addWidget(m_arduRoverPidConfig); + m_buttonToConfigWidgetMap[ui.arduRoverPidButton] = m_arduRoverPidConfig; + connect(ui.arduRoverPidButton,SIGNAL(clicked()),this,SLOT(activateStackedWidget())); + + connect(UASManager::instance(),SIGNAL(activeUASSet(UASInterface*)),this,SLOT(activeUASSet(UASInterface*))); + activeUASSet(UASManager::instance()->getActiveUAS()); +} + +ApmSoftwareConfig::~ApmSoftwareConfig() +{ +} +void ApmSoftwareConfig::activateStackedWidget() +{ + if (m_buttonToConfigWidgetMap.contains(sender())) + { + ui.stackedWidget->setCurrentWidget(m_buttonToConfigWidgetMap[sender()]); + } +} +void ApmSoftwareConfig::activeUASSet(UASInterface *uas) +{ + if (!uas) + { + return; + } + + ui.flightModesButton->setVisible(true); + ui.standardParamButton->setVisible(true); + ui.failSafeButton->setVisible(true); + ui.advancedParamButton->setVisible(true); + ui.advParamListButton->setVisible(true); + + QString compare = ""; + if (uas->getSystemType() == MAV_TYPE_FIXED_WING) + { + ui.arduPlanePidButton->setVisible(true); + ui.arduCopterPidButton->setVisible(false); + ui.arduRoverPidButton->setVisible(false); + compare = "ArduPlane"; + } + else if (uas->getSystemType() == MAV_TYPE_QUADROTOR) + { + ui.arduCopterPidButton->setVisible(true); + ui.arduPlanePidButton->setVisible(false); + ui.arduRoverPidButton->setVisible(false); + compare = "ArduCopter"; + } + else if (uas->getSystemType() == MAV_TYPE_GROUND_ROVER) + { + ui.arduRoverPidButton->setVisible(true); + ui.arduCopterPidButton->setVisible(false); + ui.arduPlanePidButton->setVisible(false); + compare = "APMRover2"; + } + + + QDir autopilotdir(qApp->applicationDirPath() + "/files/" + uas->getAutopilotTypeName().toLower()); + QFile xmlfile(autopilotdir.absolutePath() + "/arduplane.pdef.xml"); + if (xmlfile.exists() && !xmlfile.open(QIODevice::ReadOnly)) + { + return; + } + + QXmlStreamReader xml(xmlfile.readAll()); + xmlfile.close(); + + //TODO: Testing to ensure that incorrectly formated XML won't break this. + //Also, move this into the Param Manager, as it should handle all metadata. + while (!xml.atEnd()) + { + if (xml.isStartElement() && xml.name() == "paramfile") + { + xml.readNext(); + while ((xml.name() != "paramfile") && !xml.atEnd()) + { + QString valuetype = ""; + if (xml.isStartElement() && (xml.name() == "vehicles" || xml.name() == "libraries")) //Enter into the vehicles loop + { + valuetype = xml.name().toString(); + xml.readNext(); + while ((xml.name() != valuetype) && !xml.atEnd()) + { + if (xml.isStartElement() && xml.name() == "parameters") //This is a parameter block + { + QString parametersname = ""; + if (xml.attributes().hasAttribute("name")) + { + parametersname = xml.attributes().value("name").toString(); + } + + QVariantMap genset; + QVariantMap advset; + + QString setname = parametersname; + xml.readNext(); + int genarraycount = 0; + int advarraycount = 0; + while ((xml.name() != "parameters") && !xml.atEnd()) + { + if (xml.isStartElement() && xml.name() == "param") + { + QString humanname = xml.attributes().value("humanName").toString(); + QString name = xml.attributes().value("name").toString(); + QString tab= xml.attributes().value("user").toString(); + if (tab == "Advanced") + { + advset["title"] = parametersname; + } + else + { + genset["title"] = parametersname; + } + if (name.contains(":")) + { + name = name.split(":")[1]; + } + QString docs = xml.attributes().value("documentation").toString(); + //paramTooltips[name] = name + " - " + docs; + + int type = -1; //Type of item + QMap fieldmap; + QMap valuemap; + xml.readNext(); + while ((xml.name() != "param") && !xml.atEnd()) + { + if (xml.isStartElement() && xml.name() == "values") + { + type = 1; //1 is a combobox + if (tab == "Advanced") + { + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "TYPE"] = "COMBO"; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_COMBOBOX_DESCRIPTION"] = humanname; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_COMBOBOX_PARAMID"] = name; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_COMBOBOX_COMPONENTID"] = 1; + } + else + { + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "TYPE"] = "COMBO"; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_COMBOBOX_DESCRIPTION"] = humanname; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_COMBOBOX_PARAMID"] = name; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_COMBOBOX_COMPONENTID"] = 1; + } + int paramcount = 0; + xml.readNext(); + while ((xml.name() != "values") && !xml.atEnd()) + { + if (xml.isStartElement() && xml.name() == "value") + { + + QString code = xml.attributes().value("code").toString(); + QString arg = xml.readElementText(); + valuemap[code] = arg; + if (tab == "Advanced") + { + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_COMBOBOX_ITEM_" + QString::number(paramcount) + "_TEXT"] = arg; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_COMBOBOX_ITEM_" + QString::number(paramcount) + "_VAL"] = code.toInt(); + } + else + { + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_COMBOBOX_ITEM_" + QString::number(paramcount) + "_TEXT"] = arg; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_COMBOBOX_ITEM_" + QString::number(paramcount) + "_VAL"] = code.toInt(); + } + paramcount++; + } + xml.readNext(); + } + if (tab == "Advanced") + { + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_COMBOBOX_COUNT"] = paramcount; + } + else + { + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_COMBOBOX_COUNT"] = paramcount; + } + } + if (xml.isStartElement() && xml.name() == "field") + { + type = 2; //2 is a slider + QString fieldtype = xml.attributes().value("name").toString(); + QString text = xml.readElementText(); + fieldmap[fieldtype] = text; + } + xml.readNext(); + } + if (type == -1) + { + //Nothing inside! Assume it's a value, give it a default range. + type = 2; + QString fieldtype = "Range"; + QString text = "0 100"; //TODO: Determine a better way of figuring out default ranges. + fieldmap[fieldtype] = text; + } + if (type == 2) + { + if (tab == "Advanced") + { + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "TYPE"] = "SLIDER"; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_SLIDER_DESCRIPTION"] = humanname; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_SLIDER_PARAMID"] = name; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_SLIDER_COMPONENTID"] = 1; + } + else + { + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "TYPE"] = "SLIDER"; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_SLIDER_DESCRIPTION"] = humanname; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_SLIDER_PARAMID"] = name; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_SLIDER_COMPONENTID"] = 1; + } + if (fieldmap.contains("Range")) + { + float min = 0; + float max = 0; + //Some range fields list "0-10" and some list "0 10". Handle both. + if (fieldmap["Range"].split(" ").size() > 1) + { + min = fieldmap["Range"].split(" ")[0].trimmed().toFloat(); + max = fieldmap["Range"].split(" ")[1].trimmed().toFloat(); + } + else if (fieldmap["Range"].split("-").size() > 1) + { + min = fieldmap["Range"].split("-")[0].trimmed().toFloat(); + max = fieldmap["Range"].split("-")[1].trimmed().toFloat(); + } + if (tab == "Advanced") + { + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_SLIDER_MIN"] = min; + advset[setname + "\\" + QString::number(advarraycount) + "\\" + "QGC_PARAM_SLIDER_MAX"] = max; + } + else + { + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_SLIDER_MIN"] = min; + genset[setname + "\\" + QString::number(genarraycount) + "\\" + "QGC_PARAM_SLIDER_MAX"] = max; + } + } + } + if (tab == "Advanced") + { + advarraycount++; + advset["count"] = advarraycount; + } + else + { + genarraycount++; + genset["count"] = genarraycount; + } + //Right here we have a single param in memory + if (valuemap.size() > 0) + { + QList > valuelist; + for (QMap::const_iterator i = valuemap.constBegin();i!=valuemap.constEnd();i++) + { + valuelist.append(QPair(i.key().toInt(),i.value())); + } + if (compare == parametersname) + { + if (tab == "Standard") + { + m_standardParamConfig->addCombo(humanname,docs,name,valuelist); + } + else if (tab == "Advanced") + { + m_advancedParamConfig->addCombo(humanname,docs,name,valuelist); + } + m_advParameterList->setParameterMetaData(name,humanname,docs); + } + } + else if (fieldmap.size() > 0) + { + float min = 0; + float max = 65535; + if (fieldmap.contains("Range")) + { + //Some range fields list "0-10" and some list "0 10". Handle both. + if (fieldmap["Range"].split(" ").size() > 1) + { + min = fieldmap["Range"].split(" ")[0].trimmed().toFloat(); + max = fieldmap["Range"].split(" ")[1].trimmed().toFloat(); + } + else if (fieldmap["Range"].split("-").size() > 1) + { + min = fieldmap["Range"].split("-")[0].trimmed().toFloat(); + max = fieldmap["Range"].split("-")[1].trimmed().toFloat(); + } + } + if (compare == parametersname) + { + if (tab == "Standard") + { + m_standardParamConfig->addRange(humanname,docs,name,min,max); + } + else if (tab == "Advanced") + { + m_advancedParamConfig->addRange(humanname,docs,name,min,max); + } + m_advParameterList->setParameterMetaData(name,humanname,docs); + } + } + + } + xml.readNext(); + } + } + xml.readNext(); + } + + } + xml.readNext(); + } + } + xml.readNext(); + } + +} diff --git a/src/ui/configuration/ApmSoftwareConfig.h b/src/ui/configuration/ApmSoftwareConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..77b97d0822c16eb72842b586ea06fa9c5a191c8a --- /dev/null +++ b/src/ui/configuration/ApmSoftwareConfig.h @@ -0,0 +1,44 @@ +#ifndef APMSOFTWARECONFIG_H +#define APMSOFTWARECONFIG_H + +#include +#include "ui_ApmSoftwareConfig.h" +#include "FlightModeConfig.h" +#include "BasicPidConfig.h" +#include "StandardParamConfig.h" +#include "GeoFenceConfig.h" +#include "FailSafeConfig.h" +#include "AdvancedParamConfig.h" +#include "ArduCopterPidConfig.h" +#include "ArduPlanePidConfig.h" +#include "ArduRoverPidConfig.h" +#include "AdvParameterList.h" +#include "UASInterface.h" +#include "UASManager.h" + +class ApmSoftwareConfig : public QWidget +{ + Q_OBJECT + +public: + explicit ApmSoftwareConfig(QWidget *parent = 0); + ~ApmSoftwareConfig(); +private slots: + void activateStackedWidget(); + void activeUASSet(UASInterface *uas); +private: + Ui::ApmSoftwareConfig ui; + QPointer m_basicPidConfig; + QPointer m_flightConfig; + QPointer m_standardParamConfig; + QPointer m_geoFenceConfig; + QPointer m_failSafeConfig; + QPointer m_advancedParamConfig; + QPointer m_arduCopterPidConfig; + QPointer m_arduPlanePidConfig; + QPointer m_arduRoverPidConfig; + QPointer m_advParameterList; + QMap m_buttonToConfigWidgetMap; +}; + +#endif // APMSOFTWARECONFIG_H diff --git a/src/ui/configuration/ApmSoftwareConfig.ui b/src/ui/configuration/ApmSoftwareConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..d3deec752896dd3f463a9e1fe4df8d2e1005d891 --- /dev/null +++ b/src/ui/configuration/ApmSoftwareConfig.ui @@ -0,0 +1,210 @@ + + + ApmSoftwareConfig + + + + 0 + 0 + 853 + 619 + + + + Form + + + + + + + 175 + 0 + + + + + 175 + 16777215 + + + + true + + + + + 0 + 0 + 173 + 599 + + + + + + + QLayout::SetMinAndMaxSize + + + + + + 100 + 35 + + + + qgroundcontrol 2.0 Config + + + + + + + + 0 + 35 + + + + Flight Modes + + + false + + + + + + + + 0 + 35 + + + + Standard Params + + + false + + + + + + + + 0 + 35 + + + + FailSafe + + + false + + + + + + + + 0 + 35 + + + + Advanced Params + + + false + + + + + + + + 0 + 35 + + + + Full Parameter List + + + false + + + + + + + + 0 + 35 + + + + ArduCopter Pids + + + false + + + + + + + + 0 + 35 + + + + ArduPlane Pids + + + + + + + + 0 + 35 + + + + ArduRover Pids + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + + + diff --git a/src/ui/configuration/ArduCopterPidConfig.cc b/src/ui/configuration/ArduCopterPidConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..7d5f274cbd4b8822e3ee09c64df79230148271da --- /dev/null +++ b/src/ui/configuration/ArduCopterPidConfig.cc @@ -0,0 +1,207 @@ +#include "ArduCopterPidConfig.h" + +ArduCopterPidConfig::ArduCopterPidConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + m_pitchRollLocked = false; + connect(ui.checkBox,SIGNAL(clicked(bool)),this,SLOT(lockCheckBoxClicked(bool))); + connect(ui.stabilPitchPSpinBox,SIGNAL(valueChanged(double)),this,SLOT(stabilLockedChanged(double))); + connect(ui.stabilRollPSpinBox,SIGNAL(valueChanged(double)),this,SLOT(stabilLockedChanged(double))); + connect(ui.stabilYawPSpinBox,SIGNAL(valueChanged(double)),this,SLOT(stabilLockedChanged(double))); + m_nameToBoxMap["STB_RLL_P"] = ui.stabilPitchPSpinBox; + m_nameToBoxMap["STB_PIT_P"] = ui.stabilRollPSpinBox; + m_nameToBoxMap["STB_YAW_P"] = ui.stabilYawPSpinBox; + m_nameToBoxMap["HLD_LAT_P"] = ui.loiterPidPSpinBox; + + m_nameToBoxMap["RATE_RLL_P"] = ui.rateRollPSpinBox; + m_nameToBoxMap["RATE_RLL_I"] = ui.rateRollISpinBox; + m_nameToBoxMap["RATE_RLL_D"] = ui.rateRollDSpinBox; + m_nameToBoxMap["RATE_RLL_IMAX"] = ui.rateRollIMAXSpinBox; + + m_nameToBoxMap["RATE_PIT_P"] = ui.ratePitchPSpinBox; + m_nameToBoxMap["RATE_PIT_I"] = ui.ratePitchISpinBox; + m_nameToBoxMap["RATE_PIT_D"] = ui.ratePitchDSpinBox; + m_nameToBoxMap["RATE_PIT_IMAX"] = ui.ratePitchIMAXSpinBox; + + m_nameToBoxMap["RATE_YAW_P"] = ui.rateYawPSpinBox; + m_nameToBoxMap["RATE_YAW_I"] = ui.rateYawISpinBox; + m_nameToBoxMap["RATE_YAW_D"] = ui.rateYawDSpinBox; + m_nameToBoxMap["RATE_YAW_IMAX"] = ui.rateYawIMAXSpinBox; + + m_nameToBoxMap["LOITER_LAT_P"] = ui.rateLoiterPSpinBox; + m_nameToBoxMap["LOITER_LAT_I"] = ui.rateLoiterISpinBox; + m_nameToBoxMap["LOITER_LAT_D"] = ui.rateLoiterDSpinBox; + m_nameToBoxMap["LOITER_LAT_IMAX"] = ui.rateLoiterIMAXSpinBox; + + m_nameToBoxMap["THR_ACCEL_P"] = ui.throttleAccelPSpinBox; + m_nameToBoxMap["THR_ACCEL_I"] = ui.throttleAccelISpinBox; + m_nameToBoxMap["THR_ACCEL_D"] = ui.throttleAccelDSpinBox; + m_nameToBoxMap["THR_ACCEL_IMAX"] = ui.throttleAccelIMAXSpinBox; + + m_nameToBoxMap["THR_RATE_P"] = ui.throttleRatePSpinBox; + m_nameToBoxMap["THR_RATE_D"] = ui.throttleDateDSpinBox; + + m_nameToBoxMap["THR_ALT_P"] = ui.altitudeHoldPSpinBox; + + m_nameToBoxMap["WPNAV_SPEED"] = ui.wpNavLoiterSpeedSpinBox; + m_nameToBoxMap["WPNAV_RADIUS"] = ui.wpNavRadiusSpinBox; + m_nameToBoxMap["WPNAV_SPEED_DN"] = ui.wpNavSpeedDownSpinBox; + m_nameToBoxMap["WPNAV_LOIT_SPEED"] = ui.wpNavSpeedSpinBox; + m_nameToBoxMap["WPNAV_SPEED_UP"] = ui.wpNavSpeedUpSpinBox; + + m_nameToBoxMap["TUNE_HIGH"] = ui.ch6MaxSpinBox; + m_nameToBoxMap["TUNE_LOW"] = ui.ch6MinSpinBox; + + connect(ui.writePushButton,SIGNAL(clicked()),this,SLOT(writeButtonClicked())); + connect(ui.refreshPushButton,SIGNAL(clicked()),this,SLOT(refreshButtonClicked())); + + + + m_ch6ValueToTextList.append(QPair(0,"CH6_NONE")); + m_ch6ValueToTextList.append(QPair(1,"CH6_STABILIZE_KP")); + m_ch6ValueToTextList.append(QPair(2,"CH6_STABILIZE_KI")); + m_ch6ValueToTextList.append(QPair(3,"CH6_YAW_KP")); + m_ch6ValueToTextList.append(QPair(24,"CH6_YAW_KI")); + m_ch6ValueToTextList.append(QPair(4,"CH6_RATE_KP")); + m_ch6ValueToTextList.append(QPair(5,"CH6_RATE_KI")); + m_ch6ValueToTextList.append(QPair(6,"CH6_YAW_RATE_KP")); + m_ch6ValueToTextList.append(QPair(26,"CH6_YAW_RATE_KD")); + m_ch6ValueToTextList.append(QPair(7,"CH6_THROTTLE_KP")); + m_ch6ValueToTextList.append(QPair(9,"CH6_RELAY")); + m_ch6ValueToTextList.append(QPair(10,"CH6_WP_SPEED")); + m_ch6ValueToTextList.append(QPair(12,"CH6_LOITER_KP")); + m_ch6ValueToTextList.append(QPair(13,"CH6_HELI_EXTERNAL_GYRO")); + m_ch6ValueToTextList.append(QPair(14,"CH6_THR_HOLD_KP")); + m_ch6ValueToTextList.append(QPair(17,"CH6_OPTFLOW_KP")); + m_ch6ValueToTextList.append(QPair(18,"CH6_OPTFLOW_KI")); + m_ch6ValueToTextList.append(QPair(19,"CH6_OPTFLOW_KD")); + m_ch6ValueToTextList.append(QPair(21,"CH6_RATE_KD")); + m_ch6ValueToTextList.append(QPair(22,"CH6_LOITER_RATE_KP")); + m_ch6ValueToTextList.append(QPair(23,"CH6_LOITER_RATE_KD")); + m_ch6ValueToTextList.append(QPair(25,"CH6_ACRO_KP")); + m_ch6ValueToTextList.append(QPair(27,"CH6_LOITER_KI")); + m_ch6ValueToTextList.append(QPair(28,"CH6_LOITER_RATE_KI")); + m_ch6ValueToTextList.append(QPair(29,"CH6_STABILIZE_KD")); + m_ch6ValueToTextList.append(QPair(30,"CH6_AHRS_YAW_KP")); + m_ch6ValueToTextList.append(QPair(31,"CH6_AHRS_KP")); + m_ch6ValueToTextList.append(QPair(32,"CH6_INAV_TC")); + m_ch6ValueToTextList.append(QPair(33,"CH6_THROTTLE_KI")); + m_ch6ValueToTextList.append(QPair(34,"CH6_THR_ACCEL_KP")); + m_ch6ValueToTextList.append(QPair(35,"CH6_THR_ACCEL_KI")); + m_ch6ValueToTextList.append(QPair(36,"CH6_THR_ACCEL_KD")); + m_ch6ValueToTextList.append(QPair(38,"CH6_DECLINATION")); + m_ch6ValueToTextList.append(QPair(39,"CH6_CIRCLE_RATE")); + for (int i=0;iaddItem(m_ch6ValueToTextList[i].second); + } + + m_ch78ValueToTextList.append(QPair(0,"Do nothing")); + m_ch78ValueToTextList.append(QPair(2,"Flip")); + m_ch78ValueToTextList.append(QPair(3,"Simple mode")); + m_ch78ValueToTextList.append(QPair(4,"RTL")); + m_ch78ValueToTextList.append(QPair(5,"Save Trim")); + m_ch78ValueToTextList.append(QPair(7,"Save WP")); + m_ch78ValueToTextList.append(QPair(8,"Multi Mode")); + m_ch78ValueToTextList.append(QPair(9,"Camera Trigger")); + m_ch78ValueToTextList.append(QPair(10,"Sonar")); + m_ch78ValueToTextList.append(QPair(11,"Fence")); + m_ch78ValueToTextList.append(QPair(12,"ResetToArmedYaw")); + for (int i=0;iaddItem(m_ch78ValueToTextList[i].second); + ui.ch8OptComboBox->addItem(m_ch78ValueToTextList[i].second); + } + initConnections(); +} +void ArduCopterPidConfig::lockCheckBoxClicked(bool checked) +{ + m_pitchRollLocked = checked; +} +void ArduCopterPidConfig::stabilLockedChanged(double value) +{ + if (m_pitchRollLocked) + { + disconnect(ui.stabilPitchPSpinBox,SIGNAL(valueChanged(double)),this,SLOT(stabilLockedChanged(double))); + disconnect(ui.stabilRollPSpinBox,SIGNAL(valueChanged(double)),this,SLOT(stabilLockedChanged(double))); + disconnect(ui.stabilYawPSpinBox,SIGNAL(valueChanged(double)),this,SLOT(stabilLockedChanged(double))); + ui.stabilPitchPSpinBox->setValue(value); + ui.stabilRollPSpinBox->setValue(value); + ui.stabilYawPSpinBox->setValue(value); + connect(ui.stabilPitchPSpinBox,SIGNAL(valueChanged(double)),this,SLOT(stabilLockedChanged(double))); + connect(ui.stabilRollPSpinBox,SIGNAL(valueChanged(double)),this,SLOT(stabilLockedChanged(double))); + connect(ui.stabilYawPSpinBox,SIGNAL(valueChanged(double)),this,SLOT(stabilLockedChanged(double))); + } +} + +ArduCopterPidConfig::~ArduCopterPidConfig() +{ +} +void ArduCopterPidConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (m_nameToBoxMap.contains(parameterName)) + { + m_nameToBoxMap[parameterName]->setValue(value.toDouble()); + } + else if (parameterName == "TUNE") + { + for (int i=0;isetCurrentIndex(i); + } + } + } + else if (parameterName == "CH7_OPT") + { + for (int i=0;isetCurrentIndex(i); + } + } + } + else if (parameterName == "CH8_OPT") + { + for (int i=0;isetCurrentIndex(i); + } + } + } +} +void ArduCopterPidConfig::writeButtonClicked() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + for (QMap::const_iterator i=m_nameToBoxMap.constBegin();i!=m_nameToBoxMap.constEnd();i++) + { + m_uas->getParamManager()->setParameter(1,i.key(),i.value()->value()); + } + m_uas->getParamManager()->setParameter(1,"TUNE",m_ch78ValueToTextList[ui.ch6OptComboBox->currentIndex()].first); + m_uas->getParamManager()->setParameter(1,"CH7_OPT",m_ch78ValueToTextList[ui.ch7OptComboBox->currentIndex()].first); + m_uas->getParamManager()->setParameter(1,"CH8_OPT",m_ch78ValueToTextList[ui.ch8OptComboBox->currentIndex()].first); +} + +void ArduCopterPidConfig::refreshButtonClicked() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + for (QMap::const_iterator i=m_nameToBoxMap.constBegin();i!=m_nameToBoxMap.constEnd();i++) + { + m_uas->getParamManager()->requestParameterUpdate(1,i.key()); + } + m_uas->getParamManager()->requestParameterUpdate(1,"TUNE"); + m_uas->getParamManager()->requestParameterUpdate(1,"CH7_OPT"); + m_uas->getParamManager()->requestParameterUpdate(1,"CH8_OPT"); +} diff --git a/src/ui/configuration/ArduCopterPidConfig.h b/src/ui/configuration/ArduCopterPidConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..d8a1360b882e67f07e31283ae9e17ed8557538ac --- /dev/null +++ b/src/ui/configuration/ArduCopterPidConfig.h @@ -0,0 +1,30 @@ +#ifndef ARDUCOPTERPIDCONFIG_H +#define ARDUCOPTERPIDCONFIG_H + +#include +#include "ui_ArduCopterPidConfig.h" + +#include "AP2ConfigWidget.h" + +class ArduCopterPidConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit ArduCopterPidConfig(QWidget *parent = 0); + ~ArduCopterPidConfig(); +private slots: + void writeButtonClicked(); + void refreshButtonClicked(); + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void lockCheckBoxClicked(bool checked); + void stabilLockedChanged(double value); +private: + bool m_pitchRollLocked; + QList > m_ch6ValueToTextList; + QList > m_ch78ValueToTextList; + QMap m_nameToBoxMap; + Ui::ArduCopterPidConfig ui; +}; + +#endif // ARDUCOPTERPIDCONFIG_H diff --git a/src/ui/configuration/ArduCopterPidConfig.ui b/src/ui/configuration/ArduCopterPidConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..351ce51ed24e4463b9c9ac508fe2bea5c50730df --- /dev/null +++ b/src/ui/configuration/ArduCopterPidConfig.ui @@ -0,0 +1,1061 @@ + + + ArduCopterPidConfig + + + + 0 + 0 + 750 + 596 + + + + Form + + + + + 20 + 10 + 181 + 51 + + + + <h2>ArduCopter Pids</h2> + + + + + + 120 + 540 + 75 + 23 + + + + Write Params + + + + + + 220 + 540 + 91 + 23 + + + + Refresh Params + + + + + + 10 + 70 + 695 + 401 + + + + + + + Rate Yaw + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Loiter PID + + + + + + + + + + P + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Rate Pitch + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Stabilize Roll + + + + + + + + + + P + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Stabilize Pitch + + + + + + + + + + P + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + + + + + + + + Rate Roll + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Altitude Hold + + + + + + + + + + P + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Stabilize Yaw + + + + + + + + + + P + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Rate Loiter + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Lock Pitch and Roll Values + + + + + + + + + + + Ch6 Opt + + + + + + + + + + + + + + Min + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + Max + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + Ch7 Opt + + + + + + + + + + + + + + Ch8 Opt + + + + + + + + + + + + + + Throttle Accel + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Throttle Rate + + + + + + + + + + P + + + + + + + D + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + WPNav (cm's) + + + + + + + + + + Speed + + + + + + + Radius + + + + + + + Speed Up + + + + + + + speed Down + + + + + + + Loiter Speed + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + + + diff --git a/src/ui/configuration/ArduPlanePidConfig.cc b/src/ui/configuration/ArduPlanePidConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..157c2db3878a989b6b5673daa2a04e1274ef4917 --- /dev/null +++ b/src/ui/configuration/ArduPlanePidConfig.cc @@ -0,0 +1,99 @@ +#include "ArduPlanePidConfig.h" + + +ArduPlanePidConfig::ArduPlanePidConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + + m_nameToBoxMap["RLL2SRV_P"] = ui.servoRollPSpinBox; + m_nameToBoxMap["RLL2SRV_I"] = ui.servoRollISpinBox; + m_nameToBoxMap["RLL2SRV_D"] = ui.servoRollDSpinBox; + m_nameToBoxMap["RLL2SRV_IMAX"] = ui.servoRollIMAXSpinBox; + + m_nameToBoxMap["PTCH2SRV_P"] = ui.servoPitchPSpinBox; + m_nameToBoxMap["PTCH2SRV_I"] = ui.servoPitchISpinBox; + m_nameToBoxMap["PTCH2SRV_D"] = ui.servoPitchDSpinBox; + m_nameToBoxMap["PTCH2SRV_IMAX"] = ui.servoPitchIMAXSpinBox; + + m_nameToBoxMap["YW2SRV_P"] = ui.servoYawPSpinBox; + m_nameToBoxMap["YW2SRV_I"] = ui.servoYawISpinBox; + m_nameToBoxMap["YW2SRV_D"] = ui.servoYawDSpinBox; + m_nameToBoxMap["YW2SRV_IMAX"] = ui.servoYawIMAXSpinBox; + + m_nameToBoxMap["ALT2PTCH_P"] = ui.navAltPSpinBox; + m_nameToBoxMap["ALT2PTCH_I"] = ui.navAltISpinBox; + m_nameToBoxMap["ALT2PTCH_D"] = ui.navAltDSpinBox; + m_nameToBoxMap["ALT2PTCH_IMAX"] = ui.navAltIMAXSpinBox; + + m_nameToBoxMap["ARSP2PTCH_P"] = ui.navASPSpinBox; + m_nameToBoxMap["ARSP2PTCH_I"] = ui.navASISpinBox; + m_nameToBoxMap["ARSP2PTCH_D"] = ui.navASDSpinBox; + m_nameToBoxMap["ARSP2PTCH_IMAX"] = ui.navASIMAXSpinBox; + + m_nameToBoxMap["ENRGY2THR_P"] = ui.energyPSpinBox; + m_nameToBoxMap["ENRGY2THR_I"] = ui.energyISpinBox; + m_nameToBoxMap["ENRGY2THR_D"] = ui.energyDSpinBox; + m_nameToBoxMap["ENRGY2THR_IMAX"] = ui.energyIMAXSpinBox; + + m_nameToBoxMap["KFF_PTCH2THR"] = ui.otherPitchCompSpinBox; + m_nameToBoxMap["KFF_PTCHCOMP"] = ui.otherPtTSpinBox; + m_nameToBoxMap["KFF_RDDRMIX"] = ui.otherRudderMixSpinBox; + + m_nameToBoxMap["TRIM_THROTTLE"] = ui.throttleCruiseSpinBox; + m_nameToBoxMap["THR_FS_VALUE"] = ui.throttleFSSpinBox; + m_nameToBoxMap["THR_MAX"] = ui.throttleMaxSpinBox; + m_nameToBoxMap["THR_MIN"] = ui.throttleMinSpinBox; + + m_nameToBoxMap["TRIM_ARSPD_CM"] = ui.airspeedCruiseSpinBox; + m_nameToBoxMap["ARSPD_FBW_MAX"] = ui.airspeedFBWMaxSpinBox; + m_nameToBoxMap["ARSPD_FBW_MIN"] = ui.airspeedFBWMinSpinBox; + m_nameToBoxMap["ARSPD_RATIO"] = ui.airspeedRatioSpinBox; + + m_nameToBoxMap["NAVL1_DAMPING"] = ui.l1DampingSpinBox; + m_nameToBoxMap["NAVL1_PERIOD"] = ui.l1PeriodSpinBox; + + m_nameToBoxMap["LIM_ROLL_CD"] = ui.navBankMaxSpinBox; + m_nameToBoxMap["LIM_PITCH_MAX"] = ui.navPitchMaxSpinBox; + m_nameToBoxMap["LIM_PITCH_MIN"] = ui.navPitchMinSpinBox; + + connect(ui.writePushButton,SIGNAL(clicked()),this,SLOT(writeButtonClicked())); + connect(ui.refreshPushButton,SIGNAL(clicked()),this,SLOT(refreshButtonClicked())); + initConnections(); +} + +ArduPlanePidConfig::~ArduPlanePidConfig() +{ +} +void ArduPlanePidConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (m_nameToBoxMap.contains(parameterName)) + { + m_nameToBoxMap[parameterName]->setValue(value.toDouble()); + } +} +void ArduPlanePidConfig::writeButtonClicked() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + for (QMap::const_iterator i=m_nameToBoxMap.constBegin();i!=m_nameToBoxMap.constEnd();i++) + { + m_uas->getParamManager()->setParameter(1,i.key(),i.value()->value()); + } +} + +void ArduPlanePidConfig::refreshButtonClicked() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + for (QMap::const_iterator i=m_nameToBoxMap.constBegin();i!=m_nameToBoxMap.constEnd();i++) + { + m_uas->getParamManager()->requestParameterUpdate(1,i.key()); + } + +} diff --git a/src/ui/configuration/ArduPlanePidConfig.h b/src/ui/configuration/ArduPlanePidConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..3a254cb37198ec3dcb85d75f03790aabb14cb78b --- /dev/null +++ b/src/ui/configuration/ArduPlanePidConfig.h @@ -0,0 +1,24 @@ +#ifndef ARDUPLANEPIDCONFIG_H +#define ARDUPLANEPIDCONFIG_H + +#include +#include "ui_ArduPlanePidConfig.h" +#include "AP2ConfigWidget.h" + +class ArduPlanePidConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit ArduPlanePidConfig(QWidget *parent = 0); + ~ArduPlanePidConfig(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void writeButtonClicked(); + void refreshButtonClicked(); +private: + QMap m_nameToBoxMap; + Ui::ArduPlanePidConfig ui; +}; + +#endif // ARDUPLANEPIDCONFIG_H diff --git a/src/ui/configuration/ArduPlanePidConfig.ui b/src/ui/configuration/ArduPlanePidConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..4ee4c406b15f97f025969bdefc401c22fe9a3fd6 --- /dev/null +++ b/src/ui/configuration/ArduPlanePidConfig.ui @@ -0,0 +1,963 @@ + + + ArduPlanePidConfig + + + + 0 + 0 + 733 + 641 + + + + Form + + + + + 20 + 10 + 681 + 581 + + + + + + + L1 Control - Turn Control + + + + + + + + + + Period + + + + + + + Damping + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Servo Roll Pid + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 10000.000000000000000 + + + + + + + + + + + + + + Nav Pitch Alt Pid + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 10000.000000000000000 + + + + + + + + + + + + + + Nav Pitch AS Pid + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 10000.000000000000000 + + + + + + + + + + + + + + Servo Yaw Pid + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 10000.000000000000000 + + + + + + + + + + + + + + Throttle 0-100% + + + + + + + + + + Cruise + + + + + + + Min + + + + + + + Max + + + + + + + FS Value + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 10000.000000000000000 + + + + + + + + + + + + + + Servo Pitch Pid + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 10000.000000000000000 + + + + + + + + + + + + + + Aiespeed m/s + + + + + + + + + + Cruise + + + + + + + FBW min + + + + + + + FBW max + + + + + + + Ratio + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 100.000000000000000 + + + + + + + + + + + + + + Other Mix's + + + + + + + + + + P to T + + + + + + + Pitch Comp + + + + + + + Rudder Mix + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + + + + + + + + Navigation Angles + + + + + + + + + + Bank Max + + + + + + + Pitch Max + + + + + + + Pitch Min + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + 10000.000000000000000 + + + 0.000000000000000 + + + + + + + + + + + + + + Energy/Alt Pid + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 3 + + + 100.000000000000000 + + + + + + + 100.000000000000000 + + + + + + + + + + + + + + + + 260 + 600 + 75 + 23 + + + + Write Params + + + + + + 350 + 600 + 75 + 23 + + + + Refresh Params + + + + + + diff --git a/src/ui/configuration/ArduRoverPidConfig.cc b/src/ui/configuration/ArduRoverPidConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..e84d79943c3790fa6138138b1e1397fa48533e92 --- /dev/null +++ b/src/ui/configuration/ArduRoverPidConfig.cc @@ -0,0 +1,80 @@ +#include "ArduRoverPidConfig.h" + + +ArduRoverPidConfig::ArduRoverPidConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + nameToBoxMap["STEER2SRV_P"] = ui.steer2ServoPSpinBox; + nameToBoxMap["STEER2SRV_I"] = ui.steer2ServoISpinBox; + nameToBoxMap["STEER2SRV_D"] = ui.steer2ServoDSpinBox; + nameToBoxMap["STEER2SRV_IMAX"] = ui.steer2ServoIMAXSpinBox; + + nameToBoxMap["XTRK_ANGLE_CD"] = ui.xtrackEntryAngleSpinBox; + nameToBoxMap["XTRK_GAIN_SC"] = ui.xtrackGainSpinBox; + + nameToBoxMap["CRUISE_THROTTLE"] = ui.throttleCruiseSpinBox; + nameToBoxMap["THR_MIN"] = ui.throttleMinSpinBox; + nameToBoxMap["THR_MAX"] = ui.throttleMaxSpinBox; + nameToBoxMap["FS_THR_VALUE"] = ui.throttleFSSpinBox; + + nameToBoxMap["HDNG2STEER_P"] = ui.heading2SteerPSpinBox; + nameToBoxMap["HDNG2STEER_I"] = ui.heading2SteerISpinBox; + nameToBoxMap["HDNG2STEER_D"] = ui.heading2SteerDSpinBox; + nameToBoxMap["HDNG2STEER_IMAX"] = ui.heading2SteerIMAXSpinBox; + + nameToBoxMap["SPEED2THR_P"] = ui.speed2ThrottlePSpinBox; + nameToBoxMap["SPEED2THR_I"] = ui.speed2ThrottleISpinBox; + nameToBoxMap["SPEED2THR_D"] = ui.speed2ThrottleDSpinBox; + nameToBoxMap["SPEED2THR_IMAX"] = ui.speed2ThrottleIMAXSpinBox; + + nameToBoxMap["CRUISE_SPEED"] = ui.roverCruiseSpinBox; + nameToBoxMap["SPEED_TURN_GAIN"] = ui.roverTurnSpeedSpinBox; + nameToBoxMap["SPEED_TURN_DIST"] = ui.roverTurnDistSpinBox; + nameToBoxMap["WP_RADIUS"] = ui.roverWPRadiusSpinBox; + + nameToBoxMap["SONAR_TRIGGER_CM"] = ui.sonarTriggerSpinBox; + nameToBoxMap["SONAR_TURN_ANGLE"] = ui.sonarTurnAngleSpinBox; + nameToBoxMap["SONAR_TURN_TIME"] = ui.sonarTurnTimeSpinBox; + nameToBoxMap["SONAR_DEBOUNCE"] = ui.sonaeDebounceSpinBox; + + connect(ui.writePushButton,SIGNAL(clicked()),this,SLOT(writeButtonClicked())); + connect(ui.refreshPushButton,SIGNAL(clicked()),this,SLOT(refreshButtonClicked())); + initConnections(); +} + +ArduRoverPidConfig::~ArduRoverPidConfig() +{ +} +void ArduRoverPidConfig::writeButtonClicked() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + for (QMap::const_iterator i=nameToBoxMap.constBegin();i!=nameToBoxMap.constEnd();i++) + { + m_uas->getParamManager()->setParameter(1,i.key(),i.value()->value()); + } +} + +void ArduRoverPidConfig::refreshButtonClicked() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + for (QMap::const_iterator i=nameToBoxMap.constBegin();i!=nameToBoxMap.constEnd();i++) + { + m_uas->getParamManager()->requestParameterUpdate(1,i.key()); + } +} + +void ArduRoverPidConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (nameToBoxMap.contains(parameterName)) + { + nameToBoxMap[parameterName]->setValue(value.toFloat()); + } +} diff --git a/src/ui/configuration/ArduRoverPidConfig.h b/src/ui/configuration/ArduRoverPidConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..214658bdccf2f45dc8e450a2da29e81f60876e49 --- /dev/null +++ b/src/ui/configuration/ArduRoverPidConfig.h @@ -0,0 +1,23 @@ +#ifndef ARDUROVERPIDCONFIG_H +#define ARDUROVERPIDCONFIG_H + +#include +#include "ui_ArduRoverPidConfig.h" +#include "AP2ConfigWidget.h" +class ArduRoverPidConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit ArduRoverPidConfig(QWidget *parent = 0); + ~ArduRoverPidConfig(); +private slots: + void writeButtonClicked(); + void refreshButtonClicked(); + void parameterChanged(int uas, int component, QString parameterName, QVariant value); +private: + QMap nameToBoxMap; + Ui::ArduRoverPidConfig ui; +}; + +#endif // ARDUROVERPIDCONFIG_H diff --git a/src/ui/configuration/ArduRoverPidConfig.ui b/src/ui/configuration/ArduRoverPidConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..47831616e0adbd2578e60934c450c831c1ea7ce3 --- /dev/null +++ b/src/ui/configuration/ArduRoverPidConfig.ui @@ -0,0 +1,732 @@ + + + ArduRoverPidConfig + + + + 0 + 0 + 626 + 607 + + + + Form + + + + + 10 + 10 + 151 + 21 + + + + <h2>ArduRover Pids</h2> + + + + + + 60 + 90 + 504 + 419 + + + + + + + Steer 2 Servo + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Speed 2 Throttle + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Heading 2 Steer + + + + + + + + + + P + + + + + + + I + + + + + + + D + + + + + + + INT_MAX + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Throttle 0-100% + + + + + + + + + + Cruise + + + + + + + Min + + + + + + + Max + + + + + + + FS Value + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Xtrack Pids + + + + + + + + + + Gain (cm) + + + + + + + Entry Angle + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Sonar + + + + + + + + + + Trigger cm + + + + + + + Turn Angle + + + + + + + Turn Time + + + + + + + Debounce + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + Rover + + + + + + + + + + Cruise Speed + + + + + + + Turn Speed + + + + + + + Turn Dist + + + + + + + WP Radius + + + + + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + 3 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + + + + + + + + + + 300 + 540 + 91 + 23 + + + + Refresh Params + + + + + + 200 + 540 + 75 + 23 + + + + Write Params + + + + + + diff --git a/src/ui/configuration/BasicPidConfig.cc b/src/ui/configuration/BasicPidConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..938940e5f0912b7363f36f708c0b7a55b3700089 --- /dev/null +++ b/src/ui/configuration/BasicPidConfig.cc @@ -0,0 +1,11 @@ +#include "BasicPidConfig.h" + + +BasicPidConfig::BasicPidConfig(QWidget *parent) : QWidget(parent) +{ + ui.setupUi(this); +} + +BasicPidConfig::~BasicPidConfig() +{ +} diff --git a/src/ui/configuration/BasicPidConfig.h b/src/ui/configuration/BasicPidConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..3129239416bbd244b7e5547b5d03c0adb42e3c67 --- /dev/null +++ b/src/ui/configuration/BasicPidConfig.h @@ -0,0 +1,19 @@ +#ifndef BASICPIDCONFIG_H +#define BASICPIDCONFIG_H + +#include +#include "ui_BasicPidConfig.h" + +class BasicPidConfig : public QWidget +{ + Q_OBJECT + +public: + explicit BasicPidConfig(QWidget *parent = 0); + ~BasicPidConfig(); + +private: + Ui::BasicPidConfig ui; +}; + +#endif // BASICPIDCONFIG_H diff --git a/src/ui/configuration/BasicPidConfig.ui b/src/ui/configuration/BasicPidConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..4be479c989c42bc7f0b61515609a91d1882f61cf --- /dev/null +++ b/src/ui/configuration/BasicPidConfig.ui @@ -0,0 +1,32 @@ + + + BasicPidConfig + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + 30 + 20 + 141 + 31 + + + + <h2> Basic Pids</h2> + + + + + + diff --git a/src/ui/configuration/BatteryMonitorConfig.cc b/src/ui/configuration/BatteryMonitorConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..68692aa62bb2fc49bf58c6bca50515c836782cfd --- /dev/null +++ b/src/ui/configuration/BatteryMonitorConfig.cc @@ -0,0 +1,311 @@ +#include "BatteryMonitorConfig.h" +#include + +BatteryMonitorConfig::BatteryMonitorConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + ui.monitorComboBox->addItem(tr("0: Disabled")); + ui.monitorComboBox->addItem(tr("3: Battery Volts")); + ui.monitorComboBox->addItem(tr("4: Voltage and Current")); + + ui.sensorComboBox->addItem(tr("0: Other")); + ui.sensorComboBox->addItem("1: AttoPilot 45A"); + ui.sensorComboBox->addItem("2: AttoPilot 90A"); + ui.sensorComboBox->addItem("3: AttoPilot 180A"); + ui.sensorComboBox->addItem("4: 3DR Power Module"); + + ui.apmVerComboBox->addItem("0: APM1"); + ui.apmVerComboBox->addItem("1: APM2 - 2.5 non 3DR"); + ui.apmVerComboBox->addItem("2: APM2.5 - 3DR Power Module"); + ui.apmVerComboBox->addItem("3: PX4"); + + ui.alertOnLowCheckBox->setVisible(false); //Unimpelemented, but TODO. + + + connect(ui.monitorComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(monitorCurrentIndexChanged(int))); + connect(ui.sensorComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(sensorCurrentIndexChanged(int))); + connect(ui.apmVerComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(apmVerCurrentIndexChanged(int))); + + connect(ui.calcDividerLineEdit,SIGNAL(editingFinished()),this,SLOT(calcDividerSet())); + connect(ui.ampsPerVoltsLineEdit,SIGNAL(editingFinished()),this,SLOT(ampsPerVoltSet())); + connect(ui.battCapacityLineEdit,SIGNAL(editingFinished()),this,SLOT(batteryCapacitySet())); + + + initConnections(); +} +void BatteryMonitorConfig::activeUASSet(UASInterface *uas) +{ + if (m_uas) + { + disconnect(m_uas,SIGNAL(batteryChanged(UASInterface*,double,double,double,int)),this,SLOT(batteryChanged(UASInterface*,double,double,double,int))); + } + AP2ConfigWidget::activeUASSet(uas); + if (!uas) + { + return; + } + connect(uas,SIGNAL(batteryChanged(UASInterface*,double,double,double,int)),this,SLOT(batteryChanged(UASInterface*,double,double,double,int))); + +} +void BatteryMonitorConfig::alertOnLowClicked(bool checked) +{ +} + +void BatteryMonitorConfig::calcDividerSet() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + bool ok = false; + float newval = ui.calcDividerLineEdit->text().toFloat(&ok); + if (!ok) + { + //Error parsing; + QMessageBox::information(0,"Error","Invalid number entered for voltage divider. Please try again"); + return; + } + m_uas->getParamManager()->setParameter(1,"VOLT_DIVIDER",newval); +} +void BatteryMonitorConfig::ampsPerVoltSet() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + bool ok = false; + float newval = ui.ampsPerVoltsLineEdit->text().toFloat(&ok); + if (!ok) + { + //Error parsing; + QMessageBox::information(0,"Error","Invalid number entered for amps per volts. Please try again"); + return; + } + m_uas->getParamManager()->setParameter(1,"AMPS_PER_VOLT",newval); +} +void BatteryMonitorConfig::batteryCapacitySet() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + bool ok = false; + float newval = ui.battCapacityLineEdit->text().toFloat(&ok); + if (!ok) + { + //Error parsing; + QMessageBox::information(0,"Error","Invalid number entered for amps per volts. Please try again"); + return; + } + m_uas->getParamManager()->setParameter(1,"BATT_CAPACITY",newval); +} + +void BatteryMonitorConfig::monitorCurrentIndexChanged(int index) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (index == 0) //Battery Monitor Disabled + { + m_uas->getParamManager()->setParameter(1,"BATT_VOLT_PIN",-1); + m_uas->getParamManager()->setParameter(1,"BATT_CURR_PIN",-1); + m_uas->getParamManager()->setParameter(1,"BATT_MONITOR",0); + ui.sensorComboBox->setEnabled(false); + ui.apmVerComboBox->setEnabled(false); + ui.measuredVoltsLineEdit->setEnabled(false); + ui.measuredVoltsLineEdit->setEnabled(false); + ui.calcDividerLineEdit->setEnabled(false); + ui.calcVoltsLineEdit->setEnabled(false); + ui.ampsPerVoltsLineEdit->setEnabled(false); + } + else if (index == 1) //Monitor voltage only + { + m_uas->getParamManager()->setParameter(1,"BATT_MONITOR",3); + ui.sensorComboBox->setEnabled(false); + ui.apmVerComboBox->setEnabled(true); + ui.measuredVoltsLineEdit->setEnabled(true); + ui.calcDividerLineEdit->setEnabled(true); + ui.calcVoltsLineEdit->setEnabled(false); + ui.ampsPerVoltsLineEdit->setEnabled(false); + } + else if (index == 2) //Monitor voltage and current + { + m_uas->getParamManager()->setParameter(1,"BATT_MONITOR",4); + ui.sensorComboBox->setEnabled(true); + ui.apmVerComboBox->setEnabled(true); + ui.measuredVoltsLineEdit->setEnabled(true); + ui.calcDividerLineEdit->setEnabled(true); + ui.calcVoltsLineEdit->setEnabled(false); + ui.ampsPerVoltsLineEdit->setEnabled(true); + } + + +} +void BatteryMonitorConfig::sensorCurrentIndexChanged(int index) +{ + float maxvolt = 0.0; + float maxamps = 0.0; + float mvpervolt = 0.0; + float mvperamp = 0.0; + float topvolt = 0.0; + float topamps = 0.0; + + if (index == 1) + { + //atto 45 see https://www.sparkfun.com/products/10643 + maxvolt = 13.6; + maxamps = 44.7; + } + else if (index == 2) + { + //atto 90 see https://www.sparkfun.com/products/9028 + maxvolt = 51.8; + maxamps = 89.4; + } + else if (index == 3) + { + //atto 180 see https://www.sparkfun.com/products/10644 + maxvolt = 51.8; + maxamps = 178.8; + } + else if (index == 4) + { + //3dr + maxvolt = 50.0; + maxamps = 90.0; + } + mvpervolt = calculatemVPerVolt(3.3,maxvolt); + mvperamp = calculatemVPerAmp(3.3,maxamps); + if (index == 0) + { + //Other + ui.ampsPerVoltsLineEdit->setEnabled(true); + ui.calcDividerLineEdit->setEnabled(true); + ui.measuredVoltsLineEdit->setEnabled(true); + } + else + { + topvolt = (maxvolt * mvpervolt) / 1000.0; + topamps = (maxamps * mvperamp) / 1000.0; + + ui.calcDividerLineEdit->setText(QString::number(maxvolt/topvolt)); + ui.ampsPerVoltsLineEdit->setText(QString::number(maxamps / topamps)); + ui.ampsPerVoltsLineEdit->setEnabled(false); + ui.calcDividerLineEdit->setEnabled(false); + ui.measuredVoltsLineEdit->setEnabled(false); + } +} +float BatteryMonitorConfig::calculatemVPerAmp(float maxvoltsout,float maxamps) +{ + return (1000.0 * (maxvoltsout/maxamps)); +} + +float BatteryMonitorConfig::calculatemVPerVolt(float maxvoltsout,float maxvolts) +{ + return (1000.0 * (maxvoltsout/maxvolts)); +} + +void BatteryMonitorConfig::apmVerCurrentIndexChanged(int index) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (index == 0) //APM1 + { + m_uas->getParamManager()->setParameter(1,"BATT_VOLT_PIN",0); + m_uas->getParamManager()->setParameter(1,"BATT_CURR_PIN",1); + } + else if (index == 1) //APM2 + { + m_uas->getParamManager()->setParameter(1,"BATT_VOLT_PIN",1); + m_uas->getParamManager()->setParameter(1,"BATT_CURR_PIN",2); + } + else if (index == 2) //APM2.5 + { + m_uas->getParamManager()->setParameter(1,"BATT_VOLT_PIN",13); + m_uas->getParamManager()->setParameter(1,"BATT_CURR_PIN",12); + } + else if (index == 3) //PX4 + { + m_uas->getParamManager()->setParameter(1,"BATT_VOLT_PIN",100); + m_uas->getParamManager()->setParameter(1,"BATT_CURR_PIN",101); + m_uas->getParamManager()->setParameter(1,"VOLT_DIVIDER",1); + ui.calcDividerLineEdit->setText("1"); + } +} + +BatteryMonitorConfig::~BatteryMonitorConfig() +{ +} +void BatteryMonitorConfig::batteryChanged(UASInterface* uas, double voltage, double current, double percent, int seconds) +{ + ui.calcVoltsLineEdit->setText(QString::number(voltage,'f',2)); + if (ui.measuredVoltsLineEdit->text() == "") + { + ui.measuredVoltsLineEdit->setText(ui.calcVoltsLineEdit->text()); + } +} + +void BatteryMonitorConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (parameterName == "VOLT_DIVIDER") + { + ui.calcDividerLineEdit->setText(QString::number(value.toFloat(),'f',4)); + } + else if (parameterName == "AMP_PER_VOLT") + { + ui.ampsPerVoltsLineEdit->setText(QString::number(value.toFloat(),'g',2)); + + } + else if (parameterName == "BATT_MONITOR") + { + if (value.toInt() == 0) //0: Disable + { + ui.monitorComboBox->setCurrentIndex(0); + } + else if (value.toInt() == 3) //3: Battery volts + { + ui.monitorComboBox->setCurrentIndex(1); + } + else if (value.toInt() == 4) //4: Voltage and Current + { + ui.monitorComboBox->setCurrentIndex(2); + } + + } + else if (parameterName == "BATT_CAPACITY") + { + ui.battCapacityLineEdit->setText(QString::number(value.toFloat())); + } + else if (parameterName == "BATT_VOLT_PIN") + { + int ivalue = value.toInt(); + if (ivalue == 0) //APM1 + { + ui.apmVerComboBox->setCurrentIndex(0); + } + else if (ivalue == 1) //APM2 + { + ui.apmVerComboBox->setCurrentIndex(1); + } + else if (ivalue == 13) //APM2.5 + { + ui.apmVerComboBox->setCurrentIndex(2); + } + else if (ivalue == 100) //PX4 + { + ui.apmVerComboBox->setCurrentIndex(3); + } + } + else if (parameterName == "BATT_CURR_PIN") + { + //Unused at the moment, everything is off BATT_VOLT_PIN + } +} diff --git a/src/ui/configuration/BatteryMonitorConfig.h b/src/ui/configuration/BatteryMonitorConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..417e6922a95e8fe73e71f1041c0a9865ac3bb182 --- /dev/null +++ b/src/ui/configuration/BatteryMonitorConfig.h @@ -0,0 +1,32 @@ +#ifndef BATTERYMONITORCONFIG_H +#define BATTERYMONITORCONFIG_H + +#include +#include "AP2ConfigWidget.h" +#include "ui_BatteryMonitorConfig.h" + +class BatteryMonitorConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit BatteryMonitorConfig(QWidget *parent = 0); + ~BatteryMonitorConfig(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void monitorCurrentIndexChanged(int index); + void sensorCurrentIndexChanged(int index); + void apmVerCurrentIndexChanged(int index); + void calcDividerSet(); + void ampsPerVoltSet(); + void batteryCapacitySet(); + void alertOnLowClicked(bool checked); + void activeUASSet(UASInterface *uas); + void batteryChanged(UASInterface* uas, double voltage, double current, double percent, int seconds); +private: + Ui::BatteryMonitorConfig ui; + inline float calculatemVPerAmp(float maxvoltsout,float maxamps); + inline float calculatemVPerVolt(float maxvoltsout,float maxvolts); +}; + +#endif // BATTERYMONITORCONFIG_H diff --git a/src/ui/configuration/BatteryMonitorConfig.ui b/src/ui/configuration/BatteryMonitorConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..5d11f960adc90b000a3ff7e3c50c464a039c6644 --- /dev/null +++ b/src/ui/configuration/BatteryMonitorConfig.ui @@ -0,0 +1,231 @@ + + + BatteryMonitorConfig + + + + 0 + 0 + 745 + 494 + + + + Form + + + + + 20 + 20 + 141 + 31 + + + + <h2>Battery Monitor</h2> + + + false + + + + + + 10 + 70 + 141 + 51 + + + + + + + :/files/images/devices/BR-APMPWRDEAN-2.jpg + + + true + + + + + + 480 + 120 + 91 + 17 + + + + Alert On Low + + + + + + 160 + 170 + 241 + 141 + + + + Calibration + + + + + + + + + + 1. Measured battery voltage: + + + + + + + 2. Battery voltage (Calc'ed): + + + + + + + 3. Voltage divider (Calc'ed): + + + + + + + 4. Amperes per volt: + + + + + + + + + + + false + + + + + + + false + + + + + + + false + + + + + + + false + + + + + + + + + + + + + 160 + 70 + 281 + 91 + + + + + + + + + Monitor + + + + + + + Sensor + + + + + + + APM Version + + + + + + + + + + + + + + + + + + + + + + + + 470 + 70 + 195 + 41 + + + + + + + Battery Capacity: + + + + + + + + + + mAh + + + + + + + + + + + diff --git a/src/ui/configuration/CameraGimbalConfig.cc b/src/ui/configuration/CameraGimbalConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..6b14b1a466cac5260f33f8f1d3df77e21d3a228b --- /dev/null +++ b/src/ui/configuration/CameraGimbalConfig.cc @@ -0,0 +1,666 @@ +#include +#include + +#include "CameraGimbalConfig.h" + +CameraGimbalConfig::CameraGimbalConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + ui.tiltChannelComboBox->addItem(tr("Disable")); + ui.tiltChannelComboBox->addItem("RC5"); + ui.tiltChannelComboBox->addItem("RC6"); + ui.tiltChannelComboBox->addItem("RC7"); + ui.tiltChannelComboBox->addItem("RC8"); + ui.tiltChannelComboBox->addItem("RC10"); + ui.tiltChannelComboBox->addItem("RC11"); + + ui.tiltInputChannelComboBox->addItem(tr("Disable")); + ui.tiltInputChannelComboBox->addItem("RC5"); + ui.tiltInputChannelComboBox->addItem("RC6"); + ui.tiltInputChannelComboBox->addItem("RC7"); + ui.tiltInputChannelComboBox->addItem("RC8"); + + ui.rollChannelComboBox->addItem(tr("Disable")); + ui.rollChannelComboBox->addItem("RC5"); + ui.rollChannelComboBox->addItem("RC6"); + ui.rollChannelComboBox->addItem("RC7"); + ui.rollChannelComboBox->addItem("RC8"); + ui.rollChannelComboBox->addItem("RC10"); + ui.rollChannelComboBox->addItem("RC11"); + + ui.rollInputChannelComboBox->addItem(tr("Disable")); + ui.rollInputChannelComboBox->addItem("RC5"); + ui.rollInputChannelComboBox->addItem("RC6"); + ui.rollInputChannelComboBox->addItem("RC7"); + ui.rollInputChannelComboBox->addItem("RC8"); + + + ui.panChannelComboBox->addItem(tr("Disable")); + ui.panChannelComboBox->addItem("RC5"); + ui.panChannelComboBox->addItem("RC6"); + ui.panChannelComboBox->addItem("RC7"); + ui.panChannelComboBox->addItem("RC8"); + ui.panChannelComboBox->addItem("RC10"); + ui.panChannelComboBox->addItem("RC11"); + + ui.panInputChannelComboBox->addItem(tr("Disable")); + ui.panInputChannelComboBox->addItem("RC5"); + ui.panInputChannelComboBox->addItem("RC6"); + ui.panInputChannelComboBox->addItem("RC7"); + ui.panInputChannelComboBox->addItem("RC8"); + + + ui.shutterChannelComboBox->addItem(tr("Disable")); + ui.shutterChannelComboBox->addItem(tr("Relay")); + ui.shutterChannelComboBox->addItem(tr("Transistor")); + ui.shutterChannelComboBox->addItem("RC5"); + ui.shutterChannelComboBox->addItem("RC6"); + ui.shutterChannelComboBox->addItem("RC7"); + ui.shutterChannelComboBox->addItem("RC8"); + ui.shutterChannelComboBox->addItem("RC10"); + ui.shutterChannelComboBox->addItem("RC11"); + + connect(ui.tiltServoMinSpinBox,SIGNAL(editingFinished()),this,SLOT(updateTilt())); + connect(ui.tiltServoMaxSpinBox,SIGNAL(editingFinished()),this,SLOT(updateTilt())); + connect(ui.tiltAngleMinSpinBox,SIGNAL(editingFinished()),this,SLOT(updateTilt())); + connect(ui.tiltAngleMaxSpinBox,SIGNAL(editingFinished()),this,SLOT(updateTilt())); + connect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + connect(ui.tiltInputChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + connect(ui.tiltReverseCheckBox,SIGNAL(clicked(bool)),this,SLOT(updateTilt())); + connect(ui.tiltStabilizeCheckBox,SIGNAL(clicked(bool)),this,SLOT(updateTilt())); + + connect(ui.rollServoMinSpinBox,SIGNAL(editingFinished()),this,SLOT(updateRoll())); + connect(ui.rollServoMaxSpinBox,SIGNAL(editingFinished()),this,SLOT(updateRoll())); + connect(ui.rollAngleMinSpinBox,SIGNAL(editingFinished()),this,SLOT(updateRoll())); + connect(ui.rollAngleMaxSpinBox,SIGNAL(editingFinished()),this,SLOT(updateRoll())); + connect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + connect(ui.rollInputChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + connect(ui.rollReverseCheckBox,SIGNAL(clicked(bool)),this,SLOT(updateRoll())); + connect(ui.rollStabilizeCheckBox,SIGNAL(clicked(bool)),this,SLOT(updateRoll())); + + connect(ui.panServoMinSpinBox,SIGNAL(editingFinished()),this,SLOT(updatePan())); + connect(ui.panServoMaxSpinBox,SIGNAL(editingFinished()),this,SLOT(updatePan())); + connect(ui.panAngleMinSpinBox,SIGNAL(editingFinished()),this,SLOT(updatePan())); + connect(ui.panAngleMaxSpinBox,SIGNAL(editingFinished()),this,SLOT(updatePan())); + connect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + connect(ui.panInputChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + connect(ui.panReverseCheckBox,SIGNAL(clicked(bool)),this,SLOT(updatePan())); + connect(ui.panStabilizeCheckBox,SIGNAL(clicked(bool)),this,SLOT(updatePan())); + + + connect(ui.shutterServoMinSpinBox,SIGNAL(editingFinished()),this,SLOT(updateShutter())); + connect(ui.shutterServoMaxSpinBox,SIGNAL(editingFinished()),this,SLOT(updateShutter())); + connect(ui.shutterPushedSpinBox,SIGNAL(editingFinished()),this,SLOT(updateShutter())); + connect(ui.shutterNotPushedSpinBox,SIGNAL(editingFinished()),this,SLOT(updateShutter())); + connect(ui.shutterDurationSpinBox,SIGNAL(editingFinished()),this,SLOT(updateShutter())); + connect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + + connect(ui.retractXSpinBox,SIGNAL(editingFinished()),this,SLOT(updateRetractAngles())); + connect(ui.retractYSpinBox,SIGNAL(editingFinished()),this,SLOT(updateRetractAngles())); + connect(ui.retractZSpinBox,SIGNAL(editingFinished()),this,SLOT(updateRetractAngles())); + + connect(ui.controlXSpinBox,SIGNAL(editingFinished()),this,SLOT(updateControlAngles())); + connect(ui.controlYSpinBox,SIGNAL(editingFinished()),this,SLOT(updateControlAngles())); + connect(ui.controlZSpinBox,SIGNAL(editingFinished()),this,SLOT(updateControlAngles())); + + connect(ui.neutralXSpinBox,SIGNAL(editingFinished()),this,SLOT(updateNeutralAngles())); + connect(ui.neutralYSpinBox,SIGNAL(editingFinished()),this,SLOT(updateNeutralAngles())); + connect(ui.neutralZSpinBox,SIGNAL(editingFinished()),this,SLOT(updateNeutralAngles())); + initConnections(); + +} +void CameraGimbalConfig::updateRetractAngles() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,"MNT_RETRACT_X",ui.retractXSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"MNT_RETRACT_Y",ui.retractYSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"MNT_RETRACT_Z",ui.retractZSpinBox->value()); +} + +void CameraGimbalConfig::updateNeutralAngles() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,"MNT_NEUTRAL_X",ui.neutralXSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"MNT_NEUTRAL_Y",ui.neutralYSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"MNT_NEUTRAL_Z",ui.neutralZSpinBox->value()); +} + +void CameraGimbalConfig::updateControlAngles() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,"MNT_CONTROL_X",ui.controlXSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"MNT_CONTROL_Y",ui.controlYSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"MNT_CONTROL_Z",ui.controlZSpinBox->value()); +} + +void CameraGimbalConfig::updateTilt() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (!m_tiltPrefix.isEmpty()) + { + //We need to set this to 0 for disabled. + m_uas->getParamManager()->setParameter(1,m_tiltPrefix + "FUNCTION",0); + } + if (ui.tiltChannelComboBox->currentIndex() == 0) + { + //Disabled + return; + } + + m_uas->getParamManager()->setParameter(1,ui.tiltChannelComboBox->currentText() + "_FUNCTION",7); + m_uas->getParamManager()->setParameter(1,ui.tiltChannelComboBox->currentText() + "_MIN",ui.tiltServoMinSpinBox->value()); + m_uas->getParamManager()->setParameter(1,ui.tiltChannelComboBox->currentText() + "_MAX",ui.tiltServoMaxSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"MNT_ANGMIN_TIL",ui.tiltAngleMinSpinBox->value() * 100); + m_uas->getParamManager()->setParameter(1,"MNT_ANGMAX_TIL",ui.tiltAngleMaxSpinBox->value() * 100); + m_uas->getParamManager()->setParameter(1,ui.tiltChannelComboBox->currentText() + "_REV",(ui.tiltReverseCheckBox->isChecked() ? 1 : 0)); + if (ui.tiltInputChannelComboBox->currentIndex() == 0) + { + m_uas->getParamManager()->setParameter(1,"MNT_RC_IN_TILT",0); + } + else + { + m_uas->getParamManager()->setParameter(1,"MNT_RC_IN_TILT",ui.tiltInputChannelComboBox->currentIndex()+4); + } +} + +void CameraGimbalConfig::updateRoll() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,ui.rollChannelComboBox->currentText() + "_FUNCTION",8); + m_uas->getParamManager()->setParameter(1,ui.rollChannelComboBox->currentText() + "_MIN",ui.rollServoMinSpinBox->value()); + m_uas->getParamManager()->setParameter(1,ui.rollChannelComboBox->currentText() + "_MAX",ui.rollServoMaxSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"MNT_ANGMIN_ROL",ui.rollAngleMinSpinBox->value() * 100); + m_uas->getParamManager()->setParameter(1,"MNT_ANGMAX_ROL",ui.rollAngleMaxSpinBox->value() * 100); + m_uas->getParamManager()->setParameter(1,ui.rollChannelComboBox->currentText() + "_REV",(ui.rollReverseCheckBox->isChecked() ? 1 : 0)); + if (ui.rollInputChannelComboBox->currentIndex() == 0) + { + m_uas->getParamManager()->setParameter(1,"MNT_RC_IN_ROLL",0); + } + else + { + m_uas->getParamManager()->setParameter(1,"MNT_RC_IN_ROLL",ui.rollInputChannelComboBox->currentIndex()+4); + } +} + +void CameraGimbalConfig::updatePan() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,ui.panChannelComboBox->currentText() + "_FUNCTION",6); + m_uas->getParamManager()->setParameter(1,ui.panChannelComboBox->currentText() + "_MIN",ui.panServoMinSpinBox->value()); + m_uas->getParamManager()->setParameter(1,ui.panChannelComboBox->currentText() + "_MAX",ui.panServoMaxSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"MNT_ANGMIN_PAN",ui.panAngleMinSpinBox->value() * 100); + m_uas->getParamManager()->setParameter(1,"MNT_ANGMAX_PAN",ui.panAngleMaxSpinBox->value() * 100); + m_uas->getParamManager()->setParameter(1,ui.panChannelComboBox->currentText() + "_REV",(ui.panReverseCheckBox->isChecked() ? 1 : 0)); + if (ui.panInputChannelComboBox->currentIndex() == 0) + { + m_uas->getParamManager()->setParameter(1,"MNT_RC_IN_PAN",0); + } + else + { + m_uas->getParamManager()->setParameter(1,"MNT_RC_IN_PAN",ui.panInputChannelComboBox->currentIndex()+4); + } +} + +void CameraGimbalConfig::updateShutter() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (ui.shutterChannelComboBox->currentIndex() == 0) //Disabled + { + m_uas->getParamManager()->setParameter(1,"CAM_TRIGG_TYPE",0); + } + else if (ui.shutterChannelComboBox->currentIndex() == 1) //Relay + { + m_uas->getParamManager()->setParameter(1,"CAM_TRIGG_TYPE",1); + } + else if (ui.shutterChannelComboBox->currentIndex() == 2) //Transistor + { + m_uas->getParamManager()->setParameter(1,"CAM_TRIGG_TYPE",4); + } + else + { + m_uas->getParamManager()->setParameter(1,ui.shutterChannelComboBox->currentText() + "_FUNCTION",10); + m_uas->getParamManager()->setParameter(1,"CAM_TRIGG_TYPE",0); + } + m_uas->getParamManager()->setParameter(1,ui.shutterChannelComboBox->currentText() + "_MIN",ui.shutterServoMinSpinBox->value()); + m_uas->getParamManager()->setParameter(1,ui.shutterChannelComboBox->currentText() + "_MAX",ui.shutterServoMaxSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"CAM_SERVO_ON",ui.shutterPushedSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"CAM_SERVO_OFF",ui.shutterNotPushedSpinBox->value()); + m_uas->getParamManager()->setParameter(1,"CAM_DURATION",ui.shutterDurationSpinBox->value()); + + +} + + +CameraGimbalConfig::~CameraGimbalConfig() +{ +} + +void CameraGimbalConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (parameterName == "MNT_ANGMIN_TIL") //TILT + { + ui.tiltAngleMinSpinBox->setValue(value.toInt() / 100.0); + } + else if (parameterName == "MNT_ANGMAX_TIL") + { + ui.tiltAngleMaxSpinBox->setValue(value.toInt() / 100.0); + } + else if (parameterName == "MNT_RC_IN_TILT") + { + disconnect(ui.tiltInputChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + if (value.toInt() == 0) + { + ui.tiltInputChannelComboBox->setCurrentIndex(0); + } + else + { + ui.tiltInputChannelComboBox->setCurrentIndex(value.toInt()-4); + } + connect(ui.tiltInputChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + } + else if (parameterName == "MNT_ANGMIN_ROL") //ROLL + { + ui.rollAngleMinSpinBox->setValue(value.toInt() / 100.0); + } + else if (parameterName == "MNT_ANGMAX_ROL") + { + ui.rollAngleMaxSpinBox->setValue(value.toInt() / 100.0); + } + else if (parameterName == "MNT_RC_IN_ROLL") + { + disconnect(ui.rollInputChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + if (value.toInt() == 0) + { + ui.rollInputChannelComboBox->setCurrentIndex(0); + } + else + { + ui.rollInputChannelComboBox->setCurrentIndex(value.toInt()-4); + } + connect(ui.rollInputChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + } + else if (parameterName == "MNT_ANGMIN_PAN") //PAN + { + ui.panAngleMinSpinBox->setValue(value.toInt() / 100.0); + } + else if (parameterName == "MNT_ANGMAX_PAN") + { + ui.panAngleMaxSpinBox->setValue(value.toInt() / 100.0); + } + else if (parameterName == "MNT_RC_IN_PAN") + { + disconnect(ui.panInputChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + if (value.toInt() == 0) + { + ui.panInputChannelComboBox->setCurrentIndex(0); + } + else + { + ui.panInputChannelComboBox->setCurrentIndex(value.toInt()-4); + } + connect(ui.panInputChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + } + if (parameterName == "CAM_DURATION") + { + ui.shutterDurationSpinBox->setValue(value.toInt()); + } + else if (parameterName == "CAM_SERVO_OFF") + { + ui.shutterNotPushedSpinBox->setValue(value.toInt()); + } + else if (parameterName == "CAM_SERVO_ON") + { + ui.shutterPushedSpinBox->setValue(value.toInt()); + } + else if (parameterName == "CAM_TRIGG_TYPE") + { + disconnect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + if (value.toInt() == 0) //Disabled + { + ui.shutterChannelComboBox->setCurrentIndex(0); + ///TODO: Request all _FUNCTIONs here to find out if shutter is actually disabled. + } + else if (value.toInt() == 1) // Relay + { + ui.shutterChannelComboBox->setCurrentIndex(1); + } + else if (value.toInt() == 4) //Transistor + { + ui.shutterChannelComboBox->setCurrentIndex(2); + } + connect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + } + if (parameterName.startsWith(m_shutterPrefix) && !m_shutterPrefix.isEmpty()) + { + if (parameterName.endsWith("MIN")) + { + ui.shutterServoMinSpinBox->setValue(value.toInt()); + } + else if (parameterName.endsWith("MAX")) + { + ui.shutterServoMaxSpinBox->setValue(value.toInt()); + } + } + else if (parameterName.startsWith(m_tiltPrefix) && !m_tiltPrefix.isEmpty()) + { + if (parameterName.endsWith("MIN")) + { + ui.tiltServoMinSpinBox->setValue(value.toInt()); + } + else if (parameterName.endsWith("MAX")) + { + ui.tiltServoMaxSpinBox->setValue(value.toInt()); + } + else if (parameterName.endsWith("REV")) + { + if (value.toInt() == 0) + { + ui.tiltReverseCheckBox->setChecked(false); + } + else + { + ui.tiltReverseCheckBox->setChecked(true); + } + } + } + else if (parameterName.startsWith(m_rollPrefix) && !m_rollPrefix.isEmpty()) + { + if (parameterName.endsWith("MIN")) + { + ui.rollServoMinSpinBox->setValue(value.toInt()); + } + else if (parameterName.endsWith("MAX")) + { + ui.rollServoMaxSpinBox->setValue(value.toInt()); + } + else if (parameterName.endsWith("REV")) + { + if (value.toInt() == 0) + { + ui.rollReverseCheckBox->setChecked(false); + } + else + { + ui.rollReverseCheckBox->setChecked(true); + } + } + } + else if (parameterName.startsWith(m_panPrefix) && !m_panPrefix.isEmpty()) + { + if (parameterName.endsWith("MIN")) + { + ui.panServoMinSpinBox->setValue(value.toInt()); + } + else if (parameterName.endsWith("MAX")) + { + ui.panServoMaxSpinBox->setValue(value.toInt()); + } + else if (parameterName.endsWith("REV")) + { + if (value.toInt() == 0) + { + ui.panReverseCheckBox->setChecked(false); + } + else + { + ui.panReverseCheckBox->setChecked(true); + } + } + } + else if (parameterName == "RC5_FUNCTION") + { + if (value.toInt() == 10) + { + //RC5 is shutter. + disconnect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + ui.shutterChannelComboBox->setCurrentIndex(3); + connect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + m_shutterPrefix = "RC5_"; + } + else if (value.toInt() == 8) + { + //RC5 is roll + disconnect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + ui.rollChannelComboBox->setCurrentIndex(1); + connect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + m_rollPrefix = "RC5_"; + } + else if (value.toInt() == 7) + { + //RC5 is tilt + disconnect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + ui.tiltChannelComboBox->setCurrentIndex(1); + connect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + m_tiltPrefix = "RC5_"; + } + else if (value.toInt() == 6) + { + //RC5 is pan + disconnect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + ui.panChannelComboBox->setCurrentIndex(1); + connect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + m_panPrefix = "RC5_"; + } + m_uas->getParamManager()->requestParameterUpdate(1,"RC5_MIN"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC5_MAX"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC5_REV"); + } + else if (parameterName == "RC6_FUNCTION") + { + if (value.toInt() == 10) + { + //RC6 is shutter. + disconnect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + ui.shutterChannelComboBox->setCurrentIndex(4); + connect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + m_shutterPrefix = "RC6_"; + } + else if (value.toInt() == 8) + { + //RC6 is roll + disconnect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + ui.rollChannelComboBox->setCurrentIndex(2); + connect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + m_rollPrefix = "RC6_"; + } + else if (value.toInt() == 7) + { + //RC6 is tilt + disconnect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + ui.tiltChannelComboBox->setCurrentIndex(2); + connect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + m_tiltPrefix = "RC6_"; + } + else if (value.toInt() == 6) + { + //RC6 is pan + disconnect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + ui.panChannelComboBox->setCurrentIndex(2); + connect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + m_panPrefix = "RC6_"; + } + m_uas->getParamManager()->requestParameterUpdate(1,"RC6_MIN"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC6_MAX"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC6_REV"); + } + else if (parameterName == "RC7_FUNCTION") + { + if (value.toInt() == 10) + { + //RC7 is shutter. + disconnect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + ui.shutterChannelComboBox->setCurrentIndex(5); + connect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + m_shutterPrefix = "RC7_"; + } + else if (value.toInt() == 8) + { + //RC7 is roll + disconnect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + ui.rollChannelComboBox->setCurrentIndex(3); + connect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + m_rollPrefix = "RC7_"; + } + else if (value.toInt() == 7) + { + //RC7 is tilt + disconnect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + ui.tiltChannelComboBox->setCurrentIndex(3); + connect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + m_tiltPrefix = "RC7_"; + } + else if (value.toInt() == 6) + { + //RC7 is pan + disconnect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + ui.panChannelComboBox->setCurrentIndex(3); + connect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + m_panPrefix = "RC7_"; + } + m_uas->getParamManager()->requestParameterUpdate(1,"RC7_MIN"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC7_MAX"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC7_REV"); + } + else if (parameterName == "RC8_FUNCTION") + { + if (value.toInt() == 10) + { + //RC8 is shutter. + disconnect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + ui.shutterChannelComboBox->setCurrentIndex(6); + connect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + m_shutterPrefix = "RC8_"; + } + else if (value.toInt() == 8) + { + //RC8 is roll + disconnect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + ui.rollChannelComboBox->setCurrentIndex(4); + connect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + m_rollPrefix = "RC8_"; + } + else if (value.toInt() == 7) + { + //RC8 is tilt + disconnect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + ui.tiltChannelComboBox->setCurrentIndex(4); + connect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + m_tiltPrefix = "RC8_"; + } + else if (value.toInt() == 6) + { + //RC8 is pan + disconnect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + ui.panChannelComboBox->setCurrentIndex(4); + connect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + m_panPrefix = "RC8_"; + } + m_uas->getParamManager()->requestParameterUpdate(1,"RC8_MIN"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC8_MAX"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC8_REV"); + } + else if (parameterName == "RC10_FUNCTION") + { + if (value.toInt() == 10) + { + //RC10 is shutter. + disconnect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + ui.shutterChannelComboBox->setCurrentIndex(7); + connect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + m_shutterPrefix = "RC10_"; + } + else if (value.toInt() == 8) + { + //RC10 is roll + disconnect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + ui.rollChannelComboBox->setCurrentIndex(5); + connect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + m_rollPrefix = "RC10_"; + } + else if (value.toInt() == 7) + { + //RC10 is tilt + disconnect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + ui.tiltChannelComboBox->setCurrentIndex(5); + connect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + m_tiltPrefix = "RC10_"; + } + else if (value.toInt() == 6) + { + //RC10 is pan + disconnect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + ui.panChannelComboBox->setCurrentIndex(5); + connect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + m_panPrefix = "RC10_"; + } + m_uas->getParamManager()->requestParameterUpdate(1,"RC10_MIN"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC10_MAX"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC10_REV"); + } + else if (parameterName == "RC11_FUNCTION") + { + if (value.toInt() == 10) + { + //RC11 is shutter. + disconnect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + ui.shutterChannelComboBox->setCurrentIndex(8); + connect(ui.shutterChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateShutter())); + m_shutterPrefix = "RC11_"; + } + else if (value.toInt() == 8) + { + //RC11 is roll + disconnect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + ui.rollChannelComboBox->setCurrentIndex(6); + connect(ui.rollChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRoll())); + m_rollPrefix = "RC11_"; + } + else if (value.toInt() == 7) + { + //RC11 is tilt + disconnect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + ui.tiltChannelComboBox->setCurrentIndex(6); + connect(ui.tiltChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updateTilt())); + m_tiltPrefix = "RC11_"; + } + else if (value.toInt() == 6) + { + //RC11 is pan + disconnect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + ui.panChannelComboBox->setCurrentIndex(6); + connect(ui.panChannelComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePan())); + m_panPrefix = "RC11_"; + } + m_uas->getParamManager()->requestParameterUpdate(1,"RC11_MIN"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC11_MAX"); + m_uas->getParamManager()->requestParameterUpdate(1,"RC11_REV"); + } +} diff --git a/src/ui/configuration/CameraGimbalConfig.h b/src/ui/configuration/CameraGimbalConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..9f686243f707e689ee25dcfa390598cd81527d94 --- /dev/null +++ b/src/ui/configuration/CameraGimbalConfig.h @@ -0,0 +1,32 @@ +#ifndef CAMERAGIMBALCONFIG_H +#define CAMERAGIMBALCONFIG_H + +#include +#include "AP2ConfigWidget.h" +#include "ui_CameraGimbalConfig.h" + +class CameraGimbalConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit CameraGimbalConfig(QWidget *parent = 0); + ~CameraGimbalConfig(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void updateTilt(); + void updateRoll(); + void updatePan(); + void updateShutter(); + void updateRetractAngles(); + void updateNeutralAngles(); + void updateControlAngles(); +private: + Ui::CameraGimbalConfig ui; + QString m_shutterPrefix; + QString m_rollPrefix; + QString m_tiltPrefix; + QString m_panPrefix; +}; + +#endif // CAMERAGIMBALCONFIG_H diff --git a/src/ui/configuration/CameraGimbalConfig.ui b/src/ui/configuration/CameraGimbalConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..1775b5945e38bc7c009e59443088c3b129ba6592 --- /dev/null +++ b/src/ui/configuration/CameraGimbalConfig.ui @@ -0,0 +1,965 @@ + + + CameraGimbalConfig + + + + 0 + 0 + 959 + 813 + + + + Form + + + + + 30 + 20 + 131 + 31 + + + + <h2>Camera Gimbal</h2> + + + false + + + + + + 30 + 60 + 541 + 151 + + + + + + + Min + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Max + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <h3>Input Ch</h3> + + + + + + + Reverse + + + + + + + <h3>Angle Limits</h3> + + + + + + + <h3>Servo Limits</h3> + + + + + + + Max + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Min + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + <h2>Tilt</h2> + + + Qt::AlignCenter + + + + + + + Stabilize Tilt + + + + + + + + 250 + 120 + + + + + 250 + 120 + + + + + + + :/files/images/devices/cameraGimalPitch1.png + + + true + + + + + + + 3000 + + + 1000 + + + + + + + 3000 + + + 2000 + + + + + + + -100 + + + 100 + + + 100 + + + + + + + 100 + + + 0 + + + + + + + + + + + + 30 + 230 + 541 + 149 + + + + + + + Min + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Max + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + <h3>Input Ch</h3> + + + + + + + Reverse + + + + + + + <h3>Angle Limits</h3> + + + + + + + <h3>Servo Limits</h3> + + + + + + + Max + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Min + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + <h2>Roll</h2> + + + Qt::AlignCenter + + + + + + + Stabilize Roll + + + + + + + + 250 + 120 + + + + + 250 + 120 + + + + + + + :/files/images/devices/cameraGimalRoll1.png + + + true + + + + + + + 3000 + + + 1000 + + + + + + + 3000 + + + 2000 + + + + + + + -100 + + + 100 + + + 100 + + + + + + + -100 + + + 100 + + + 100 + + + + + + + + + 30 + 390 + 541 + 149 + + + + + + + Min + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Max + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + <h3>Input Ch</h3> + + + + + + + Reverse + + + + + + + <h3>Angle Limits</h3> + + + + + + + <h3>Servo Limits</h3> + + + + + + + Max + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Min + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + <h2>Pan</h2> + + + Qt::AlignCenter + + + + + + + Stabilize Pan + + + + + + + + 250 + 120 + + + + + 250 + 120 + + + + + + + :/files/images/devices/cameraGimalYaw.png + + + true + + + + + + + 3000 + + + 1000 + + + + + + + -100 + + + 100 + + + 100 + + + + + + + -100 + + + 100 + + + 100 + + + + + + + 3000 + + + 2000 + + + + + + + + + 30 + 550 + 541 + 181 + + + + + + + + 250 + 120 + + + + + 250 + 120 + + + + + + + :/files/images/devices/Shutter.png + + + true + + + + + + + Duration +(1/10th sec) + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Pushed + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Not Pushed + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <h3>Shutter</h3> + + + + + + + <h3>Servo Limits</h3> + + + + + + + Max + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Min + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + <h2>Shutter</h2> + + + Qt::AlignCenter + + + + + + + <h2>Please set the Ch7 Option to Camera Trigger</h2> + + + Qt::AlignCenter + + + + + + + 3000 + + + 1000 + + + + + + + 3000 + + + 2000 + + + + + + + 100 + + + 20 + + + + + + + 3000 + + + 1000 + + + + + + + 3000 + + + 2000 + + + + + + + + + 590 + 60 + 171 + 131 + + + + Retract Angles + + + + + + + + + + X + + + + + + + Y + + + + + + + Z + + + + + + + + + + + -180 + + + 180 + + + + + + + -180 + + + 180 + + + + + + + -180 + + + 180 + + + + + + + + + + + + + 590 + 210 + 171 + 131 + + + + Neutral Angles + + + + + + + + + + X + + + + + + + Y + + + + + + + Z + + + + + + + + + + + -180 + + + 180 + + + + + + + -180 + + + 180 + + + + + + + -180 + + + 180 + + + + + + + + + + + + + 590 + 360 + 171 + 131 + + + + Control Angles + + + + + + + + + + X + + + + + + + Y + + + + + + + Z + + + + + + + + + + + -180 + + + 180 + + + + + + + -180 + + + 180 + + + + + + + -180 + + + 180 + + + + + + + + + + + + + + + diff --git a/src/ui/configuration/CompassConfig.cc b/src/ui/configuration/CompassConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..610d354ed614465965a9f08fd247b30a1ffd7191 --- /dev/null +++ b/src/ui/configuration/CompassConfig.cc @@ -0,0 +1,136 @@ +#include "CompassConfig.h" + + +CompassConfig::CompassConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + ui.autoDecCheckBox->setEnabled(false); + ui.enableCheckBox->setEnabled(false); + ui.orientationComboBox->setEnabled(false); + ui.declinationLineEdit->setEnabled(false); + connect(ui.enableCheckBox,SIGNAL(clicked(bool)),this,SLOT(enableClicked(bool))); + connect(ui.autoDecCheckBox,SIGNAL(clicked(bool)),this,SLOT(autoDecClicked(bool))); + connect(ui.orientationComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(orientationComboChanged(int))); + + ui.orientationComboBox->addItem("ROTATION_NONE"); + ui.orientationComboBox->addItem("ROTATION_YAW_45"); + ui.orientationComboBox->addItem("ROTATION_YAW_90"); + ui.orientationComboBox->addItem("ROTATION_YAW_135"); + ui.orientationComboBox->addItem("ROTATION_YAW_180"); + ui.orientationComboBox->addItem("ROTATION_YAW_225"); + ui.orientationComboBox->addItem("ROTATION_YAW_270"); + ui.orientationComboBox->addItem("ROTATION_YAW_315"); + ui.orientationComboBox->addItem("ROTATION_ROLL_180"); + ui.orientationComboBox->addItem("ROTATION_ROLL_180_YAW_45"); + ui.orientationComboBox->addItem("ROTATION_ROLL_180_YAW_90"); + ui.orientationComboBox->addItem("ROTATION_ROLL_180_YAW_135"); + ui.orientationComboBox->addItem("ROTATION_PITCH_180"); + ui.orientationComboBox->addItem("ROTATION_ROLL_180_YAW_225"); + ui.orientationComboBox->addItem("ROTATION_ROLL_180_YAW_270"); + ui.orientationComboBox->addItem("ROTATION_ROLL_180_YAW_315"); + ui.orientationComboBox->addItem("ROTATION_ROLL_90"); + ui.orientationComboBox->addItem("ROTATION_ROLL_90_YAW_45"); + ui.orientationComboBox->addItem("ROTATION_ROLL_90_YAW_90"); + ui.orientationComboBox->addItem("ROTATION_ROLL_90_YAW_135"); + ui.orientationComboBox->addItem("ROTATION_ROLL_270"); + ui.orientationComboBox->addItem("ROTATION_ROLL_270_YAW_45"); + ui.orientationComboBox->addItem("ROTATION_ROLL_270_YAW_90"); + ui.orientationComboBox->addItem("ROTATION_ROLL_270_YAW_135"); + ui.orientationComboBox->addItem("ROTATION_PITCH_90"); + ui.orientationComboBox->addItem("ROTATION_PITCH_270"); + ui.orientationComboBox->addItem("ROTATION_MAX"); + initConnections(); +} +CompassConfig::~CompassConfig() +{ +} +void CompassConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (parameterName == "MAG_ENABLE") + { + if (value.toInt() == 0) + { + ui.enableCheckBox->setChecked(false); + ui.autoDecCheckBox->setEnabled(false); + ui.declinationLineEdit->setEnabled(false); + ui.orientationComboBox->setEnabled(false); + } + else + { + ui.enableCheckBox->setChecked(true); + ui.autoDecCheckBox->setEnabled(true); + ui.declinationLineEdit->setEnabled(true); + ui.orientationComboBox->setEnabled(true); + } + ui.enableCheckBox->setEnabled(true); + } + else if (parameterName == "COMPASS_AUTODEC") + { + if (value.toInt() == 0) + { + ui.autoDecCheckBox->setChecked(false); + } + else + { + ui.autoDecCheckBox->setChecked(true); + } + } + else if (parameterName == "COMPASS_DEC") + { + ui.declinationLineEdit->setText(QString::number(value.toDouble())); + } + else if (parameterName == "COMPASS_ORIENT") + { + disconnect(ui.orientationComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(orientationComboChanged(int))); + ui.orientationComboBox->setCurrentIndex(value.toInt()); + connect(ui.orientationComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(orientationComboChanged(int))); + } +} + +void CompassConfig::enableClicked(bool enabled) +{ + if (m_uas) + { + if (enabled) + { + m_uas->getParamManager()->setParameter(1,"MAG_ENABLE",QVariant(1)); + ui.autoDecCheckBox->setEnabled(true); + if (!ui.autoDecCheckBox->isChecked()) + { + ui.declinationLineEdit->setEnabled(true); + } + } + else + { + m_uas->getParamManager()->setParameter(1,"MAG_ENABLE",QVariant(0)); + ui.autoDecCheckBox->setEnabled(false); + ui.declinationLineEdit->setEnabled(false); + } + } +} + +void CompassConfig::autoDecClicked(bool enabled) +{ + if (m_uas) + { + if (enabled) + { + m_uas->getParamManager()->setParameter(1,"COMPASS_AUTODEC",QVariant(1)); + } + else + { + m_uas->getParamManager()->setParameter(1,"COMPASS_AUTODEC",QVariant(0)); + } + } +} + +void CompassConfig::orientationComboChanged(int index) +{ + //COMPASS_ORIENT + if (!m_uas) + { + return; + } + m_uas->getParamManager()->setParameter(1,"COMPASS_ORIENT",index); + +} diff --git a/src/ui/configuration/CompassConfig.h b/src/ui/configuration/CompassConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..d650c1bebb89fc587934a9d3fbc70377020d2723 --- /dev/null +++ b/src/ui/configuration/CompassConfig.h @@ -0,0 +1,25 @@ +#ifndef COMPASSCONFIG_H +#define COMPASSCONFIG_H + +#include +#include "ui_CompassConfig.h" +#include "UASManager.h" +#include "UASInterface.h" +#include "AP2ConfigWidget.h" +class CompassConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit CompassConfig(QWidget *parent = 0); + ~CompassConfig(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void enableClicked(bool enabled); + void autoDecClicked(bool enabled); + void orientationComboChanged(int index); +private: + Ui::CompassConfig ui; +}; + +#endif // COMPASSCONFIG_H diff --git a/src/ui/configuration/CompassConfig.ui b/src/ui/configuration/CompassConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..95b9362b441dc7279f45a2c26adf80606b89d7ea --- /dev/null +++ b/src/ui/configuration/CompassConfig.ui @@ -0,0 +1,196 @@ + + + CompassConfig + + + + 0 + 0 + 565 + 241 + + + + Form + + + + + 10 + 0 + 521 + 31 + + + + <h2>Compass</h2> + + + false + + + + + + 230 + 100 + 101 + 16 + + + + <a href="http://magnetic-declination.com/">Declination Website</a> + + + + + + 280 + 120 + 201 + 22 + + + + + + + 290 + 180 + 101 + 23 + + + + Live Calibration + + + + + + 390 + 180 + 101 + 23 + + + + Log Calibration + + + + + + 340 + 160 + 91 + 16 + + + + Advanced Config + + + + + + 220 + 70 + 321 + 31 + + + + + + + + + + in Degrees eg 2* 3' W is -2.3 + + + + + + + + + 10 + 70 + 211 + 111 + + + + + + + + 100 + 100 + + + + + + + :/files/images/devices/BR-HMC5883-01-2.jpg + + + true + + + + + + + + + Enable + + + + + + + Auto Declination + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + 220 + 120 + 54 + 20 + + + + Orientation + + + + + + + + diff --git a/src/ui/configuration/FailSafeConfig.cc b/src/ui/configuration/FailSafeConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..9d177cc735ec12e004ac113e5c500fc1bf13e201 --- /dev/null +++ b/src/ui/configuration/FailSafeConfig.cc @@ -0,0 +1,440 @@ +#include "FailSafeConfig.h" + + +FailSafeConfig::FailSafeConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + ui.radio1In->setName("Radio 1"); + ui.radio1In->setMin(800); + ui.radio1In->setMax(2200); + ui.radio1In->setOrientation(Qt::Horizontal); + ui.radio2In->setName("Radio 2"); + ui.radio2In->setMin(800); + ui.radio2In->setMax(2200); + ui.radio2In->setOrientation(Qt::Horizontal); + ui.radio3In->setName("Radio 3"); + ui.radio3In->setMin(800); + ui.radio3In->setMax(2200); + ui.radio3In->setOrientation(Qt::Horizontal); + ui.radio4In->setName("Radio 4"); + ui.radio4In->setMin(800); + ui.radio4In->setMax(2200); + ui.radio4In->setOrientation(Qt::Horizontal); + ui.radio5In->setName("Radio 5"); + ui.radio5In->setMin(800); + ui.radio5In->setMax(2200); + ui.radio5In->setOrientation(Qt::Horizontal); + ui.radio6In->setName("Radio 6"); + ui.radio6In->setMin(800); + ui.radio6In->setMax(2200); + ui.radio6In->setOrientation(Qt::Horizontal); + ui.radio7In->setName("Radio 7"); + ui.radio7In->setMin(800); + ui.radio7In->setMax(2200); + ui.radio7In->setOrientation(Qt::Horizontal); + ui.radio8In->setName("Radio 8"); + ui.radio8In->setMin(800); + ui.radio8In->setMax(2200); + ui.radio8In->setOrientation(Qt::Horizontal); + + ui.radio1Out->setName("Radio 1"); + ui.radio1Out->setMin(800); + ui.radio1Out->setMax(2200); + ui.radio1Out->setOrientation(Qt::Horizontal); + ui.radio2Out->setName("Radio 2"); + ui.radio2Out->setMin(800); + ui.radio2Out->setMax(2200); + ui.radio2Out->setOrientation(Qt::Horizontal); + ui.radio3Out->setName("Radio 3"); + ui.radio3Out->setMin(800); + ui.radio3Out->setMax(2200); + ui.radio3Out->setOrientation(Qt::Horizontal); + ui.radio4Out->setName("Radio 4"); + ui.radio4Out->setMin(800); + ui.radio4Out->setMax(2200); + ui.radio4Out->setOrientation(Qt::Horizontal); + ui.radio5Out->setName("Radio 5"); + ui.radio5Out->setMin(800); + ui.radio5Out->setMax(2200); + ui.radio5Out->setOrientation(Qt::Horizontal); + ui.radio6Out->setName("Radio 6"); + ui.radio6Out->setMin(800); + ui.radio6Out->setMax(2200); + ui.radio6Out->setOrientation(Qt::Horizontal); + ui.radio7Out->setName("Radio 7"); + ui.radio7Out->setMin(800); + ui.radio7Out->setMax(2200); + ui.radio7Out->setOrientation(Qt::Horizontal); + ui.radio8Out->setName("Radio 8"); + ui.radio8Out->setMin(800); + ui.radio8Out->setMax(2200); + ui.radio8Out->setOrientation(Qt::Horizontal); + + ui.throttleFailSafeComboBox->addItem("Disable"); + ui.throttleFailSafeComboBox->addItem("Enabled - Always TRL"); + ui.throttleFailSafeComboBox->addItem("Enabled - Continue in auto"); + + connect(ui.batteryFailCheckBox,SIGNAL(clicked(bool)),this,SLOT(batteryFailChecked(bool))); + connect(ui.fsLongCheckBox,SIGNAL(clicked(bool)),this,SLOT(fsLongClicked(bool))); + connect(ui.fsShortCheckBox,SIGNAL(clicked(bool)),this,SLOT(fsShortClicked(bool))); + connect(ui.gcsCheckBox,SIGNAL(clicked(bool)),this,SLOT(gcsChecked(bool))); + connect(ui.throttleActionCheckBox,SIGNAL(clicked(bool)),this,SLOT(throttleActionChecked(bool))); + connect(ui.throttleCheckBox,SIGNAL(clicked(bool)),this,SLOT(throttleChecked(bool))); + connect(ui.throttlePwmSpinBox,SIGNAL(editingFinished()),this,SLOT(throttlePwmChanged())); + connect(ui.throttleFailSafeComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(throttleFailSafeChanged(int))); + + ui.armedLabel->setText("

DISARMED

"); + + + ui.modeLabel->setText("

MODE

"); + initConnections(); +} +void FailSafeConfig::gcsChecked(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (checked) + { + m_uas->setParameter(1,"FS_GCS_ENABL",1); + } + else + { + m_uas->setParameter(1,"FS_GCS_ENABL",0); + } +} + +void FailSafeConfig::throttleActionChecked(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (checked) + { + m_uas->setParameter(1,"THR_FS_ACTION",1); + } + else + { + m_uas->setParameter(1,"THR_FS_ACTION",0); + } +} + +void FailSafeConfig::throttleChecked(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (checked) + { + m_uas->setParameter(1,"THR_FAILSAFE",1); + } + else + { + m_uas->setParameter(1,"THR_FAILSAFE",0); + } +} + +void FailSafeConfig::throttlePwmChanged() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->setParameter(1,"THR_FS_VALUE",ui.throttlePwmSpinBox->value()); +} + +void FailSafeConfig::throttleFailSafeChanged(int index) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->setParameter(1,"FS_THR_ENABLE",index); +} + +void FailSafeConfig::fsLongClicked(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (checked) + { + m_uas->setParameter(1,"FS_LONG_ACTN",1); + } + else + { + m_uas->setParameter(1,"FS_LONG_ACTN",0); + } +} + +void FailSafeConfig::fsShortClicked(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (checked) + { + m_uas->setParameter(1,"FS_SHORT_ACTN",1); + } + else + { + m_uas->setParameter(1,"FS_SHORT_ACTN",0); + } +} + +void FailSafeConfig::batteryFailChecked(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + if (checked) + { + m_uas->setParameter(1,"FS_BATT_ENABLE",1); + } + else + { + m_uas->setParameter(1,"FS_BATT_ENABLE",0); + } +} + +FailSafeConfig::~FailSafeConfig() +{ +} +void FailSafeConfig::activeUASSet(UASInterface *uas) +{ + if (m_uas) + { + disconnect(m_uas,SIGNAL(remoteControlChannelRawChanged(int,float)),this,SLOT(remoteControlChannelRawChanges(int,float))); + disconnect(m_uas,SIGNAL(hilActuatorsChanged(uint64_t,float,float,float,float,float,float,float,float)),this,SLOT(hilActuatorsChanged(uint64_t,float,float,float,float,float,float,float,float))); + disconnect(m_uas,SIGNAL(armingChanged(bool)),this,SLOT(armingChanged(bool))); + } + AP2ConfigWidget::activeUASSet(uas); + if (!uas) + { + return; + } + connect(m_uas,SIGNAL(remoteControlChannelRawChanged(int,float)),this,SLOT(remoteControlChannelRawChanges(int,float))); + connect(m_uas,SIGNAL(hilActuatorsChanged(uint64_t,float,float,float,float,float,float,float,float)),this,SLOT(hilActuatorsChanged(uint64_t,float,float,float,float,float,float,float,float))); + connect(m_uas,SIGNAL(armingChanged(bool)),this,SLOT(armingChanged(bool))); + connect(m_uas,SIGNAL(gpsLocalizationChanged(UASInterface*,int)),this,SLOT(gpsStatusChanged(UASInterface*,int))); + if (m_uas->getSystemType() == MAV_TYPE_FIXED_WING) + { + ui.batteryFailCheckBox->setVisible(false); + ui.throttleFailSafeComboBox->setVisible(false); + ui.batteryVoltSpinBox->setVisible(false); + ui.label_6->setVisible(false); + + ui.throttlePwmSpinBox->setVisible(true); //Both + + ui.throttleCheckBox->setVisible(true); + ui.throttleActionCheckBox->setVisible(true); + ui.gcsCheckBox->setVisible(true); + ui.fsLongCheckBox->setVisible(true); + ui.fsShortCheckBox->setVisible(true); + } + else if (m_uas->getSystemType() == MAV_TYPE_QUADROTOR) + { + ui.batteryFailCheckBox->setVisible(true); + ui.throttleFailSafeComboBox->setVisible(true); + ui.batteryVoltSpinBox->setVisible(true); + ui.label_6->setVisible(true); + + ui.throttlePwmSpinBox->setVisible(true); //Both + + ui.throttleCheckBox->setVisible(false); + ui.throttleActionCheckBox->setVisible(false); + ui.gcsCheckBox->setVisible(false); + ui.fsLongCheckBox->setVisible(false); + ui.fsShortCheckBox->setVisible(false); + } + else + { + //Show all, just in case + ui.batteryFailCheckBox->setVisible(true); + ui.throttleFailSafeComboBox->setVisible(true); + ui.batteryVoltSpinBox->setVisible(true); + ui.throttlePwmSpinBox->setVisible(true); //Both + ui.throttleCheckBox->setVisible(true); + ui.throttleActionCheckBox->setVisible(true); + ui.gcsCheckBox->setVisible(true); + ui.fsLongCheckBox->setVisible(true); + ui.fsShortCheckBox->setVisible(true); + } + +} +void FailSafeConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + //Arducopter + if (parameterName == "FS_THR_ENABLE") + { + ui.throttleFailSafeComboBox->setCurrentIndex(value.toInt()); + } + else if (parameterName == "FS_THR_VALUE") + { + ui.throttlePwmSpinBox->setValue(value.toFloat()); + } + else if (parameterName == "FS_BATT_ENABLE") + { + if (value.toInt() == 0) + { + ui.batteryFailCheckBox->setChecked(false); + } + else + { + ui.batteryFailCheckBox->setChecked(true); + } + } + else if (parameterName == "LOW_VOLT") + { + ui.batteryVoltSpinBox->setValue(value.toFloat()); + } + //Arduplane + else if (parameterName == "THR_FAILSAFE") + { + if (value.toInt() == 0) + { + ui.throttleCheckBox->setChecked(false); + } + else + { + ui.throttleCheckBox->setChecked(true); + } + } + else if (parameterName == "THR_FS_VALUE") + { + ui.throttlePwmSpinBox->setValue(value.toFloat()); + } + else if (parameterName == "THR_FS_ACTION") + { + if (value.toInt() == 0) + { + ui.throttleActionCheckBox->setChecked(false); + } + else + { + ui.throttleActionCheckBox->setChecked(true); + } + } + else if (parameterName == "FS_GCS_ENABL") + { + if (value.toInt() == 0) + { + ui.gcsCheckBox->setChecked(false); + } + else + { + ui.gcsCheckBox->setChecked(true); + } + } + else if (parameterName == "FS_SHORT_ACTN") + { + if (value.toInt() == 0) + { + ui.fsShortCheckBox->setChecked(false); + } + else + { + ui.fsShortCheckBox->setChecked(true); + } + } + else if (parameterName == "FS_LONG_ACTN") + { + if (value.toInt() == 0) + { + ui.fsLongCheckBox->setChecked(false); + } + else + { + ui.fsLongCheckBox->setChecked(true); + } + } + +} + +void FailSafeConfig::armingChanged(bool armed) +{ + if (armed) + { + ui.armedLabel->setText("

ARMED

"); + } + else + { + ui.armedLabel->setText("

DISARMED

"); + } +} + +void FailSafeConfig::remoteControlChannelRawChanges(int chan,float value) +{ + if (chan == 0) + { + ui.radio1In->setValue(value); + } + else if (chan == 1) + { + ui.radio2In->setValue(value); + } + else if (chan == 2) + { + ui.radio3In->setValue(value); + } + else if (chan == 3) + { + ui.radio4In->setValue(value); + } + else if (chan == 4) + { + ui.radio5In->setValue(value); + } + else if (chan == 5) + { + ui.radio6In->setValue(value); + } + else if (chan == 6) + { + ui.radio7In->setValue(value); + } + else if (chan == 7) + { + ui.radio8In->setValue(value); + } +} +void FailSafeConfig::hilActuatorsChanged(uint64_t time, float act1, float act2, float act3, float act4, float act5, float act6, float act7, float act8) +{ + ui.radio1Out->setValue(act1); + ui.radio2Out->setValue(act2); + ui.radio3Out->setValue(act3); + ui.radio4Out->setValue(act4); + ui.radio5Out->setValue(act5); + ui.radio6Out->setValue(act6); + ui.radio7Out->setValue(act7); + ui.radio8Out->setValue(act8); +} +void FailSafeConfig::gpsStatusChanged(UASInterface* uas,int fixtype) +{ + if (fixtype == 0 || fixtype == 1) + { + ui.gpsLabel->setText("

None

"); + } + else if (fixtype == 2) + { + ui.gpsLabel->setText("

2D Fix

"); + } + else if (fixtype == 3) + { + ui.gpsLabel->setText("

3D Fix

"); + } +} diff --git a/src/ui/configuration/FailSafeConfig.h b/src/ui/configuration/FailSafeConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..82467393122121d0d2bc696ff65ee2131a2d9e40 --- /dev/null +++ b/src/ui/configuration/FailSafeConfig.h @@ -0,0 +1,33 @@ +#ifndef FAILSAFECONFIG_H +#define FAILSAFECONFIG_H + +#include +#include "ui_FailSafeConfig.h" +#include "AP2ConfigWidget.h" +class FailSafeConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit FailSafeConfig(QWidget *parent = 0); + ~FailSafeConfig(); +private slots: + void activeUASSet(UASInterface *uas); + void remoteControlChannelRawChanges(int chan,float value); + void hilActuatorsChanged(uint64_t time, float act1, float act2, float act3, float act4, float act5, float act6, float act7, float act8); + void armingChanged(bool armed); + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void batteryFailChecked(bool checked); + void fsLongClicked(bool checked); + void fsShortClicked(bool checked); + void gcsChecked(bool checked); + void throttleActionChecked(bool checked); + void throttleChecked(bool checked); + void throttlePwmChanged(); + void throttleFailSafeChanged(int index); + void gpsStatusChanged(UASInterface* uas,int fixtype); +private: + Ui::FailSafeConfig ui; +}; + +#endif // FAILSAFECONFIG_H diff --git a/src/ui/configuration/FailSafeConfig.ui b/src/ui/configuration/FailSafeConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..69375dd53599967a7c06b48b2aeb1f2f3213397c --- /dev/null +++ b/src/ui/configuration/FailSafeConfig.ui @@ -0,0 +1,452 @@ + + + FailSafeConfig + + + + 0 + 0 + 822 + 536 + + + + Form + + + + + 20 + 20 + 141 + 31 + + + + <h2>Fail Safe</h2> + + + + + + 20 + 70 + 252 + 441 + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + + 300 + 70 + 252 + 441 + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + + 570 + 60 + 181 + 181 + + + + Status + + + + + + TextLabel + + + + + + + TextLabel + + + + + + + TextLabel + + + + + + + + + 570 + 250 + 161 + 261 + + + + Failsafe Options + + + + + + Throttle FailSafe + + + + + + + + + + + + FS Pwm + + + + + + + 3000 + + + + + + + + + Throttle FailSafe Action + + + + + + + GCS FailSafe + + + + + + + FailSafe Short (1 sec) + + + + + + + FailSafe Long (20 sec) + + + + + + + Battery Failsafe + + + + + + + + + Low Battery + + + + + + + 100.000000000000000 + + + + + + + + + + + QGCRadioChannelDisplay + QWidget +
ui/designer/QGCRadioChannelDisplay.h
+ 1 +
+
+ + +
diff --git a/src/ui/configuration/FlightModeConfig.cc b/src/ui/configuration/FlightModeConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..114c88857a77cbd06ba4d90211d2b6df1418ae50 --- /dev/null +++ b/src/ui/configuration/FlightModeConfig.cc @@ -0,0 +1,307 @@ +#include "FlightModeConfig.h" + + +FlightModeConfig::FlightModeConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + connect(ui.savePushButton,SIGNAL(clicked()),this,SLOT(saveButtonClicked())); + initConnections(); +} + +FlightModeConfig::~FlightModeConfig() +{ +} +void FlightModeConfig::activeUASSet(UASInterface *uas) +{ + if (m_uas) + { + disconnect(m_uas,SIGNAL(modeChanged(int,QString,QString)),this,SLOT(modeChanged(int,QString,QString))); + disconnect(m_uas,SIGNAL(remoteControlChannelRawChanged(int,float)),this,SLOT(remoteControlChannelRawChanged(int,float))); + } + AP2ConfigWidget::activeUASSet(uas); + if (!uas) return; + connect(m_uas,SIGNAL(modeChanged(int,QString,QString)),this,SLOT(modeChanged(int,QString,QString))); + connect(m_uas,SIGNAL(remoteControlChannelRawChanged(int,float)),this,SLOT(remoteControlChannelRawChanged(int,float))); + QStringList itemlist; + if (m_uas->getSystemType() == MAV_TYPE_FIXED_WING) + { + itemlist << "Manual"; + itemlist << "Circle"; + itemlist << "Stabilize"; + itemlist << "Training"; + itemlist << "FBW A"; + itemlist << "FBW B"; + itemlist << "Auto"; + itemlist << "RTL"; + itemlist << "Loiter"; + itemlist << "Guided"; + + planeModeIndexToUiIndex[0] = 0; + planeModeUiIndexToIndex[0] = 0; + + planeModeIndexToUiIndex[1] = 1; + planeModeUiIndexToIndex[1] = 1; + + planeModeIndexToUiIndex[2] = 2; + planeModeUiIndexToIndex[2] = 2; + + planeModeIndexToUiIndex[3] = 3; + planeModeUiIndexToIndex[3] = 3; + + planeModeIndexToUiIndex[5] = 4; + planeModeUiIndexToIndex[4] = 5; + + planeModeIndexToUiIndex[6] = 5; + planeModeUiIndexToIndex[5] = 6; + + planeModeIndexToUiIndex[10] = 6; + planeModeUiIndexToIndex[6] = 10; + + planeModeIndexToUiIndex[11] = 7; + planeModeUiIndexToIndex[7] = 11; + + planeModeIndexToUiIndex[12] = 8; + planeModeUiIndexToIndex[8] = 12; + + planeModeIndexToUiIndex[15] = 9; + planeModeUiIndexToIndex[9] = 15; + + ui.mode6ComboBox->setEnabled(true); + } + else if (m_uas->getSystemType() == MAV_TYPE_GROUND_ROVER) + { + itemlist << "Manual"; + itemlist << "Learning"; + itemlist << "Steering"; + itemlist << "Hold"; + itemlist << "Auto"; + itemlist << "RTL"; + itemlist << "Guided"; + itemlist << "Initialising"; + ui.mode6ComboBox->setEnabled(false); + roverModeIndexToUiIndex[0] = 0; + roverModeUiIndexToIndex[0] = 0; + + roverModeIndexToUiIndex[2] = 1; + roverModeUiIndexToIndex[1] = 2; + + roverModeIndexToUiIndex[3] = 2; + roverModeUiIndexToIndex[2] = 3; + + roverModeIndexToUiIndex[4] = 3; + roverModeUiIndexToIndex[3] = 4; + + roverModeIndexToUiIndex[10] = 5; + roverModeUiIndexToIndex[5] = 10; + + roverModeIndexToUiIndex[11] = 6; + roverModeUiIndexToIndex[6] = 11; + + roverModeIndexToUiIndex[15] = 7; + roverModeUiIndexToIndex[7] = 15; + + roverModeIndexToUiIndex[16] = 8; + roverModeUiIndexToIndex[8] = 16; + + + } + else if (m_uas->getSystemType() == MAV_TYPE_QUADROTOR) + { + itemlist << "Stabilize"; + itemlist << "Acro"; + itemlist << "Alt Hold"; + itemlist << "Auto"; + itemlist << "Guided"; + itemlist << "Loiter"; + itemlist << "RTL"; + itemlist << "Circle"; + itemlist << "Pos Hold"; + itemlist << "Land"; + itemlist << "OF_LOITER"; + itemlist << "Toy"; + ui.mode6ComboBox->setEnabled(true); + } + ui.mode1ComboBox->addItems(itemlist); + ui.mode2ComboBox->addItems(itemlist); + ui.mode3ComboBox->addItems(itemlist); + ui.mode4ComboBox->addItems(itemlist); + ui.mode5ComboBox->addItems(itemlist); + ui.mode6ComboBox->addItems(itemlist); +} +void FlightModeConfig::modeChanged(int sysId, QString status, QString description) +{ + //Unused? +} +void FlightModeConfig::saveButtonClicked() +{ + if (m_uas->getSystemType() == MAV_TYPE_FIXED_WING) + { + m_uas->getParamManager()->setParameter(1,"FLTMODE1",(char)planeModeUiIndexToIndex[ui.mode1ComboBox->currentIndex()]); + m_uas->getParamManager()->setParameter(1,"FLTMODE2",(char)planeModeUiIndexToIndex[ui.mode2ComboBox->currentIndex()]); + m_uas->getParamManager()->setParameter(1,"FLTMODE3",(char)planeModeUiIndexToIndex[ui.mode3ComboBox->currentIndex()]); + m_uas->getParamManager()->setParameter(1,"FLTMODE4",(char)planeModeUiIndexToIndex[ui.mode4ComboBox->currentIndex()]); + m_uas->getParamManager()->setParameter(1,"FLTMODE5",(char)planeModeUiIndexToIndex[ui.mode5ComboBox->currentIndex()]); + m_uas->getParamManager()->setParameter(1,"FLTMODE6",(char)planeModeUiIndexToIndex[ui.mode6ComboBox->currentIndex()]); + } + else if (m_uas->getSystemType() == MAV_TYPE_GROUND_ROVER) + { + m_uas->getParamManager()->setParameter(1,"MODE1",(char)roverModeUiIndexToIndex[ui.mode1ComboBox->currentIndex()]); + m_uas->getParamManager()->setParameter(1,"MODE2",(char)roverModeUiIndexToIndex[ui.mode2ComboBox->currentIndex()]); + m_uas->getParamManager()->setParameter(1,"MODE3",(char)roverModeUiIndexToIndex[ui.mode3ComboBox->currentIndex()]); + m_uas->getParamManager()->setParameter(1,"MODE4",(char)roverModeUiIndexToIndex[ui.mode4ComboBox->currentIndex()]); + m_uas->getParamManager()->setParameter(1,"MODE5",(char)roverModeUiIndexToIndex[ui.mode5ComboBox->currentIndex()]); + } + else if (m_uas->getSystemType() == MAV_TYPE_QUADROTOR) + { + m_uas->getParamManager()->setParameter(1,"FLTMODE1",(char)ui.mode1ComboBox->currentIndex()); + m_uas->getParamManager()->setParameter(1,"FLTMODE2",(char)ui.mode2ComboBox->currentIndex()); + m_uas->getParamManager()->setParameter(1,"FLTMODE3",(char)ui.mode3ComboBox->currentIndex()); + m_uas->getParamManager()->setParameter(1,"FLTMODE4",(char)ui.mode4ComboBox->currentIndex()); + m_uas->getParamManager()->setParameter(1,"FLTMODE5",(char)ui.mode5ComboBox->currentIndex()); + m_uas->getParamManager()->setParameter(1,"FLTMODE6",(char)ui.mode6ComboBox->currentIndex()); + } +} + +void FlightModeConfig::remoteControlChannelRawChanged(int chan,float val) +{ + if (chan == 4) + { + //Channel 5 (0 array) is the mode switch. + ///TODO: Make this configurable + if (val <= 1230) + { + ui.mode1Label->setStyleSheet("background-color: rgb(0, 255, 0);color: rgb(0, 0, 0);"); + ui.mode2Label->setStyleSheet(""); + ui.mode3Label->setStyleSheet(""); + ui.mode4Label->setStyleSheet(""); + ui.mode5Label->setStyleSheet(""); + ui.mode6Label->setStyleSheet(""); + } + else if (val <= 1360) + { + ui.mode1Label->setStyleSheet(""); + ui.mode2Label->setStyleSheet("background-color: rgb(0, 255, 0);color: rgb(0, 0, 0);"); + ui.mode3Label->setStyleSheet(""); + ui.mode4Label->setStyleSheet(""); + ui.mode5Label->setStyleSheet(""); + ui.mode6Label->setStyleSheet(""); + } + else if (val <= 1490) + { + ui.mode1Label->setStyleSheet(""); + ui.mode2Label->setStyleSheet(""); + ui.mode3Label->setStyleSheet("background-color: rgb(0, 255, 0);color: rgb(0, 0, 0);"); + ui.mode4Label->setStyleSheet(""); + ui.mode5Label->setStyleSheet(""); + ui.mode6Label->setStyleSheet(""); + } + else if (val <=1620) + { + ui.mode1Label->setStyleSheet(""); + ui.mode2Label->setStyleSheet(""); + ui.mode3Label->setStyleSheet(""); + ui.mode4Label->setStyleSheet("background-color: rgb(0, 255, 0);color: rgb(0, 0, 0);"); + ui.mode5Label->setStyleSheet(""); + ui.mode6Label->setStyleSheet(""); + } + else if (val <=1749) + { + ui.mode1Label->setStyleSheet(""); + ui.mode2Label->setStyleSheet(""); + ui.mode3Label->setStyleSheet(""); + ui.mode4Label->setStyleSheet(""); + ui.mode5Label->setStyleSheet("background-color: rgb(0, 255, 0);color: rgb(0, 0, 0);"); + ui.mode6Label->setStyleSheet(""); + } + else + { + ui.mode1Label->setStyleSheet(""); + ui.mode2Label->setStyleSheet(""); + ui.mode3Label->setStyleSheet(""); + ui.mode4Label->setStyleSheet(""); + ui.mode5Label->setStyleSheet(""); + ui.mode6Label->setStyleSheet("background-color: rgb(0, 255, 0);color: rgb(0, 0, 0);"); + } + } +} + +void FlightModeConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (m_uas->getSystemType() == MAV_TYPE_FIXED_WING) + { + if (parameterName == "FLTMODE1") + { + ui.mode1ComboBox->setCurrentIndex(planeModeIndexToUiIndex[value.toInt()]); + } + else if (parameterName == "FLTMODE2") + { + ui.mode2ComboBox->setCurrentIndex(planeModeIndexToUiIndex[value.toInt()]); + } + else if (parameterName == "FLTMODE3") + { + ui.mode3ComboBox->setCurrentIndex(planeModeIndexToUiIndex[value.toInt()]); + } + else if (parameterName == "FLTMODE4") + { + ui.mode4ComboBox->setCurrentIndex(planeModeIndexToUiIndex[value.toInt()]); + } + else if (parameterName == "FLTMODE5") + { + ui.mode5ComboBox->setCurrentIndex(planeModeIndexToUiIndex[value.toInt()]); + } + else if (parameterName == "FLTMODE6") + { + ui.mode6ComboBox->setCurrentIndex(planeModeIndexToUiIndex[value.toInt()]); + } + } + else if (m_uas->getSystemType() == MAV_TYPE_GROUND_ROVER) + { + if (parameterName == "MODE1") + { + ui.mode1ComboBox->setCurrentIndex(roverModeIndexToUiIndex[value.toInt()]); + } + else if (parameterName == "MODE2") + { + ui.mode2ComboBox->setCurrentIndex(roverModeIndexToUiIndex[value.toInt()]); + } + else if (parameterName == "MODE3") + { + ui.mode3ComboBox->setCurrentIndex(roverModeIndexToUiIndex[value.toInt()]); + } + else if (parameterName == "MODE4") + { + ui.mode4ComboBox->setCurrentIndex(roverModeIndexToUiIndex[value.toInt()]); + } + else if (parameterName == "MODE5") + { + ui.mode5ComboBox->setCurrentIndex(roverModeIndexToUiIndex[value.toInt()]); + } + } + else if (m_uas->getSystemType() == MAV_TYPE_QUADROTOR) + { + if (parameterName == "FLTMODE1") + { + ui.mode1ComboBox->setCurrentIndex(value.toInt()); + } + else if (parameterName == "FLTMODE2") + { + ui.mode2ComboBox->setCurrentIndex(value.toInt()); + } + else if (parameterName == "FLTMODE3") + { + ui.mode3ComboBox->setCurrentIndex(value.toInt()); + } + else if (parameterName == "FLTMODE4") + { + ui.mode4ComboBox->setCurrentIndex(value.toInt()); + } + else if (parameterName == "FLTMODE5") + { + ui.mode5ComboBox->setCurrentIndex(value.toInt()); + } + else if (parameterName == "FLTMODE6") + { + ui.mode6ComboBox->setCurrentIndex(value.toInt()); + } + } +} diff --git a/src/ui/configuration/FlightModeConfig.h b/src/ui/configuration/FlightModeConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..373de8560e02ee5259c4f1b7b45cd6247f203d3f --- /dev/null +++ b/src/ui/configuration/FlightModeConfig.h @@ -0,0 +1,31 @@ +#ifndef FLIGHTMODECONFIG_H +#define FLIGHTMODECONFIG_H + +#include +#include "ui_FlightModeConfig.h" +#include "UASInterface.h" +#include "UASManager.h" +#include "AP2ConfigWidget.h" + +class FlightModeConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit FlightModeConfig(QWidget *parent = 0); + ~FlightModeConfig(); +private slots: + void activeUASSet(UASInterface *uas); + void saveButtonClicked(); + void modeChanged(int sysId, QString status, QString description); + void remoteControlChannelRawChanged(int chan,float val); + void parameterChanged(int uas, int component, QString parameterName, QVariant value); +private: + QMap roverModeIndexToUiIndex; + QMap planeModeIndexToUiIndex; + QMap roverModeUiIndexToIndex; + QMap planeModeUiIndexToIndex; + Ui::FlightModeConfig ui; +}; + +#endif // FLIGHTMODECONFIG_H diff --git a/src/ui/configuration/FlightModeConfig.ui b/src/ui/configuration/FlightModeConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..2cb8585bd3f0d3e4dcb4c18ff2d7e8aa574b3ec2 --- /dev/null +++ b/src/ui/configuration/FlightModeConfig.ui @@ -0,0 +1,264 @@ + + + FlightModeConfig + + + + 0 + 0 + 818 + 359 + + + + Form + + + + + 10 + 20 + 131 + 31 + + + + <h2>Flight Modes</h2> + + + false + + + + + + 20 + 70 + 481 + 191 + + + + + + + 8 + + + 0 + + + + + Flight Mode 1 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Flight Mode 2 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Flight Mode 3 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Flight Mode 4 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Flight Mode 5 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Flight Mode 6 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + 8 + + + 0 + + + + + Simple Mode + + + + + + + Simple Mode + + + + + + + Simple Mode + + + + + + + Simple Mode + + + + + + + Simple Mode + + + + + + + Simple Mode + + + + + + + + + + + + + + PWM 0 - 1230 + + + + + + + PWM 1231 - 1360 + + + + + + + PWM 1361 - 1490 + + + + + + + PWM 1491 - 1620 + + + + + + + PWM 1621 - 1749 + + + + + + + + + + PWM 1750 + + + + + + + + + + + + 50 + 290 + 75 + 23 + + + + Save + + + + + + diff --git a/src/ui/configuration/FrameTypeConfig.cc b/src/ui/configuration/FrameTypeConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..8c123c69fbb581de6e719b22676f1e0407ef6ec1 --- /dev/null +++ b/src/ui/configuration/FrameTypeConfig.cc @@ -0,0 +1,103 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2013 Michael Carpenter (malcom2073@gmail.com) + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL 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 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Airframe type configuration widget source. + * + * @author Michael Carpenter + * + */ + +#include "FrameTypeConfig.h" + + +FrameTypeConfig::FrameTypeConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + + //Disable until we get a FRAME parameter. + ui.xRadioButton->setEnabled(false); + ui.vRadioButton->setEnabled(false); + ui.plusRadioButton->setEnabled(false); + + connect(ui.plusRadioButton,SIGNAL(clicked()),this,SLOT(plusFrameSelected())); + connect(ui.xRadioButton,SIGNAL(clicked()),this,SLOT(xFrameSelected())); + connect(ui.vRadioButton,SIGNAL(clicked()),this,SLOT(vFrameSelected())); + initConnections(); +} + +FrameTypeConfig::~FrameTypeConfig() +{ +} +void FrameTypeConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (parameterName == "FRAME") + { + ui.xRadioButton->setEnabled(true); + ui.vRadioButton->setEnabled(true); + ui.plusRadioButton->setEnabled(true); + if (value.toInt() == 0) + { + ui.plusRadioButton->setChecked(true); + } + else if (value.toInt() == 1) + { + ui.xRadioButton->setChecked(true); + } + else if (value.toInt() == 2) + { + ui.vRadioButton->setChecked(true); + } + } +} + +void FrameTypeConfig::xFrameSelected() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,"FRAME",QVariant(1)); +} + +void FrameTypeConfig::plusFrameSelected() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,"FRAME",QVariant(0)); +} + +void FrameTypeConfig::vFrameSelected() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,"FRAME",QVariant(2)); +} diff --git a/src/ui/configuration/FrameTypeConfig.h b/src/ui/configuration/FrameTypeConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..92d04b95c50db05eb24233f20360ff672287da71 --- /dev/null +++ b/src/ui/configuration/FrameTypeConfig.h @@ -0,0 +1,57 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2013 Michael Carpenter (malcom2073@gmail.com) + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL 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 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Airframe type configuration widget header. + * + * @author Michael Carpenter + * + */ + +#ifndef FRAMETYPECONFIG_H +#define FRAMETYPECONFIG_H + +#include +#include "ui_FrameTypeConfig.h" +#include "UASInterface.h" +#include "UASManager.h" +#include "QGCUASParamManager.h" +#include "AP2ConfigWidget.h" +class FrameTypeConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit FrameTypeConfig(QWidget *parent = 0); + ~FrameTypeConfig(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void xFrameSelected(); + void plusFrameSelected(); + void vFrameSelected(); +private: + Ui::FrameTypeConfig ui; +}; + +#endif // FRAMETYPECONFIG_H diff --git a/src/ui/configuration/FrameTypeConfig.ui b/src/ui/configuration/FrameTypeConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..6787fa5dbc17d6f27fdfeeb689e766c4dc49b44d --- /dev/null +++ b/src/ui/configuration/FrameTypeConfig.ui @@ -0,0 +1,107 @@ + + + FrameTypeConfig + + + + 0 + 0 + 553 + 497 + + + + Form + + + + + + <h2>Frame Setup</h2> + + + false + + + + + + + + + 'Plus' Style + + + + :/files/images/mavs/frames_plus.png:/files/images/mavs/frames_plus.png + + + + 300 + 150 + + + + + + + + 'X' Style + + + + :/files/images/mavs/frames_x.png:/files/images/mavs/frames_x.png + + + + 300 + 150 + + + + + + + + Qt::LeftToRight + + + false + + + 'V' Style + + + + :/files/images/mavs/frames-05.png:/files/images/mavs/frames-05.png + + + + 300 + 120 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + diff --git a/src/ui/configuration/GeoFenceConfig.cc b/src/ui/configuration/GeoFenceConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..ea01a4b248aa781b46c20fa384402a0dbff6502d --- /dev/null +++ b/src/ui/configuration/GeoFenceConfig.cc @@ -0,0 +1,11 @@ +#include "GeoFenceConfig.h" + + +GeoFenceConfig::GeoFenceConfig(QWidget *parent) : QWidget(parent) +{ + ui.setupUi(this); +} + +GeoFenceConfig::~GeoFenceConfig() +{ +} diff --git a/src/ui/configuration/GeoFenceConfig.h b/src/ui/configuration/GeoFenceConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..71624346d7c009b4284bb06937bccfb5e7772026 --- /dev/null +++ b/src/ui/configuration/GeoFenceConfig.h @@ -0,0 +1,19 @@ +#ifndef GEOFENCECONFIG_H +#define GEOFENCECONFIG_H + +#include +#include "ui_GeoFenceConfig.h" + +class GeoFenceConfig : public QWidget +{ + Q_OBJECT + +public: + explicit GeoFenceConfig(QWidget *parent = 0); + ~GeoFenceConfig(); + +private: + Ui::GeoFenceConfig ui; +}; + +#endif // GEOFENCECONFIG_H diff --git a/src/ui/configuration/GeoFenceConfig.ui b/src/ui/configuration/GeoFenceConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..b51ea2e5083aa2ffe8cedff24cf37228206d76a8 --- /dev/null +++ b/src/ui/configuration/GeoFenceConfig.ui @@ -0,0 +1,32 @@ + + + GeoFenceConfig + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + 20 + 20 + 141 + 51 + + + + <h2>Geo Fence</h2> + + + + + + diff --git a/src/ui/configuration/OpticalFlowConfig.cc b/src/ui/configuration/OpticalFlowConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..3e8bdb8b78b55ab58111f28ac837b652194720da --- /dev/null +++ b/src/ui/configuration/OpticalFlowConfig.cc @@ -0,0 +1,37 @@ +#include "OpticalFlowConfig.h" +#include + +OpticalFlowConfig::OpticalFlowConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + connect(ui.enableCheckBox,SIGNAL(clicked(bool)),this,SLOT(enableCheckBoxClicked(bool))); + initConnections(); +} + +OpticalFlowConfig::~OpticalFlowConfig() +{ +} +void OpticalFlowConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (parameterName == "FLOW_ENABLE") + { + if (value.toInt() == 0) + { + ui.enableCheckBox->setChecked(false); + } + else + { + ui.enableCheckBox->setChecked(true); + } + } +} + +void OpticalFlowConfig::enableCheckBoxClicked(bool checked) +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,"FLOW_ENABLE",checked ? 1 : 0); +} diff --git a/src/ui/configuration/OpticalFlowConfig.h b/src/ui/configuration/OpticalFlowConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..38b4ae7ebb83f565a80a315ad11d870bf89fc0f3 --- /dev/null +++ b/src/ui/configuration/OpticalFlowConfig.h @@ -0,0 +1,22 @@ +#ifndef OPTICALFLOWCONFIG_H +#define OPTICALFLOWCONFIG_H + +#include +#include "AP2ConfigWidget.h" +#include "ui_OpticalFlowConfig.h" + +class OpticalFlowConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit OpticalFlowConfig(QWidget *parent = 0); + ~OpticalFlowConfig(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void enableCheckBoxClicked(bool checked); +private: + Ui::OpticalFlowConfig ui; +}; + +#endif // OPTICALFLOWCONFIG_H diff --git a/src/ui/configuration/OpticalFlowConfig.ui b/src/ui/configuration/OpticalFlowConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..e5a5bce4c6406af6cb060bce8447517871586632 --- /dev/null +++ b/src/ui/configuration/OpticalFlowConfig.ui @@ -0,0 +1,69 @@ + + + OpticalFlowConfig + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + 20 + 20 + 131 + 31 + + + + <h2>Optical Flow</h2> + + + false + + + + + + 100 + 60 + 70 + 17 + + + + Enable + + + + + + 10 + 60 + 81 + 71 + + + + + + + :/files/images/devices/BR-0016-01-3T.jpg + + + true + + + + + + + + diff --git a/src/ui/configuration/OsdConfig.cc b/src/ui/configuration/OsdConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..e3280a9c86607e1de0d99c300cba22691a425341 --- /dev/null +++ b/src/ui/configuration/OsdConfig.cc @@ -0,0 +1,30 @@ +#include "OsdConfig.h" +#include + +OsdConfig::OsdConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + connect(ui.enablePushButton,SIGNAL(clicked()),this,SLOT(enableButtonClicked())); + initConnections(); + +} + +OsdConfig::~OsdConfig() +{ +} +void OsdConfig::enableButtonClicked() +{ + if (!m_uas) + { + showNullMAVErrorMessageBox(); + return; + } + m_uas->getParamManager()->setParameter(1,"SR0_EXT_STAT",2); + m_uas->getParamManager()->setParameter(1,"SR0_EXTRA1",10); + m_uas->getParamManager()->setParameter(1,"SR0_EXTRA2",10); + m_uas->getParamManager()->setParameter(1,"SR0_EXTRA3",2); + m_uas->getParamManager()->setParameter(1,"SR0_POSITION",3); + m_uas->getParamManager()->setParameter(1,"SR0_RAW_CTRL",2); + m_uas->getParamManager()->setParameter(1,"SR0_RAW_SENS",2); + m_uas->getParamManager()->setParameter(1,"SR0_RC_CHAN",2); +} diff --git a/src/ui/configuration/OsdConfig.h b/src/ui/configuration/OsdConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..963fa0dd1a507b8f1d0f1a4e9ad072326d11512b --- /dev/null +++ b/src/ui/configuration/OsdConfig.h @@ -0,0 +1,21 @@ +#ifndef OSDCONFIG_H +#define OSDCONFIG_H + +#include +#include "AP2ConfigWidget.h" +#include "ui_OsdConfig.h" + +class OsdConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit OsdConfig(QWidget *parent = 0); + ~OsdConfig(); +private slots: + void enableButtonClicked(); +private: + Ui::OsdConfig ui; +}; + +#endif // OSDCONFIG_H diff --git a/src/ui/configuration/OsdConfig.ui b/src/ui/configuration/OsdConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..6c9e4d7aece4e8246d56d24fd691a2e4e06b94d6 --- /dev/null +++ b/src/ui/configuration/OsdConfig.ui @@ -0,0 +1,85 @@ + + + OsdConfig + + + + 0 + 0 + 499 + 243 + + + + Form + + + + + 20 + 20 + 131 + 31 + + + + <h2>OSD</h2> + + + false + + + + + + 10 + 60 + 101 + 41 + + + + + + + :/files/images/devices/MinimOSD.jpg + + + true + + + + + + 230 + 60 + 191 + 41 + + + + You only need to use this if you are +having issue with your OSD not +updating + + + + + + 120 + 60 + 91 + 41 + + + + Enable +Telemetry + + + + + + + + diff --git a/src/ui/configuration/ParamWidget.cc b/src/ui/configuration/ParamWidget.cc new file mode 100644 index 0000000000000000000000000000000000000000..b9fb03c72671989e039a4bc732230974735b0083 --- /dev/null +++ b/src/ui/configuration/ParamWidget.cc @@ -0,0 +1,139 @@ +#include "ParamWidget.h" + +ParamWidget::ParamWidget(QString param,QWidget *parent) : QWidget(parent) +{ + ui.setupUi(this); + m_param = param; + + connect(ui.doubleSpinBox,SIGNAL(editingFinished()),this,SLOT(doubleSpinEditFinished())); + connect(ui.intSpinBox,SIGNAL(editingFinished()),this,SLOT(intSpinEditFinished())); + connect(ui.valueComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(comboIndexChanged(int))); + connect(ui.valueSlider,SIGNAL(sliderReleased()),this,SLOT(valueSliderReleased())); +} +void ParamWidget::doubleSpinEditFinished() +{ + ui.valueSlider->setValue(((ui.doubleSpinBox->value() - m_min) / (m_max - m_min)) * 100.0); + emit doubleValueChanged(m_param,ui.doubleSpinBox->value()); +} + +void ParamWidget::intSpinEditFinished() +{ + ui.valueSlider->setValue(((ui.intSpinBox->value() - m_min) / (m_max - m_min)) * 100.0); + emit intValueChanged(m_param,ui.intSpinBox->value()); +} + +void ParamWidget::comboIndexChanged(int index) +{ + emit intValueChanged(m_param,m_valueList[index].first); +} + +void ParamWidget::valueSliderReleased() +{ + //Set the spin box, and emit a signal. + if (type == INT) + { + ui.intSpinBox->setValue(((ui.valueSlider->value() / 100.0) * (m_max - m_min)) + m_min); + emit intValueChanged(m_param,ui.intSpinBox->value()); + } + else if (type == DOUBLE) + { + ui.doubleSpinBox->setValue(((ui.valueSlider->value() / 100.0) * (m_max - m_min)) + m_min); + emit doubleValueChanged(m_param,ui.doubleSpinBox->value()); + } +} + +ParamWidget::~ParamWidget() +{ +} + +void ParamWidget::setupInt(QString title,QString description,int value,int min,int max) +{ + type = INT; + ui.titleLabel->setText("

" + title + "

"); + ui.descriptionLabel->setText(description); + ui.valueComboBox->hide(); + ui.valueSlider->show(); + ui.intSpinBox->show(); + ui.doubleSpinBox->hide(); + if (min == 0 && max == 0) + { + m_min = 0; + m_max = 65535; + } + else + { + m_min = min; + m_max = max; + } + ui.intSpinBox->setMinimum(m_min); + ui.intSpinBox->setMaximum(m_max); +} + +void ParamWidget::setupDouble(QString title,QString description,double value,double min,double max) +{ + type = DOUBLE; + ui.titleLabel->setText("

" + title + "

"); + ui.descriptionLabel->setText(description); + ui.valueComboBox->hide(); + ui.valueSlider->show(); + ui.intSpinBox->hide(); + ui.doubleSpinBox->show(); + if (min == 0 && max == 0) + { + m_min = 0; + m_max = 65535; + } + else + { + m_min = min; + m_max = max; + } + ui.doubleSpinBox->setMinimum(m_min); + ui.doubleSpinBox->setMaximum(m_max); +} + +void ParamWidget::setupCombo(QString title,QString description,QList > list) +{ + type = COMBO; + ui.titleLabel->setText("

" + title + "

"); + ui.descriptionLabel->setText(description); + ui.valueComboBox->show(); + ui.valueSlider->hide(); + ui.intSpinBox->hide(); + ui.doubleSpinBox->hide(); + m_valueList = list; + ui.valueComboBox->clear(); + disconnect(ui.valueComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(comboIndexChanged(int))); + for (int i=0;iaddItem(m_valueList[i].second); + } + connect(ui.valueComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(comboIndexChanged(int))); +} + +void ParamWidget::setValue(double value) +{ + if (type == INT) + { + ui.intSpinBox->setValue(value); + ui.valueSlider->setValue(((value - m_min) / (m_max - m_min)) * 100.0); + } + else if (type == DOUBLE) + { + ui.doubleSpinBox->setValue(value); + ui.valueSlider->setValue(((value - m_min) / (m_max - m_min)) * 100.0); + } + else if (type == COMBO) + { + for (int i=0;isetCurrentIndex(i); + connect(ui.valueComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(comboIndexChanged(int))); + return; + } + } + } +} diff --git a/src/ui/configuration/ParamWidget.h b/src/ui/configuration/ParamWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..68a3efbf4c6ac2586e056be69c08622a91ca8551 --- /dev/null +++ b/src/ui/configuration/ParamWidget.h @@ -0,0 +1,43 @@ +#ifndef PARAMWIDGET_H +#define PARAMWIDGET_H + +#include +#include "ui_ParamWidget.h" + +class ParamWidget : public QWidget +{ + Q_OBJECT + +public: + explicit ParamWidget(QString param,QWidget *parent = 0); + ~ParamWidget(); + void setupInt(QString title,QString description,int value,int min,int max); + void setupDouble(QString title,QString description,double value,double min,double max); + void setupCombo(QString title,QString description,QList > list); + void setValue(double value); +signals: + void doubleValueChanged(QString param,double value); + void intValueChanged(QString param,int value); +private slots: + void doubleSpinEditFinished(); + void intSpinEditFinished(); + void comboIndexChanged(int index); + void valueSliderReleased(); +private: + QString m_param; + enum VIEWTYPE + { + INT, + DOUBLE, + COMBO + }; + double m_min; + double m_max; + double m_dvalue; + int m_ivalue; + VIEWTYPE type; + QList > m_valueList; + Ui::ParamWidget ui; +}; + +#endif // PARAMWIDGET_H diff --git a/src/ui/configuration/ParamWidget.ui b/src/ui/configuration/ParamWidget.ui new file mode 100644 index 0000000000000000000000000000000000000000..8e396cb6fee1c0702dcf8dd1bfe2c66eeffb3331 --- /dev/null +++ b/src/ui/configuration/ParamWidget.ui @@ -0,0 +1,81 @@ + + + ParamWidget + + + + 0 + 0 + 619 + 207 + + + + Form + + + + + + + + TextLabel + + + + + + + TextLabel + + + true + + + + + + + + + + + + + + + 100 + + + 0 + + + Qt::Horizontal + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + diff --git a/src/ui/configuration/Radio3DRConfig.cc b/src/ui/configuration/Radio3DRConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..435ae290f92f2bc05c417f86c3c8716b810a2946 --- /dev/null +++ b/src/ui/configuration/Radio3DRConfig.cc @@ -0,0 +1,11 @@ +#include "Radio3DRConfig.h" + + +Radio3DRConfig::Radio3DRConfig(QWidget *parent) : QWidget(parent) +{ + ui.setupUi(this); +} + +Radio3DRConfig::~Radio3DRConfig() +{ +} diff --git a/src/ui/configuration/Radio3DRConfig.h b/src/ui/configuration/Radio3DRConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..5233921d1592ca7aae68fbe9642c2a9c08fa3708 --- /dev/null +++ b/src/ui/configuration/Radio3DRConfig.h @@ -0,0 +1,19 @@ +#ifndef RADIO3DRCONFIG_H +#define RADIO3DRCONFIG_H + +#include +#include "ui_Radio3DRConfig.h" + +class Radio3DRConfig : public QWidget +{ + Q_OBJECT + +public: + explicit Radio3DRConfig(QWidget *parent = 0); + ~Radio3DRConfig(); + +private: + Ui::Radio3DRConfig ui; +}; + +#endif // RADIO3DRCONFIG_H diff --git a/src/ui/configuration/Radio3DRConfig.ui b/src/ui/configuration/Radio3DRConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..7a98b9dba7db8ce30c2de14706483a9924b6076d --- /dev/null +++ b/src/ui/configuration/Radio3DRConfig.ui @@ -0,0 +1,35 @@ + + + Radio3DRConfig + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + 20 + 20 + 131 + 31 + + + + <h2>3DR Radio</h2> + + + false + + + + + + diff --git a/src/ui/configuration/RadioCalibrationConfig.cc b/src/ui/configuration/RadioCalibrationConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..eb9db6fca9bfb4c71df52145f285616ed995c122 --- /dev/null +++ b/src/ui/configuration/RadioCalibrationConfig.cc @@ -0,0 +1,245 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2013 Michael Carpenter (malcom2073@gmail.com) + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL 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 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Radio Calibration Configuration source. + * + * @author Michael Carpenter + * + */ + +#include "RadioCalibrationConfig.h" +#include + +RadioCalibrationConfig::RadioCalibrationConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + + connect(ui.calibrateButton,SIGNAL(clicked()),this,SLOT(calibrateButtonClicked())); + m_calibrationEnabled = false; + ui.rollWidget->setMin(800); + ui.rollWidget->setMax(2200); + ui.pitchWidget->setMin(800); + ui.pitchWidget->setMax(2200); + ui.throttleWidget->setMin(800); + ui.throttleWidget->setMax(2200); + ui.yawWidget->setMin(800); + ui.yawWidget->setMax(2200); + ui.radio5Widget->setMin(800); + ui.radio5Widget->setMax(2200); + ui.radio6Widget->setMin(800); + ui.radio6Widget->setMax(2200); + ui.radio7Widget->setMin(800); + ui.radio7Widget->setMax(2200); + ui.radio8Widget->setMin(800); + ui.radio8Widget->setMax(2200); + ui.rollWidget->setOrientation(Qt::Horizontal); + ui.rollWidget->setName("Roll"); + ui.yawWidget->setOrientation(Qt::Horizontal); + ui.yawWidget->setName("Yaw"); + ui.pitchWidget->setName("Pitch"); + ui.throttleWidget->setName("Throttle"); + ui.radio5Widget->setOrientation(Qt::Horizontal); + ui.radio5Widget->setName("Radio 5"); + ui.radio6Widget->setOrientation(Qt::Horizontal); + ui.radio6Widget->setName("Radio 6"); + ui.radio7Widget->setOrientation(Qt::Horizontal); + ui.radio7Widget->setName("Radio 7"); + ui.radio8Widget->setOrientation(Qt::Horizontal); + ui.radio8Widget->setName("Radio 8"); + + guiUpdateTimer = new QTimer(this); + connect(guiUpdateTimer,SIGNAL(timeout()),this,SLOT(guiUpdateTimerTick())); + + rcMin << 1100.0 << 1100.0 << 1100.0 << 1100.0 << 1100.0 << 1100.0 << 1100.0 << 1100.0; + rcMax << 1900.0 << 1900.0 << 1900.0 << 1900.0 << 1900.0 << 1900.0 << 1900.0 << 1900.0; + rcTrim << 1500.0 << 1500.0 << 1500.0 << 1500.0 << 1500.0 << 1500.0 << 1500.0 << 1500.0; + rcValue << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0; + + initConnections(); +} + +RadioCalibrationConfig::~RadioCalibrationConfig() +{ +} +void RadioCalibrationConfig::activeUASSet(UASInterface *uas) +{ + if (m_uas) + { + disconnect(m_uas, SIGNAL(remoteControlChannelRawChanged(int,float)), this,SLOT(remoteControlChannelRawChanged(int,float))); + } + AP2ConfigWidget::activeUASSet(uas); + if (!uas) + { + return; + } + connect(m_uas,SIGNAL(remoteControlChannelRawChanged(int,float)),this,SLOT(remoteControlChannelRawChanged(int,float))); +} +void RadioCalibrationConfig::remoteControlChannelRawChanged(int chan,float val) +{ + + //Channel is 0-7 typically? + //Val will be 0-3000, PWM value. + if (m_calibrationEnabled) { + if (val < rcMin[chan]) + { + rcMin[chan] = val; + } + + if (val > rcMax[chan]) + { + rcMax[chan] = val; + } + } + + // Raw value + rcValue[chan] = val; +} + +void RadioCalibrationConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + +} +void RadioCalibrationConfig::guiUpdateTimerTick() +{ + ui.rollWidget->setValue(rcValue[0]); + ui.pitchWidget->setValue(rcValue[1]); + ui.throttleWidget->setValue(rcValue[2]); + ui.yawWidget->setValue(rcValue[3]); + ui.radio5Widget->setValue(rcValue[4]); + ui.radio6Widget->setValue(rcValue[5]); + ui.radio7Widget->setValue(rcValue[6]); + ui.radio8Widget->setValue(rcValue[7]); + if (m_calibrationEnabled) + { + ui.rollWidget->setMin(rcMin[0]); + ui.rollWidget->setMax(rcMax[0]); + ui.pitchWidget->setMin(rcMin[1]); + ui.pitchWidget->setMax(rcMax[1]); + ui.throttleWidget->setMin(rcMin[2]); + ui.throttleWidget->setMax(rcMax[2]); + ui.yawWidget->setMin(rcMin[3]); + ui.yawWidget->setMax(rcMax[3]); + ui.radio5Widget->setMin(rcMin[4]); + ui.radio5Widget->setMax(rcMax[4]); + ui.radio6Widget->setMin(rcMin[5]); + ui.radio6Widget->setMax(rcMax[5]); + ui.radio7Widget->setMin(rcMin[6]); + ui.radio7Widget->setMax(rcMax[6]); + ui.radio8Widget->setMin(rcMin[7]); + ui.radio8Widget->setMax(rcMax[7]); + } +} +void RadioCalibrationConfig::showEvent(QShowEvent *event) +{ + guiUpdateTimer->start(100); +} +void RadioCalibrationConfig::hideEvent(QHideEvent *event) +{ + guiUpdateTimer->stop(); +} +void RadioCalibrationConfig::calibrateButtonClicked() +{ + if (!m_calibrationEnabled) + { + ui.calibrateButton->setText("End Calibration"); + QMessageBox::information(0,"Warning!","You are about to start radio calibration.\nPlease ensure all motor power is disconnected AND all props are removed from the vehicle.\nAlso ensure transmitter and reciever are powered and connected\n\nClick OK to confirm"); + m_calibrationEnabled = true; + for (int i=0;i<8;i++) + { + rcMin[i] = 1500; + rcMax[i] = 1500; + } + ui.rollWidget->showMinMax(); + ui.pitchWidget->showMinMax(); + ui.yawWidget->showMinMax(); + ui.radio5Widget->showMinMax(); + ui.radio6Widget->showMinMax(); + ui.radio7Widget->showMinMax(); + ui.throttleWidget->showMinMax(); + ui.radio8Widget->showMinMax(); + QMessageBox::information(0,"Information","Click OK, then move all sticks to their extreme positions, watching the min/max values to ensure you get the most range from your controller. This includes all switches"); + } + else + { + ui.calibrateButton->setText("Calibrate"); + QMessageBox::information(0,"Trims","Ensure all sticks are centered and throttle is in the downmost position, click OK to continue"); + ///TODO: Set trims! + m_calibrationEnabled = false; + ui.rollWidget->hideMinMax(); + ui.pitchWidget->hideMinMax(); + ui.yawWidget->hideMinMax(); + ui.radio5Widget->hideMinMax(); + ui.radio6Widget->hideMinMax(); + ui.throttleWidget->hideMinMax(); + ui.radio7Widget->hideMinMax(); + ui.radio8Widget->hideMinMax(); + QString statusstr; + statusstr = "Below you will find the detected radio calibration information that will be sent to the autopilot\n"; + statusstr += "Normal values are around 1100 to 1900, with disconnected channels reading very close to 1500\n\n"; + statusstr += "Channel\tMin\tCenter\tMax\n"; + statusstr += "--------------------\n"; + for (int i=0;i<8;i++) + { + statusstr += QString::number(i) + "\t" + QString::number(rcMin[i]) + "\t" + QString::number(rcValue[i]) + "\t" + QString::number(rcMax[i]) + "\n"; + } + QMessageBox::information(0,"Status",statusstr); + //Send calibrations. + QString minTpl("RC%1_MIN"); + QString maxTpl("RC%1_MAX"); + //QString trimTpl("RC%1_TRIM"); + + // Do not write the RC type, as these values depend on this + // active onboard parameter + + for (unsigned int i = 0; i < 8; ++i) + { + qDebug() << "SENDING MIN" << minTpl.arg(i+1) << rcMin[i]; + qDebug() << "SENDING MAX" << maxTpl.arg(i+1) << rcMax[i]; + m_uas->getParamManager()->setParameter(1, minTpl.arg(i+1), (float)rcMin[i]); + QGC::SLEEP::usleep(50000); + //m_uas->setParameter(0, trimTpl.arg(i+1), rcTrim[i]); + //QGC::SLEEP::usleep(50000); + m_uas->getParamManager()->setParameter(1, maxTpl.arg(i+1), (float)rcMax[i]); + QGC::SLEEP::usleep(50000); + } + ui.rollWidget->setMin(800); + ui.rollWidget->setMax(2200); + ui.pitchWidget->setMin(800); + ui.pitchWidget->setMax(2200); + ui.throttleWidget->setMin(800); + ui.throttleWidget->setMax(2200); + ui.yawWidget->setMin(800); + ui.yawWidget->setMax(2200); + ui.radio5Widget->setMin(800); + ui.radio5Widget->setMax(2200); + ui.radio6Widget->setMin(800); + ui.radio6Widget->setMax(2200); + ui.radio7Widget->setMin(800); + ui.radio7Widget->setMax(2200); + ui.radio8Widget->setMin(800); + ui.radio8Widget->setMax(2200); + + } +} diff --git a/src/ui/configuration/RadioCalibrationConfig.h b/src/ui/configuration/RadioCalibrationConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..00b90f8e20970fd1f2b3d7bf313149727f741758 --- /dev/null +++ b/src/ui/configuration/RadioCalibrationConfig.h @@ -0,0 +1,73 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2013 Michael Carpenter (malcom2073@gmail.com) + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL 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 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Radio Calibration Configuration widget header. + * + * @author Michael Carpenter + * + */ + +#ifndef RADIOCALIBRATIONCONFIG_H +#define RADIOCALIBRATIONCONFIG_H + +#include +#include +#include +#include +#include "ui_RadioCalibrationConfig.h" +#include "UASManager.h" +#include "UASInterface.h" +#include "AP2ConfigWidget.h" +class RadioCalibrationConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit RadioCalibrationConfig(QWidget *parent = 0); + ~RadioCalibrationConfig(); +protected: + void showEvent(QShowEvent *event); + void hideEvent(QHideEvent *event); +private slots: + void activeUASSet(UASInterface *uas); + void remoteControlChannelRawChanged(int chan,float val); + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void guiUpdateTimerTick(); + void calibrateButtonClicked(); +private: + QList rcMin; + QList rcMax; + QList rcTrim; + QList rcValue; + //double rcMin[8]; + //double rcMax[8]; + //double rcTrim[8]; + //double rcValue[8]; + QTimer *guiUpdateTimer; + bool m_calibrationEnabled; + Ui::RadioCalibrationConfig ui; +}; + +#endif // RADIOCALIBRATIONCONFIG_H diff --git a/src/ui/configuration/RadioCalibrationConfig.ui b/src/ui/configuration/RadioCalibrationConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..ccf80621198ef28a53d60e967e397d0e811d5bb5 --- /dev/null +++ b/src/ui/configuration/RadioCalibrationConfig.ui @@ -0,0 +1,280 @@ + + + RadioCalibrationConfig + + + + 0 + 0 + 771 + 389 + + + + Form + + + + + 10 + 10 + 171 + 31 + + + + <h2>Radio Calibration</h2> + + + false + + + + + + 10 + 50 + 716 + 300 + + + + + QLayout::SetMinAndMaxSize + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 50 + 200 + + + + + 50 + 200 + + + + + + + + Qt::Horizontal + + + + 250 + 20 + + + + + + + + + 50 + 200 + + + + + 50 + 200 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + + + + + + + + 250 + 40 + + + + + 250 + 40 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 20 + 360 + 91 + 23 + + + + Calibrate + + + + + + QGCRadioChannelDisplay + QWidget +
ui/designer/QGCRadioChannelDisplay.h
+ 1 +
+
+ + +
diff --git a/src/ui/configuration/SerialSettingsDialog.cc b/src/ui/configuration/SerialSettingsDialog.cc new file mode 100644 index 0000000000000000000000000000000000000000..fbb8d2da60eb93687ba0c3a0c73a4297f7d32246 --- /dev/null +++ b/src/ui/configuration/SerialSettingsDialog.cc @@ -0,0 +1,189 @@ +/*===================================================================== + +APM_PLANNER Open Source Ground Control Station + +(c) 2013, Bill Bonney + +This file is part of the APM_PLANNER project + + APM_PLANNER 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 3 of the License, or + (at your option) any later version. + + APM_PLANNER 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 APM_PLANNER. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Serial Settings View. + * + * @author Bill Bonney + * + * Influenced from Qt examples by :- + * Copyright (C) 2012 Denis Shienkov + * Copyright (C) 2012 Laszlo Papp + * + */ + +#include "SerialSettingsDialog.h" +#include "terminalconsole.h" +#include "ui_SerialSettingsDialog.h" + +#include +#include +#include +#include + +QT_USE_NAMESPACE + +SettingsDialog::SettingsDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::SettingsDialog) +{ + ui->setupUi(this); + + m_intValidator = new QIntValidator(0, 4000000, this); + + ui->baudRateBox->setInsertPolicy(QComboBox::NoInsert); + + connect(ui->applyButton, SIGNAL(clicked()), + this, SLOT(apply())); + connect(ui->serialPortInfoListBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(showPortInfo(int))); + connect(ui->baudRateBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(checkCustomBaudRatePolicy(int))); + + fillPortsParameters(); + fillPortsInfo(); + + updateSettings(); +} + +SettingsDialog::~SettingsDialog() +{ + delete ui; +} + +const SerialSettings& SettingsDialog::settings() const +{ + return m_currentSettings; +} + +void SettingsDialog::showPortInfo(int idx) +{ + if (idx != -1) { + QStringList list = ui->serialPortInfoListBox->itemData(idx).toStringList(); + ui->descriptionLabel->setText(tr("Description: %1").arg(list.at(1))); + ui->manufacturerLabel->setText(tr("Manufacturer: %1").arg(list.at(2))); + ui->locationLabel->setText(tr("Location: %1").arg(list.at(3))); + ui->vidLabel->setText(tr("Vendor Identifier: %1").arg(list.at(4))); + ui->pidLabel->setText(tr("Product Identifier: %1").arg(list.at(5))); + } +} + +void SettingsDialog::apply() +{ + updateSettings(); + hide(); +} + +void SettingsDialog::checkCustomBaudRatePolicy(int idx) +{ + bool isCustomBaudRate = !ui->baudRateBox->itemData(idx).isValid(); + ui->baudRateBox->setEditable(isCustomBaudRate); + if (isCustomBaudRate) { + ui->baudRateBox->clearEditText(); + QLineEdit *edit = ui->baudRateBox->lineEdit(); + edit->setValidator(m_intValidator); + } +} + +void SettingsDialog::fillPortsParameters() +{ + // fill baud rate (is not the entire list of available values, + // desired values??, add your independently) + ui->baudRateBox->addItem(QLatin1String("115200"), QSerialPort::Baud115200); + ui->baudRateBox->addItem(QLatin1String("57600"), QSerialPort::Baud57600); + ui->baudRateBox->addItem(QLatin1String("38400"), QSerialPort::Baud38400); + ui->baudRateBox->addItem(QLatin1String("19200"), QSerialPort::Baud19200); + ui->baudRateBox->addItem(QLatin1String("19200"), QSerialPort::Baud19200); + ui->baudRateBox->addItem(QLatin1String("9600"), QSerialPort::Baud9600); + ui->baudRateBox->addItem(QLatin1String("Custom")); + + // fill data bits + ui->dataBitsBox->addItem(QLatin1String("5"), QSerialPort::Data5); + ui->dataBitsBox->addItem(QLatin1String("6"), QSerialPort::Data6); + ui->dataBitsBox->addItem(QLatin1String("7"), QSerialPort::Data7); + ui->dataBitsBox->addItem(QLatin1String("8"), QSerialPort::Data8); + ui->dataBitsBox->setCurrentIndex(3); + + // fill parity + ui->parityBox->addItem(QLatin1String("None"), QSerialPort::NoParity); + ui->parityBox->addItem(QLatin1String("Even"), QSerialPort::EvenParity); + ui->parityBox->addItem(QLatin1String("Odd"), QSerialPort::OddParity); + ui->parityBox->addItem(QLatin1String("Mark"), QSerialPort::MarkParity); + ui->parityBox->addItem(QLatin1String("Space"), QSerialPort::SpaceParity); + + // fill stop bits + ui->stopBitsBox->addItem(QLatin1String("1"), QSerialPort::OneStop); +#ifdef Q_OS_WIN + ui->stopBitsBox->addItem(QLatin1String("1.5"), QSerialPort::OneAndHalfStop); +#endif + ui->stopBitsBox->addItem(QLatin1String("2"), QSerialPort::TwoStop); + + // fill flow control + ui->flowControlBox->addItem(QLatin1String("None"), QSerialPort::NoFlowControl); + ui->flowControlBox->addItem(QLatin1String("RTS/CTS"), QSerialPort::HardwareControl); + ui->flowControlBox->addItem(QLatin1String("XON/XOFF"), QSerialPort::SoftwareControl); +} + +void SettingsDialog::fillPortsInfo() +{ + ui->serialPortInfoListBox->clear(); + foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { + QStringList list; + list << info.portName() + << info.description() + << info.manufacturer() + << info.systemLocation() + << (info.vendorIdentifier() ? QString::number(info.vendorIdentifier(), 16) : QString()) + << (info.productIdentifier() ? QString::number(info.productIdentifier(), 16) : QString()); + + ui->serialPortInfoListBox->insertItem(0, list.first(), list); + } +} + +void SettingsDialog::updateSettings() +{ + m_currentSettings.name = ui->serialPortInfoListBox->currentText(); + + // Baud Rate + if (ui->baudRateBox->currentIndex() == 4) { + // custom baud rate + m_currentSettings.baudRate = ui->baudRateBox->currentText().toInt(); + } else { + // standard baud rate + m_currentSettings.baudRate = static_cast( + ui->baudRateBox->itemData(ui->baudRateBox->currentIndex()).toInt()); + } + // Data bits + m_currentSettings.dataBits = static_cast( + ui->dataBitsBox->itemData(ui->dataBitsBox->currentIndex()).toInt()); + // Parity + m_currentSettings.parity = static_cast( + ui->parityBox->itemData(ui->parityBox->currentIndex()).toInt()); + // Stop bits + m_currentSettings.stopBits = static_cast( + ui->stopBitsBox->itemData(ui->stopBitsBox->currentIndex()).toInt()); + // Flow control + m_currentSettings.flowControl = static_cast( + ui->flowControlBox->itemData(ui->flowControlBox->currentIndex()).toInt()); +} diff --git a/src/ui/configuration/SerialSettingsDialog.h b/src/ui/configuration/SerialSettingsDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..5b1586fdf2ffe3f55830639a3e8b8f556209a513 --- /dev/null +++ b/src/ui/configuration/SerialSettingsDialog.h @@ -0,0 +1,91 @@ +/*===================================================================== + +APM_PLANNER Open Source Ground Control Station + +(c) 2013, Bill Bonney + +This file is part of the APM_PLANNER project + + APM_PLANNER 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 3 of the License, or + (at your option) any later version. + + APM_PLANNER 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 APM_PLANNER. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Serial Settings View. + * + * @author Bill Bonney + * + * Influenced from Qt examples by :- + * Copyright (C) 2012 Denis Shienkov + * Copyright (C) 2012 Laszlo Papp + * + */ + +#ifndef SETTINGSDIALOG_H +#define SETTINGSDIALOG_H + +#include +#include + +namespace Ui { +class SettingsDialog; +} + +class QIntValidator; + +class SerialSettings { +public: + SerialSettings() : name(""), + baudRate(115200), + dataBits(QSerialPort::Data8), + parity(QSerialPort::NoParity), + stopBits(QSerialPort::OneStop), + flowControl(QSerialPort::NoFlowControl){} +public: + QString name; + qint32 baudRate; + QSerialPort::DataBits dataBits; + QSerialPort::Parity parity; + QSerialPort::StopBits stopBits; + QSerialPort::FlowControl flowControl; +}; + +class SettingsDialog : public QDialog +{ + Q_OBJECT + +public: + explicit SettingsDialog(QWidget *parent = 0); + ~SettingsDialog(); + + const SerialSettings &settings() const; + +private slots: + void showPortInfo(int idx); + void apply(); + void checkCustomBaudRatePolicy(int idx); + +private: + void fillPortsParameters(); + void fillPortsInfo(); + void updateSettings(); + +private: + Ui::SettingsDialog *ui; + SerialSettings m_currentSettings; + QIntValidator *m_intValidator; +}; + +#endif // SETTINGSDIALOG_H diff --git a/src/ui/configuration/SerialSettingsDialog.ui b/src/ui/configuration/SerialSettingsDialog.ui new file mode 100644 index 0000000000000000000000000000000000000000..5f2706fa2868f99f6775ea2375668e9fa54f5fa5 --- /dev/null +++ b/src/ui/configuration/SerialSettingsDialog.ui @@ -0,0 +1,151 @@ + + + SettingsDialog + + + + 0 + 0 + 401 + 250 + + + + Settings + + + + + + Select Serial Port + + + + + + + + + Description: + + + + + + + Manufacturer: + + + + + + + Location: + + + + + + + Vendor ID: + + + + + + + Product ID: + + + + + + + + + + + + Qt::Horizontal + + + + 96 + 20 + + + + + + + + Apply + + + + + + + + + Select Parameters + + + + + + BaudRate: + + + + + + + + + + Data bits: + + + + + + + + + + Parity: + + + + + + + + + + Stop bits: + + + + + + + + + + Flow control: + + + + + + + + + + + + + + diff --git a/src/ui/configuration/SonarConfig.cc b/src/ui/configuration/SonarConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..fb8c4687b03dc6a2b69df6c398cee064de6f381f --- /dev/null +++ b/src/ui/configuration/SonarConfig.cc @@ -0,0 +1,69 @@ +#include "SonarConfig.h" +#include + +SonarConfig::SonarConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + ui.sonarTypeComboBox->addItem("XL-EZ0 / XL-EZ4"); + ui.sonarTypeComboBox->addItem("LV-EZ0"); + ui.sonarTypeComboBox->addItem("XL-EZL0"); + ui.sonarTypeComboBox->addItem("HRLV"); + connect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(checkBoxToggled(bool))); + connect(ui.sonarTypeComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(sonarTypeChanged(int))); + + initConnections(); +} + +SonarConfig::~SonarConfig() +{ +} +void SonarConfig::checkBoxToggled(bool enabled) +{ + if (enabled) + { + ui.sonarTypeComboBox->setEnabled(false); + } + if (!m_uas) + { + QMessageBox::information(0,tr("Error"),tr("Please connect to a MAV before attempting to set configuration")); + return; + } + m_uas->getParamManager()->setParameter(1,"SONAR_ENABLE",ui.enableCheckBox->isChecked() ? 1 : 0); +} +void SonarConfig::sonarTypeChanged(int index) +{ + if (!m_uas) + { + QMessageBox::information(0,tr("Error"),tr("Please connect to a MAV before attempting to set configuration")); + return; + } + m_uas->getParamManager()->setParameter(1,"SONAR_TYPE",ui.sonarTypeComboBox->currentIndex()); +} + +void SonarConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (parameterName == "SONAR_ENABLE") + { + if (value.toInt() == 0) + { + //Disabled + disconnect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(checkBoxToggled(bool))); + ui.enableCheckBox->setChecked(false); + connect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(checkBoxToggled(bool))); + ui.sonarTypeComboBox->setEnabled(false); + } + else + { + disconnect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(checkBoxToggled(bool))); + ui.enableCheckBox->setChecked(true); + connect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(checkBoxToggled(bool))); + ui.sonarTypeComboBox->setEnabled(true); + } + } + else if (parameterName == "SONAR_TYPE") + { + disconnect(ui.sonarTypeComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(sonarTypeChanged(int))); + ui.sonarTypeComboBox->setCurrentIndex(value.toInt()); + connect(ui.sonarTypeComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(sonarTypeChanged(int))); + } +} diff --git a/src/ui/configuration/SonarConfig.h b/src/ui/configuration/SonarConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..825591a65294e37f5359675d715103031bf601c9 --- /dev/null +++ b/src/ui/configuration/SonarConfig.h @@ -0,0 +1,23 @@ +#ifndef SONARCONFIG_H +#define SONARCONFIG_H + +#include +#include "AP2ConfigWidget.h" +#include "ui_SonarConfig.h" + +class SonarConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit SonarConfig(QWidget *parent = 0); + ~SonarConfig(); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void checkBoxToggled(bool enabled); + void sonarTypeChanged(int index); +private: + Ui::SonarConfig ui; +}; + +#endif // SONARCONFIG_H diff --git a/src/ui/configuration/SonarConfig.ui b/src/ui/configuration/SonarConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..7c40d028ce6c772db234b8972473c3ed906b7019 --- /dev/null +++ b/src/ui/configuration/SonarConfig.ui @@ -0,0 +1,79 @@ + + + SonarConfig + + + + 0 + 0 + 651 + 432 + + + + Form + + + + + 20 + 20 + 131 + 31 + + + + <h2>Sonar</h2> + + + false + + + + + + 30 + 60 + 91 + 81 + + + + + + + :/files/images/devices/AC-0004-11-2.jpg + + + true + + + + + + 140 + 60 + 70 + 17 + + + + Enable + + + + + + 150 + 100 + 171 + 22 + + + + + + + + + diff --git a/src/ui/configuration/StandardParamConfig.cc b/src/ui/configuration/StandardParamConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..0f43a922504a66928ca326e9e478525f35d58d44 --- /dev/null +++ b/src/ui/configuration/StandardParamConfig.cc @@ -0,0 +1,63 @@ +#include "StandardParamConfig.h" +#include "ParamWidget.h" +StandardParamConfig::StandardParamConfig(QWidget *parent) : AP2ConfigWidget(parent) +{ + ui.setupUi(this); + initConnections(); +} +StandardParamConfig::~StandardParamConfig() +{ +} +void StandardParamConfig::addRange(QString title,QString description,QString param,double min,double max) +{ + ParamWidget *widget = new ParamWidget(param,ui.scrollAreaWidgetContents); + connect(widget,SIGNAL(doubleValueChanged(QString,double)),this,SLOT(doubleValueChanged(QString,double))); + connect(widget,SIGNAL(intValueChanged(QString,int)),this,SLOT(intValueChanged(QString,int))); + paramToWidgetMap[param] = widget; + widget->setupDouble(title + "(" + param + ")",description,0,min,max); + ui.verticalLayout->addWidget(widget); + widget->show(); +} + +void StandardParamConfig::addCombo(QString title,QString description,QString param,QList > valuelist) +{ + ParamWidget *widget = new ParamWidget(param,ui.scrollAreaWidgetContents); + connect(widget,SIGNAL(doubleValueChanged(QString,double)),this,SLOT(doubleValueChanged(QString,double))); + connect(widget,SIGNAL(intValueChanged(QString,int)),this,SLOT(intValueChanged(QString,int))); + paramToWidgetMap[param] = widget; + widget->setupCombo(title + "(" + param + ")",description,valuelist); + ui.verticalLayout->addWidget(widget); + widget->show(); +} +void StandardParamConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + if (paramToWidgetMap.contains(parameterName)) + { + if (value.type() == QVariant::Double) + { + paramToWidgetMap[parameterName]->setValue(value.toDouble()); + } + else + { + paramToWidgetMap[parameterName]->setValue(value.toInt()); + } + } +} +void StandardParamConfig::doubleValueChanged(QString param,double value) +{ + if (!m_uas) + { + this->showNullMAVErrorMessageBox(); + } + m_uas->getParamManager()->setParameter(1,param,value); +} + +void StandardParamConfig::intValueChanged(QString param,int value) +{ + if (!m_uas) + { + this->showNullMAVErrorMessageBox(); + } + m_uas->getParamManager()->setParameter(1,param,value); +} + diff --git a/src/ui/configuration/StandardParamConfig.h b/src/ui/configuration/StandardParamConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..b098d7d05e1863b1ca98c5e0bd08bf86b7ec1d0a --- /dev/null +++ b/src/ui/configuration/StandardParamConfig.h @@ -0,0 +1,26 @@ +#ifndef STANDARDPARAMCONFIG_H +#define STANDARDPARAMCONFIG_H + +#include +#include "ui_StandardParamConfig.h" +#include "AP2ConfigWidget.h" +#include "ParamWidget.h" +class StandardParamConfig : public AP2ConfigWidget +{ + Q_OBJECT + +public: + explicit StandardParamConfig(QWidget *parent = 0); + ~StandardParamConfig(); + void addRange(QString title,QString description,QString param,double min,double max); + void addCombo(QString title,QString description,QString param,QList > valuelist); +private slots: + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + void doubleValueChanged(QString param,double value); + void intValueChanged(QString param,int value); +private: + QMap paramToWidgetMap; + Ui::StandardParamConfig ui; +}; + +#endif // STANDARDPARAMCONFIG_H diff --git a/src/ui/configuration/StandardParamConfig.ui b/src/ui/configuration/StandardParamConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..53a96d984792d7aa6198efe9bfb7f3864b57c523 --- /dev/null +++ b/src/ui/configuration/StandardParamConfig.ui @@ -0,0 +1,50 @@ + + + StandardParamConfig + + + + 0 + 0 + 651 + 552 + + + + Form + + + + + + <h2>Standard Params</h2> + + + + + + + true + + + + + 0 + 0 + 631 + 505 + + + + + + + + + + + + + + + diff --git a/src/ui/configuration/TerminalConsole.cc b/src/ui/configuration/TerminalConsole.cc new file mode 100644 index 0000000000000000000000000000000000000000..1c5233e6308e15147a664309b4e533286c2df0f2 --- /dev/null +++ b/src/ui/configuration/TerminalConsole.cc @@ -0,0 +1,14 @@ +#include "terminalconsole.h" +#include "ui_terminalconsole.h" + +TerminalConsole::TerminalConsole(QWidget *parent) : + QWidget(parent), + ui(new Ui::TerminalConsole) +{ + ui->setupUi(this); +} + +TerminalConsole::~TerminalConsole() +{ + delete ui; +} diff --git a/src/ui/configuration/console.cpp b/src/ui/configuration/console.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c530af0e6c6460ae7db9c1c390a0a554951774a7 --- /dev/null +++ b/src/ui/configuration/console.cpp @@ -0,0 +1,101 @@ +/*===================================================================== + +APM_PLANNER Open Source Ground Control Station + +(c) 2013, Bill Bonney + +This file is part of the APM_PLANNER project + + APM_PLANNER 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 3 of the License, or + (at your option) any later version. + + APM_PLANNER 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 APM_PLANNER. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Text Console. + * + * @author Bill Bonney + * + * Influenced from Qt examples by :- + * Copyright (C) 2012 Denis Shienkov + * Copyright (C) 2012 Laszlo Papp + * + */ + +#include "console.h" +#include "ApmHighlighter.h" + +#include + +#include + +Console::Console(QWidget *parent) + : QPlainTextEdit(parent) + , localEchoEnabled(false) +{ + document()->setMaximumBlockCount(100); + QPalette p = palette(); + p.setColor(QPalette::Base, Qt::black); + p.setColor(QPalette::Text, Qt::green); + setPalette(p); + + m_highlighter = new APMHighlighter(document()); + +} + +void Console::putData(const QByteArray &data) +{ + insertPlainText(QString(data)); + + QScrollBar *bar = verticalScrollBar(); + bar->setValue(bar->maximum()); +} + +void Console::setLocalEchoEnabled(bool set) +{ + localEchoEnabled = set; +} + +void Console::keyPressEvent(QKeyEvent *e) +{ + switch (e->key()) { + case Qt::Key_Backspace: + case Qt::Key_Left: + case Qt::Key_Right: + case Qt::Key_Up: + case Qt::Key_Down: + // skip processing + break; + default: + if (localEchoEnabled) + QPlainTextEdit::keyPressEvent(e); + emit getData(e->text().toLocal8Bit()); + } +} + +void Console::mousePressEvent(QMouseEvent *e) +{ + Q_UNUSED(e) + setFocus(); +} + +void Console::mouseDoubleClickEvent(QMouseEvent *e) +{ + Q_UNUSED(e) +} + +void Console::contextMenuEvent(QContextMenuEvent *e) +{ + Q_UNUSED(e) +} diff --git a/src/ui/configuration/console.h b/src/ui/configuration/console.h new file mode 100644 index 0000000000000000000000000000000000000000..28a1135ded8584453f11e5a1487a90a4ebc23210 --- /dev/null +++ b/src/ui/configuration/console.h @@ -0,0 +1,69 @@ +/*===================================================================== + +APM_PLANNER Open Source Ground Control Station + +(c) 2013, Bill Bonney + +This file is part of the APM_PLANNER project + + APM_PLANNER 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 3 of the License, or + (at your option) any later version. + + APM_PLANNER 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 APM_PLANNER. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Text Console. + * + * @author Bill Bonney + * + * Influenced from Qt examples by :- + * Copyright (C) 2012 Denis Shienkov + * Copyright (C) 2012 Laszlo Papp + * + */ + +#ifndef CONSOLE_H +#define CONSOLE_H + +#include + +class APMHighlighter; + +class Console : public QPlainTextEdit +{ + Q_OBJECT + +signals: + void getData(const QByteArray &data); + +public: + explicit Console(QWidget *parent = 0); + + void putData(const QByteArray &data); + + void setLocalEchoEnabled(bool set); + +protected: + virtual void keyPressEvent(QKeyEvent *e); + virtual void mousePressEvent(QMouseEvent *e); + virtual void mouseDoubleClickEvent(QMouseEvent *e); + virtual void contextMenuEvent(QContextMenuEvent *e); + +private: + bool localEchoEnabled; + APMHighlighter* m_highlighter; + +}; + +#endif // CONSOLE_H diff --git a/src/ui/configuration/terminalconsole.cpp b/src/ui/configuration/terminalconsole.cpp new file mode 100644 index 0000000000000000000000000000000000000000..66ef5469112865cc60c6ecce7af3aaec22f9222b --- /dev/null +++ b/src/ui/configuration/terminalconsole.cpp @@ -0,0 +1,301 @@ +/*===================================================================== + +APM_PLANNER Open Source Ground Control Station + +(c) 2013, Bill Bonney + +This file is part of the APM_PLANNER project + + APM_PLANNER 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 3 of the License, or + (at your option) any later version. + + APM_PLANNER 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 APM_PLANNER. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Terminal Console display View. + * + * @author Bill Bonney + * + * Influenced from Qt examples by :- + * Copyright (C) 2012 Denis Shienkov + * Copyright (C) 2012 Laszlo Papp + * + */ + +#include "SerialSettingsDialog.h" +#include "terminalconsole.h" +#include "ui_terminalconsole.h" +#include "console.h" +#include "configuration.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +TerminalConsole::TerminalConsole(QWidget *parent) : + QWidget(parent), + ui(new Ui::TerminalConsole), + m_consoleMode(APM) +{ + ui->setupUi(this); + + // create the cosole and add it to the centralwidget + m_console = new Console; + m_console->setEnabled(false); + + m_statusBar = new QStatusBar; + + QLayout* layout = ui->terminalGroupBox->layout(); + layout->addWidget(m_console); + layout->addWidget(m_statusBar); + + m_serial = new QSerialPort(this); + m_settingsDialog = new SettingsDialog; + + ui->connectButton->setEnabled(true); + ui->disconnectButton->setEnabled(false); + ui->settingsButton->setEnabled(true); + + + addBaudComboBoxConfig(); + fillPortsInfo(*ui->linkComboBox); + + loadSettings(); + + if (m_settings.name == "") { + setLink(ui->linkComboBox->currentIndex()); + } else { + ui->linkComboBox->setCurrentIndex(0); + } + + addConsoleModesComboBoxConfig(); + + initConnections(); +} + +void TerminalConsole::addBaudComboBoxConfig() +{ + ui->consoleModeBox->addItem(QLatin1String("APM"), APM); + ui->consoleModeBox->addItem(QLatin1String("PX4"), PX4); +} + +void TerminalConsole::addConsoleModesComboBoxConfig() +{ + ui->baudComboBox->addItem(QLatin1String("115200"), QSerialPort::Baud115200); + ui->baudComboBox->addItem(QLatin1String("57600"), QSerialPort::Baud57600); + ui->baudComboBox->addItem(QLatin1String("38400"), QSerialPort::Baud38400); + ui->baudComboBox->addItem(QLatin1String("19200"), QSerialPort::Baud19200); + ui->baudComboBox->addItem(QLatin1String("19200"), QSerialPort::Baud19200); + ui->baudComboBox->addItem(QLatin1String("9600"), QSerialPort::Baud9600); +} + +void TerminalConsole::fillPortsInfo(QComboBox &comboxBox) +{ + comboxBox.clear(); + foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { + QStringList list; + list << info.portName() + << info.description() + << info.manufacturer() + << info.systemLocation() + << (info.vendorIdentifier() ? QString::number(info.vendorIdentifier(), 16) : QString()) + << (info.productIdentifier() ? QString::number(info.productIdentifier(), 16) : QString()); + + comboxBox.insertItem(0,list.first(), list); + qDebug() << "Inserting " << list.first(); + } +} + +TerminalConsole::~TerminalConsole() +{ + delete m_console; + delete m_statusBar; + delete m_settingsDialog; + delete ui; +} + +void TerminalConsole::openSerialPort() +{ + openSerialPort(m_settings); +} + +void TerminalConsole::openSerialPort(const SerialSettings &settings) +{ + m_serial->setPortName(settings.name); + if (m_serial->open(QIODevice::ReadWrite)) { + if (m_serial->setBaudRate(settings.baudRate) + && m_serial->setDataBits(settings.dataBits) + && m_serial->setParity(settings.parity) + && m_serial->setStopBits(settings.stopBits) + && m_serial->setFlowControl(settings.flowControl)) { + + m_console->setEnabled(true); + m_console->setLocalEchoEnabled(false); + ui->connectButton->setEnabled(false); + ui->disconnectButton->setEnabled(true); + ui->settingsButton->setEnabled(false); + m_statusBar->showMessage(tr("Connected to %1 : baud %2z") + .arg(settings.name).arg(QString::number(settings.baudRate))); + qDebug() << "Open Terminal Console Serial Port"; + writeSettings(); // Save last successful connection + + sendResetCommand(); + + } else { + m_serial->close(); + QMessageBox::critical(this, tr("Error"), m_serial->errorString()); + + m_statusBar->showMessage(tr("Open error")); + } + } else { + QMessageBox::critical(this, tr("Error"), m_serial->errorString()); + + m_statusBar->showMessage(tr("Configure error")); + } +} + +void TerminalConsole::closeSerialPort() +{ + m_serial->close(); + m_console->setEnabled(false); + ui->connectButton->setEnabled(true); + ui->disconnectButton->setEnabled(false); + ui->settingsButton->setEnabled(true); + m_statusBar->showMessage(tr("Disconnected")); +} + +void TerminalConsole::sendResetCommand() +{ + if (m_serial->isOpen()) { + m_serial->setDataTerminalReady(true); + m_serial->waitForBytesWritten(250); + m_serial->setDataTerminalReady(false); + } +} + +void TerminalConsole::writeData(const QByteArray &data) +{ +// qDebug() << "writeData:" << data; + m_serial->write(data); +} + +void TerminalConsole::readData() +{ + QByteArray data = m_serial->readAll(); +// qDebug() << "readData:" << data; + m_console->putData(data); + + switch(m_consoleMode) + { + case APM: // APM + // On reset, send the break sequence and display help + if (data.contains("ENTER 3")) { + m_serial->write("\r\r\r"); + m_serial->waitForBytesWritten(10); + m_serial->write("HELP\r"); + } + break; + case PX4: + // Do nothing + default: + qDebug() << "Mode not yet implemented"; + } + +} + +void TerminalConsole::handleError(QSerialPort::SerialPortError error) +{ + if (error == QSerialPort::ResourceError) { + QMessageBox::critical(this, tr("Critical Error"), m_serial->errorString()); + closeSerialPort(); + } +} + +void TerminalConsole::initConnections() +{ + // Ui Connections + connect(ui->connectButton, SIGNAL(released()), this, SLOT(openSerialPort())); + connect(ui->disconnectButton, SIGNAL(released()), this, SLOT(closeSerialPort())); + connect(ui->settingsButton, SIGNAL(released()), m_settingsDialog, SLOT(show())); + connect(ui->clearButton, SIGNAL(released()), m_console, SLOT(clear())); + + connect(ui->baudComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setBaudRate(int))); + connect(ui->linkComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setLink(int))); +// connect(ui->linkComboBox, SIGNAL()), this, SLOT(setLink(int))); + + // Serial Port Connections + connect(m_serial, SIGNAL(error(QSerialPort::SerialPortError)), this, + SLOT(handleError(QSerialPort::SerialPortError))); + + connect(m_serial, SIGNAL(readyRead()), this, SLOT(readData())); + connect(m_console, SIGNAL(getData(QByteArray)), this, SLOT(writeData(QByteArray))); +} + +void TerminalConsole::setBaudRate(int index) +{ + m_settings.baudRate = static_cast( + ui->baudComboBox->itemData(index).toInt()); + qDebug() << "Changed Baud to:" << m_settings.baudRate; + +} + +void TerminalConsole::setLink(int index) +{ + m_settings.name = ui->linkComboBox->currentText(); + qDebug() << "Changed Link to:" << m_settings.name; + +} + +void TerminalConsole::loadSettings() +{ + // Load defaults from settings + QSettings settings(QGC::ORG_NAME, QGC::APPNAME); + settings.sync(); + if (settings.contains("TERMINALCONSOLE_COMM_PORT")) + { + m_settings.name = settings.value("TERMINALCONSOLE_COMM_PORT").toString(); + m_settings.baudRate = settings.value("TERMINALCONSOLE_COMM_BAUD").toInt(); + m_settings.parity = static_cast + (settings.value("TERMINALCONSOLE_COMM_PARITY").toInt()); + m_settings.stopBits = static_cast + (settings.value("TERMINALCONSOLE_COMM_STOPBITS").toInt()); + m_settings.dataBits = static_cast + (settings.value("TERMINALCONSOLE_COMM_DATABITS").toInt()); + m_settings.flowControl = static_cast + (settings.value("TERMINALCONSOLE_COMM_FLOW_CONTROL").toInt()); + } else { + // init the structure + } +} + +void TerminalConsole::writeSettings() +{ + // Store settings + QSettings settings(QGC::ORG_NAME, QGC::APPNAME); + settings.setValue("TERMINALCONSOLE_COMM_PORT", m_settings.name); + settings.setValue("TERMINALCONSOLE_COMM_BAUD", m_settings.baudRate); + settings.setValue("TERMINALCONSOLE_COMM_PARITY", m_settings.parity); + settings.setValue("TERMINALCONSOLE_COMM_STOPBITS", m_settings.stopBits); + settings.setValue("TERMINALCONSOLE_COMM_DATABITS", m_settings.dataBits); + settings.setValue("TERMINALCONSOLE_COMM_FLOW_CONTROL", m_settings.flowControl); + settings.sync(); +} + + + diff --git a/src/ui/configuration/terminalconsole.h b/src/ui/configuration/terminalconsole.h new file mode 100644 index 0000000000000000000000000000000000000000..85a5643946c001a1ea2929c72a3078d501aae419 --- /dev/null +++ b/src/ui/configuration/terminalconsole.h @@ -0,0 +1,97 @@ +/*===================================================================== + +APM_PLANNER Open Source Ground Control Station + +(c) 2013, Bill Bonney + +This file is part of the APM_PLANNER project + + APM_PLANNER 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 3 of the License, or + (at your option) any later version. + + APM_PLANNER 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 APM_PLANNER. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Terminal Console display View. + * + * @author Bill Bonney + * + * Influenced from Qt examples by :- + * Copyright (C) 2012 Denis Shienkov + * Copyright (C) 2012 Laszlo Papp + * + */ + +#ifndef TERMINALCONSOLE_H +#define TERMINALCONSOLE_H + +#include "SerialSettingsDialog.h" + +#include +#include + +namespace Ui { +class TerminalConsole; +} + +class Console; +class SettingsDialog; +class QStatusBar; +class QComboBox; + +class TerminalConsole : public QWidget +{ + Q_OBJECT + +public: + enum ConsoleMode { APM, PX4 }; +public: + explicit TerminalConsole(QWidget *parent = 0); + ~TerminalConsole(); + +private slots: + void openSerialPort(); + void openSerialPort(const SerialSettings &settings); + void closeSerialPort(); + void writeData(const QByteArray &data); + void readData(); + void sendResetCommand(); + + void handleError(QSerialPort::SerialPortError error); + +private slots: + void setBaudRate(int index); + void setLink(int index); + +private: + void initConnections(); + void addBaudComboBoxConfig(); + void fillPortsInfo(QComboBox &comboxBox); + void addConsoleModesComboBoxConfig(); + void writeSettings(); + void loadSettings(); + + +private: + Ui::TerminalConsole *ui; + + Console *m_console; + QStatusBar *m_statusBar; + SettingsDialog *m_settingsDialog; + QSerialPort *m_serial; + SerialSettings m_settings; + ConsoleMode m_consoleMode; +}; + +#endif // TERMINALCONSOLE_H diff --git a/src/ui/configuration/terminalconsole.ui b/src/ui/configuration/terminalconsole.ui new file mode 100644 index 0000000000000000000000000000000000000000..455cfc1e7abfe3871af0b0ff70f588af15bded16 --- /dev/null +++ b/src/ui/configuration/terminalconsole.ui @@ -0,0 +1,177 @@ + + + TerminalConsole + + + + 0 + 0 + 889 + 531 + + + + Form + + + + + + + 0 + 0 + + + + Terminal Output + + + + + + + + QLayout::SetMinAndMaxSize + + + + + + 100 + 0 + + + + + 131 + 0 + + + + CONNECT + + + + + + + + 0 + 0 + + + + + 131 + 0 + + + + DISCONNECT + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + + 123 + 0 + + + + + 220 + 32 + + + + + + + + + 0 + 0 + + + + + 123 + 0 + + + + + + + + + 0 + 0 + + + + + 123 + 0 + + + + + + + + Qt::Vertical + + + + 91 + 23 + + + + + + + + Adv. Settings + + + + + + + Clear + + + + + + + + + + diff --git a/src/ui/designer/QGCActionButton.ui b/src/ui/designer/QGCActionButton.ui index 8f0fb544f6fc144b5b51d8b08fb649fc9cefdaca..93144ae18888f48ff76c8b0408acfece6c01b178 100644 --- a/src/ui/designer/QGCActionButton.ui +++ b/src/ui/designer/QGCActionButton.ui @@ -61,14 +61,14 @@
- + Button name - + Description diff --git a/src/ui/designer/QGCComboBox.cc b/src/ui/designer/QGCComboBox.cc index 21d86f67954059323952d6038c11c023e9f5130b..1b8345bf221afb5a23c5e546fa31b29fd09c0728 100644 --- a/src/ui/designer/QGCComboBox.cc +++ b/src/ui/designer/QGCComboBox.cc @@ -17,7 +17,7 @@ QGCComboBox::QGCComboBox(QWidget *parent) : parameterScalingFactor(0.0), parameterMin(0.0f), parameterMax(0.0f), - component(0), + componentId(0), ui(new Ui::QGCComboBox) { ui->setupUi(this); @@ -48,7 +48,7 @@ QGCComboBox::QGCComboBox(QWidget *parent) : connect(ui->editRemoveItemButton,SIGNAL(clicked()),this,SLOT(delButtonClicked())); // Sending actions - connect(ui->writeButton, SIGNAL(clicked()), this, SLOT(sendParameter())); + connect(ui->writeButton, SIGNAL(clicked()), this, SLOT(setParamPending())); connect(ui->editSelectComponentComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(selectComponent(int))); connect(ui->editSelectParamComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(selectParameter(int))); //connect(ui->valueSlider, SIGNAL(valueChanged(int)), this, SLOT(setSliderValue(int))); @@ -56,7 +56,7 @@ QGCComboBox::QGCComboBox(QWidget *parent) : //connect(ui->intValueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setParamValue(int))); connect(ui->editNameLabel, SIGNAL(textChanged(QString)), ui->nameLabel, SLOT(setText(QString))); connect(ui->readButton, SIGNAL(clicked()), this, SLOT(requestParameter())); - connect(ui->editRefreshParamsButton, SIGNAL(clicked()), this, SLOT(refreshParamList())); + connect(ui->editRefreshParamsButton, SIGNAL(clicked()), this, SLOT(refreshParameter())); connect(ui->editInfoCheckBox, SIGNAL(clicked(bool)), this, SLOT(showInfo(bool))); // connect to self connect(ui->infoLabel, SIGNAL(released()), this, SLOT(showTooltip())); @@ -82,14 +82,13 @@ void QGCComboBox::showTooltip() } } -void QGCComboBox::refreshParamList() +void QGCComboBox::refreshParameter() { ui->editSelectParamComboBox->setEnabled(true); ui->editSelectComponentComboBox->setEnabled(true); - if (uas) - { - uas->getParamManager()->requestParameterList(); - ui->editStatusLabel->setText(tr("Parameter list updating..")); + if (uas && !parameterName.isEmpty()) { + uas->getParamManager()->requestParameterUpdate(componentId,parameterName); + ui->editStatusLabel->setText(tr("Requesting refresh...")); } } @@ -105,18 +104,18 @@ void QGCComboBox::setActiveUAS(UASInterface* activeUas) // Connect buttons and signals connect(activeUas, SIGNAL(parameterChanged(int,int,int,int,QString,QVariant)), this, SLOT(setParameterValue(int,int,int,int,QString,QVariant)), Qt::UniqueConnection); uas = activeUas; + paramMgr = uas->getParamManager(); // Update current param value //requestParameter(); // Set param info - QString text = uas->getParamManager()->getParamInfo(parameterName); - if (text != "") - { + + QString text = paramMgr->dataModel()->getParamDescription(parameterName); + if (!text.isEmpty()) { ui->infoLabel->setToolTip(text); ui->infoLabel->show(); } // Force-uncheck and hide label if no description is available - if (ui->editInfoCheckBox->isChecked()) - { + if (ui->editInfoCheckBox->isChecked()) { showInfo((text.length() > 0)); } } @@ -126,7 +125,7 @@ void QGCComboBox::requestParameter() { if (!parameterName.isEmpty() && uas) { - uas->getParamManager()->requestParameterUpdate(this->component, this->parameterName); + paramMgr->requestParameterUpdate(this->componentId, this->parameterName); } } @@ -138,7 +137,7 @@ void QGCComboBox::showInfo(bool enable) void QGCComboBox::selectComponent(int componentIndex) { - this->component = ui->editSelectComponentComboBox->itemData(componentIndex).toInt(); + this->componentId = ui->editSelectComponentComboBox->itemData(componentIndex).toInt(); } void QGCComboBox::selectParameter(int paramIndex) @@ -147,117 +146,72 @@ void QGCComboBox::selectParameter(int paramIndex) parameterName = ui->editSelectParamComboBox->itemText(paramIndex); // Update min and max values if available - if (uas) - { - if (uas->getParamManager()) - { - // Current value - //uas->getParamManager()->requestParameterUpdate(component, parameterName); - + if (uas) { + UASParameterDataModel* dataModel = paramMgr->dataModel(); + if (dataModel) { // Minimum - if (uas->getParamManager()->isParamMinKnown(parameterName)) - { - parameterMin = uas->getParamManager()->getParamMin(parameterName); + if (dataModel->isParamMinKnown(parameterName)) { + parameterMin = dataModel->getParamMin(parameterName); } // Maximum - if (uas->getParamManager()->isParamMaxKnown(parameterName)) - { - parameterMax = uas->getParamManager()->getParamMax(parameterName); + if (dataModel->isParamMaxKnown(parameterName)) { + parameterMax = dataModel->getParamMax(parameterName); } // Description - QString text = uas->getParamManager()->getParamInfo(parameterName); + QString text = dataModel->getParamDescription(parameterName); //ui->infoLabel->setText(text); showInfo(!(text.length() > 0)); } } } -void QGCComboBox::startEditMode() +void QGCComboBox::setEditMode(bool editMode) { - ui->nameLabel->hide(); - ui->writeButton->hide(); - ui->readButton->hide(); - - ui->editInfoCheckBox->show(); - ui->editDoneButton->show(); - ui->editNameLabel->show(); - ui->editRefreshParamsButton->show(); - ui->editSelectParamComboBox->show(); - ui->editSelectComponentComboBox->show(); - ui->editStatusLabel->show(); - ui->writeButton->hide(); - ui->readButton->hide(); - ui->editLine1->show(); - ui->editLine2->show(); - ui->editAddItemButton->show(); - ui->editRemoveItemButton->show(); - ui->editItemValueSpinBox->show(); - ui->editItemNameLabel->show(); - ui->itemValueLabel->show(); - ui->itemNameLabel->show(); - if (isDisabled) - { - ui->editOptionComboBox->setEnabled(true); + if(!editMode) { + // Store component id + selectComponent(ui->editSelectComponentComboBox->currentIndex()); + // Store parameter name and id + selectParameter(ui->editSelectParamComboBox->currentIndex()); } - isInEditMode = true; -} - -void QGCComboBox::endEditMode() -{ - // Store component id - selectComponent(ui->editSelectComponentComboBox->currentIndex()); - // Store parameter name and id - selectParameter(ui->editSelectParamComboBox->currentIndex()); - - // Min/max - - ui->editInfoCheckBox->hide(); - ui->editDoneButton->hide(); - ui->editNameLabel->hide(); - ui->editRefreshParamsButton->hide(); - ui->editSelectParamComboBox->hide(); - ui->editSelectComponentComboBox->hide(); - ui->editStatusLabel->hide(); - ui->editLine1->hide(); - ui->editLine2->hide(); - ui->writeButton->show(); - ui->readButton->show(); - ui->editAddItemButton->hide(); - ui->editRemoveItemButton->hide(); - ui->editItemValueSpinBox->hide(); - ui->editItemNameLabel->hide(); - ui->itemValueLabel->hide(); - ui->itemNameLabel->hide(); - ui->nameLabel->show(); + ui->nameLabel->setVisible(!editMode); + ui->writeButton->setVisible(!editMode); + ui->readButton->setVisible(!editMode); + + ui->editInfoCheckBox->setVisible(editMode); + ui->editDoneButton->setVisible(editMode); + ui->editNameLabel->setVisible(editMode); + ui->editRefreshParamsButton->setVisible(editMode); + ui->editSelectParamComboBox->setVisible(editMode); + ui->editSelectComponentComboBox->setVisible(editMode); + ui->editStatusLabel->setVisible(editMode); + ui->writeButton->setVisible(!editMode); + ui->readButton->setVisible(!editMode); + ui->editLine1->setVisible(editMode); + ui->editLine2->setVisible(editMode); + ui->editAddItemButton->setVisible(editMode); + ui->editRemoveItemButton->setVisible(editMode); + ui->editItemValueSpinBox->setVisible(editMode); + ui->editItemNameLabel->setVisible(editMode); + ui->itemValueLabel->setVisible(editMode); + ui->itemNameLabel->setVisible(editMode); if (isDisabled) { - ui->editOptionComboBox->setEnabled(false); + ui->editOptionComboBox->setEnabled(editMode); } - isInEditMode = false; - emit editingFinished(); + + QGCToolWidgetItem::setEditMode(editMode); } -void QGCComboBox::sendParameter() +void QGCComboBox::setParamPending() { - if (uas) - { - // Set value, param manager handles retransmission - if (uas->getParamManager()) - { - qDebug() << "Sending param:" << parameterName << "to component" << component << "with a value of" << parameterValue; - uas->getParamManager()->setParameter(component, parameterName, parameterValue); - } - else - { - qDebug() << "UAS HAS NO PARAM MANAGER, DOING NOTHING"; - } + if (uas) { + uas->getParamManager()->setPendingParam(componentId, parameterName, parameterValue); } - else - { - qDebug() << __FILE__ << __LINE__ << "NO UAS SET, DOING NOTHING"; + else { + qWarning() << __FILE__ << __LINE__ << "NO UAS SET, DOING NOTHING"; } } @@ -310,7 +264,7 @@ void QGCComboBox::setParameterValue(int uas, int component, int paramCount, int { if (visibleVal == value.toInt()) { - this->uas->requestParameter(this->component,this->parameterName); + this->uas->requestParameter(this->componentId,this->parameterName); visibleEnabled = true; this->show(); } @@ -325,7 +279,7 @@ void QGCComboBox::setParameterValue(int uas, int component, int paramCount, int } } } - if (component == this->component && parameterName == this->parameterName) + if (component == this->componentId && parameterName == this->parameterName) { if (!visibleEnabled) { @@ -368,7 +322,7 @@ void QGCComboBox::writeSettings(QSettings& settings) settings.setValue("QGC_PARAM_COMBOBOX_DESCRIPTION", ui->nameLabel->text()); //settings.setValue("QGC_PARAM_COMBOBOX_BUTTONTEXT", ui->actionButton->text()); settings.setValue("QGC_PARAM_COMBOBOX_PARAMID", parameterName); - settings.setValue("QGC_PARAM_COMBOBOX_COMPONENTID", component); + settings.setValue("QGC_PARAM_COMBOBOX_COMPONENTID", componentId); settings.setValue("QGC_PARAM_COMBOBOX_DISPLAY_INFO", ui->editInfoCheckBox->isChecked()); settings.setValue("QGC_PARAM_COMBOBOX_COUNT", ui->editOptionComboBox->count()); @@ -382,7 +336,7 @@ void QGCComboBox::writeSettings(QSettings& settings) void QGCComboBox::readSettings(const QString& pre,const QVariantMap& settings) { parameterName = settings.value(pre + "QGC_PARAM_COMBOBOX_PARAMID").toString(); - component = settings.value(pre + "QGC_PARAM_COMBOBOX_COMPONENTID").toInt(); + componentId = settings.value(pre + "QGC_PARAM_COMBOBOX_COMPONENTID").toInt(); ui->nameLabel->setText(settings.value(pre + "QGC_PARAM_COMBOBOX_DESCRIPTION").toString()); ui->editNameLabel->setText(settings.value(pre + "QGC_PARAM_COMBOBOX_DESCRIPTION").toString()); //settings.setValue("QGC_PARAM_SLIDER_BUTTONTEXT", ui->actionButton->text()); diff --git a/src/ui/designer/QGCComboBox.h b/src/ui/designer/QGCComboBox.h index 4c5491580e5c7da5af777354a7a4e03bb675bdb8..2e606a559c1c51e666a184f3e976aabb6508102e 100644 --- a/src/ui/designer/QGCComboBox.h +++ b/src/ui/designer/QGCComboBox.h @@ -7,6 +7,8 @@ #include "QGCToolWidgetItem.h" +class QGCUASParamManager; + namespace Ui { class QGCComboBox; @@ -20,17 +22,18 @@ public: explicit QGCComboBox(QWidget *parent = 0); ~QGCComboBox(); + virtual void setEditMode(bool editMode); + public slots: - void startEditMode(); - void endEditMode(); - /** @brief Send the parameter to the MAV */ - void sendParameter(); + /** @brief Queue parameter for sending to the MAV (add to pending list)*/ + void setParamPending(); /** @brief Update the UI with the new parameter value */ - void setParameterValue(int uas, int component, int paramCount, int paramIndex, QString parameterName, const QVariant value); + void setParameterValue(int uas, int componentId, int paramCount, int paramIndex, QString parameterName, const QVariant value); void writeSettings(QSettings& settings); void readSettings(const QString& pre,const QVariantMap& settings); void readSettings(const QSettings& settings); - void refreshParamList(); + /** @brief request that the parameter for this widget be refreshed */ + void refreshParameter(); void setActiveUAS(UASInterface *uas); void selectComponent(int componentIndex); void selectParameter(int paramIndex); @@ -49,6 +52,7 @@ protected slots: /** @brief Updates current parameter based on new combobox value */ void comboBoxIndexChanged(QString val); protected: + QGCUASParamManager *paramMgr; ///< Access to parameter manager bool visibleEnabled; QString visibleParam; int visibleVal; @@ -61,7 +65,7 @@ protected: float parameterMin; bool isDisabled; float parameterMax; - int component; ///< ID of the MAV component to address + int componentId; ///< ID of the MAV component to address //double scaledInt; void changeEvent(QEvent *e); diff --git a/src/ui/designer/QGCComboBox.ui b/src/ui/designer/QGCComboBox.ui index f9d4db90d2d24c1ed65f64f9e8d349675b48f363..fdfbc7935b1feb8710265f39886e15ea36b0482d 100644 --- a/src/ui/designer/QGCComboBox.ui +++ b/src/ui/designer/QGCComboBox.ui @@ -75,8 +75,8 @@ - - <Parameter Name / Label> + + Parameter Name diff --git a/src/ui/designer/QGCCommandButton.cc b/src/ui/designer/QGCCommandButton.cc index 24bdc7d37e3fa9b1ba73e6e80a5b32b2ea29aae2..69efc00607f7efc6ef897206c3d5e12624353cae 100644 --- a/src/ui/designer/QGCCommandButton.cc +++ b/src/ui/designer/QGCCommandButton.cc @@ -159,93 +159,33 @@ void QGCCommandButton::setCommandButtonName(QString text) ui->commandButton->setText(text); } -void QGCCommandButton::startEditMode() +void QGCCommandButton::setEditMode(bool editMode) { // Hide elements - ui->commandButton->hide(); - ui->nameLabel->hide(); - - ui->editCommandComboBox->blockSignals(false); - ui->editCommandComboBox->show(); - ui->editFinishButton->show(); - ui->editNameLabel->show(); - ui->editButtonName->show(); - ui->editConfirmationCheckBox->show(); - ui->editComponentSpinBox->show(); - ui->editParamsVisibleCheckBox->show(); - ui->editParam1SpinBox->show(); - ui->editParam2SpinBox->show(); - ui->editParam3SpinBox->show(); - ui->editParam4SpinBox->show(); - ui->editParam5SpinBox->show(); - ui->editParam6SpinBox->show(); - ui->editParam7SpinBox->show(); - ui->editLine1->show(); - ui->editLine2->show(); - - // Attempt to undock the dock widget - QWidget* p = this; - QDockWidget* dock; - - do { - p = p->parentWidget(); - dock = dynamic_cast(p); - - if (dock) - { - dock->setFloating(true); - break; - } - } while (p && !dock); - - isInEditMode = true; -} - -void QGCCommandButton::endEditMode() -{ - ui->editCommandComboBox->blockSignals(true); - ui->editCommandComboBox->hide(); - ui->editFinishButton->hide(); - ui->editNameLabel->hide(); - ui->editButtonName->hide(); - ui->editConfirmationCheckBox->hide(); - ui->editComponentSpinBox->hide(); - ui->editParamsVisibleCheckBox->hide(); - ui->editLine1->hide(); - ui->editLine2->hide(); - if (!ui->editParamsVisibleCheckBox->isChecked()) - { - ui->editParam1SpinBox->hide(); - ui->editParam2SpinBox->hide(); - ui->editParam3SpinBox->hide(); - ui->editParam4SpinBox->hide(); - ui->editParam5SpinBox->hide(); - ui->editParam6SpinBox->hide(); - ui->editParam7SpinBox->hide(); - } - - ui->commandButton->show(); - ui->nameLabel->show(); - - // Write to settings - emit editingFinished(); - - // Attempt to dock the dock widget - QWidget* p = this; - QDockWidget* dock; - - do { - p = p->parentWidget(); - dock = dynamic_cast(p); - - if (dock) - { - dock->setFloating(false); - break; - } - } while (p && !dock); - - isInEditMode = false; + ui->commandButton->setVisible(!editMode); + ui->nameLabel->setVisible(!editMode); + + ui->editCommandComboBox->blockSignals(!editMode); + ui->editCommandComboBox->setVisible(editMode); + ui->editFinishButton->setVisible(editMode); + ui->editNameLabel->setVisible(editMode); + ui->editButtonName->setVisible(editMode); + ui->editConfirmationCheckBox->setVisible(editMode); + ui->editComponentSpinBox->setVisible(editMode); + ui->editParamsVisibleCheckBox->setVisible(editMode); + bool showParams = editMode || ui->editParamsVisibleCheckBox->isChecked(); + ui->editParam1SpinBox->setVisible(showParams); + ui->editParam2SpinBox->setVisible(showParams); + ui->editParam3SpinBox->setVisible(showParams); + ui->editParam4SpinBox->setVisible(showParams); + ui->editParam5SpinBox->setVisible(showParams); + ui->editParam6SpinBox->setVisible(showParams); + ui->editParam7SpinBox->setVisible(showParams); + + ui->editLine1->setVisible(editMode); + ui->editLine2->setVisible(editMode); + + QGCToolWidgetItem::setEditMode(editMode); } void QGCCommandButton::writeSettings(QSettings& settings) diff --git a/src/ui/designer/QGCCommandButton.h b/src/ui/designer/QGCCommandButton.h index 320cc97fbae314bb16de86913f0a9ca9f9d3f20a..da47e6082c72155f145192614b2980d116d7e035 100644 --- a/src/ui/designer/QGCCommandButton.h +++ b/src/ui/designer/QGCCommandButton.h @@ -18,11 +18,11 @@ public: explicit QGCCommandButton(QWidget *parent = 0); ~QGCCommandButton(); + virtual void setEditMode(bool editMode); + public slots: void sendCommand(); void setCommandButtonName(QString text); - void startEditMode(); - void endEditMode(); void writeSettings(QSettings& settings); void readSettings(const QSettings& settings); void readSettings(const QString& pre,const QVariantMap& settings); diff --git a/src/ui/designer/QGCCommandButton.ui b/src/ui/designer/QGCCommandButton.ui index eb26a6785cc2a1be5251b1f2a324cf7c60a02db5..854ca81c187ddf03110c1e3b0d28060dac609dff 100644 --- a/src/ui/designer/QGCCommandButton.ui +++ b/src/ui/designer/QGCCommandButton.ui @@ -49,8 +49,8 @@
- - <Button Description Label (in front of button)> + + Button Description diff --git a/src/ui/designer/QGCParamSlider.cc b/src/ui/designer/QGCParamSlider.cc index edba2c78cd7bc08e99571a541e711cfeafcf8e5a..c5f2da52d903d5f7522f13d74111178f749a48dc 100644 --- a/src/ui/designer/QGCParamSlider.cc +++ b/src/ui/designer/QGCParamSlider.cc @@ -17,7 +17,7 @@ QGCParamSlider::QGCParamSlider(QWidget *parent) : parameterScalingFactor(0.0), parameterMin(0.0f), parameterMax(0.0f), - component(0), + componentId(0), ui(new Ui::QGCParamSlider) { valueModLock = false; @@ -47,20 +47,31 @@ QGCParamSlider::QGCParamSlider(QWidget *parent) : connect(ui->editDoneButton, SIGNAL(clicked()), this, SLOT(endEditMode())); // Sending actions - connect(ui->writeButton, SIGNAL(clicked()), this, SLOT(sendParameter())); - connect(ui->editSelectComponentComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(selectComponent(int))); - connect(ui->editSelectParamComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(selectParameter(int))); - connect(ui->valueSlider, SIGNAL(valueChanged(int)), this, SLOT(setSliderValue(int))); - connect(ui->doubleValueSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setParamValue(double))); - connect(ui->intValueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setParamValue(int))); - connect(ui->editNameLabel, SIGNAL(textChanged(QString)), ui->nameLabel, SLOT(setText(QString))); + connect(ui->writeButton, SIGNAL(clicked()), + this, SLOT(setParamPending())); + connect(ui->editSelectComponentComboBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(selectComponent(int))); + connect(ui->editSelectParamComboBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(selectParameter(int))); + connect(ui->valueSlider, SIGNAL(valueChanged(int)), + this, SLOT(setSliderValue(int))); + connect(ui->doubleValueSpinBox, SIGNAL(valueChanged(double)), + this, SLOT(setParamValue(double))); + connect(ui->intValueSpinBox, SIGNAL(valueChanged(int)), + this, SLOT(setParamValue(int))); + connect(ui->editNameLabel, SIGNAL(textChanged(QString)), + ui->nameLabel, SLOT(setText(QString))); connect(ui->readButton, SIGNAL(clicked()), this, SLOT(requestParameter())); - connect(ui->editRefreshParamsButton, SIGNAL(clicked()), this, SLOT(refreshParamList())); - connect(ui->editInfoCheckBox, SIGNAL(clicked(bool)), this, SLOT(showInfo(bool))); + connect(ui->editRefreshParamsButton, SIGNAL(clicked()), + this, SLOT(refreshParamList())); + connect(ui->editInfoCheckBox, SIGNAL(clicked(bool)), + this, SLOT(showInfo(bool))); // connect to self - connect(ui->infoLabel, SIGNAL(released()), this, SLOT(showTooltip())); + connect(ui->infoLabel, SIGNAL(released()), + this, SLOT(showTooltip())); // Set the current UAS if present - connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*))); + connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), + this, SLOT(setActiveUAS(UASInterface*))); } QGCParamSlider::~QGCParamSlider() @@ -83,8 +94,7 @@ void QGCParamSlider::refreshParamList() { ui->editSelectParamComboBox->setEnabled(true); ui->editSelectComponentComboBox->setEnabled(true); - if (uas) - { + if (uas) { uas->getParamManager()->requestParameterList(); ui->editStatusLabel->setText(tr("Parameter list updating..")); } @@ -92,38 +102,38 @@ void QGCParamSlider::refreshParamList() void QGCParamSlider::setActiveUAS(UASInterface* activeUas) { - if (activeUas) - { - if (uas) - { - disconnect(uas, SIGNAL(parameterChanged(int,int,int,int,QString,QVariant)), this, SLOT(setParameterValue(int,int,int,int,QString,QVariant))); - } - // Connect buttons and signals - connect(activeUas, SIGNAL(parameterChanged(int,int,int,int,QString,QVariant)), this, SLOT(setParameterValue(int,int,int,int,QString,QVariant)), Qt::UniqueConnection); + if (uas != activeUas) { + if (uas) { + disconnect(uas, SIGNAL(parameterChanged(int,int,int,int,QString,QVariant)), + this, SLOT(setParameterValue(int,int,int,int,QString,QVariant))); + } + if (activeUas) { + connect(activeUas, SIGNAL(parameterChanged(int,int,int,int,QString,QVariant)), + this, SLOT(setParameterValue(int,int,int,int,QString,QVariant)), Qt::UniqueConnection); + } uas = activeUas; - // Update current param value - //requestParameter(); - // Set param info - QString text = uas->getParamManager()->getParamInfo(parameterName); - if (text != "") - { + } + + if (uas && !parameterName.isEmpty()) { + QString text = uas->getParamManager()->dataModel()->getParamDescription(parameterName); + if (!text.isEmpty()) { ui->infoLabel->setToolTip(text); ui->infoLabel->show(); } // Force-uncheck and hide label if no description is available - if (ui->editInfoCheckBox->isChecked()) - { + if (ui->editInfoCheckBox->isChecked()) { showInfo((text.length() > 0)); } } + + } void QGCParamSlider::requestParameter() { - if (!parameterName.isEmpty() && uas) - { - uas->getParamManager()->requestParameterUpdate(this->component, this->parameterName); + if (uas && !parameterName.isEmpty()) { + uas->getParamManager()->requestParameterUpdate(componentId, parameterName); } } @@ -167,132 +177,96 @@ void QGCParamSlider::setParamValue(int value) void QGCParamSlider::selectComponent(int componentIndex) { - this->component = ui->editSelectComponentComboBox->itemData(componentIndex).toInt(); + this->componentId = ui->editSelectComponentComboBox->itemData(componentIndex).toInt(); } void QGCParamSlider::selectParameter(int paramIndex) { // Set name parameterName = ui->editSelectParamComboBox->itemText(paramIndex); + if (parameterName.isEmpty()) { + return; + } // Update min and max values if available - if (uas) - { - if (uas->getParamManager()) - { - // Current value - //uas->getParamManager()->requestParameterUpdate(component, parameterName); - + if (uas) { + UASParameterDataModel* dataModel = uas->getParamManager()->dataModel(); + if (dataModel) { // Minimum - if (uas->getParamManager()->isParamMinKnown(parameterName)) - { - parameterMin = uas->getParamManager()->getParamMin(parameterName); + if (dataModel->isParamMinKnown(parameterName)) { + parameterMin = dataModel->getParamMin(parameterName); ui->editMinSpinBox->setValue(parameterMin); } // Maximum - if (uas->getParamManager()->isParamMaxKnown(parameterName)) - { - parameterMax = uas->getParamManager()->getParamMax(parameterName); + if (dataModel->isParamMaxKnown(parameterName)) { + parameterMax = dataModel->getParamMax(parameterName); ui->editMaxSpinBox->setValue(parameterMax); } - - // Description - //QString text = uas->getParamManager()->getParamInfo(parameterName); - //ui->infoLabel->setText(text); - - //showInfo(!(text.length() > 0)); } } } -void QGCParamSlider::startEditMode() -{ - ui->valueSlider->hide(); - ui->doubleValueSpinBox->hide(); - ui->intValueSpinBox->hide(); - ui->nameLabel->hide(); - ui->writeButton->hide(); - ui->readButton->hide(); - - ui->editInfoCheckBox->show(); - ui->editDoneButton->show(); - ui->editNameLabel->show(); - ui->editRefreshParamsButton->show(); - ui->editSelectParamComboBox->show(); - ui->editSelectComponentComboBox->show(); - ui->editStatusLabel->show(); - ui->editMinSpinBox->show(); - ui->editMaxSpinBox->show(); - ui->writeButton->hide(); - ui->readButton->hide(); - ui->editLine1->show(); - ui->editLine2->show(); - isInEditMode = true; -} - -void QGCParamSlider::endEditMode() +void QGCParamSlider::setEditMode(bool editMode) { - // Store component id - selectComponent(ui->editSelectComponentComboBox->currentIndex()); + if(!editMode) { + // Store component id + selectComponent(ui->editSelectComponentComboBox->currentIndex()); - // Store parameter name and id - selectParameter(ui->editSelectParamComboBox->currentIndex()); + // Store parameter name and id + selectParameter(ui->editSelectParamComboBox->currentIndex()); - // Min/max - parameterMin = ui->editMinSpinBox->value(); - parameterMax = ui->editMaxSpinBox->value(); + // Min/max + parameterMin = ui->editMinSpinBox->value(); + parameterMax = ui->editMaxSpinBox->value(); - ui->editInfoCheckBox->hide(); - ui->editDoneButton->hide(); - ui->editNameLabel->hide(); - ui->editRefreshParamsButton->hide(); - ui->editSelectParamComboBox->hide(); - ui->editSelectComponentComboBox->hide(); - ui->editStatusLabel->hide(); - ui->editMinSpinBox->hide(); - ui->editMaxSpinBox->hide(); - ui->editLine1->hide(); - ui->editLine2->hide(); - ui->writeButton->show(); - ui->readButton->show(); - ui->valueSlider->show(); - switch (parameterValue.type()) - { - case QVariant::Char: - case QVariant::Int: - case QVariant::UInt: - ui->intValueSpinBox->show(); - break; - case QMetaType::Float: - ui->doubleValueSpinBox->show(); - break; - default: - qCritical() << "ERROR: NO VALID PARAM TYPE"; - return; + switch ((int)parameterValue.type()) + { + case QVariant::Char: + case QVariant::Int: + case QVariant::UInt: + ui->intValueSpinBox->show(); + break; + case QMetaType::Float: + ui->doubleValueSpinBox->show(); + break; + default: + qCritical() << "ERROR: NO VALID PARAM TYPE"; + return; + } + } else { + ui->doubleValueSpinBox->hide(); + ui->intValueSpinBox->hide(); } - ui->nameLabel->show(); - isInEditMode = false; - emit editingFinished(); + ui->valueSlider->setVisible(!editMode); + ui->nameLabel->setVisible(!editMode); + ui->writeButton->setVisible(!editMode); + ui->readButton->setVisible(!editMode); + + ui->editInfoCheckBox->setVisible(editMode); + ui->editDoneButton->setVisible(editMode); + ui->editNameLabel->setVisible(editMode); + ui->editRefreshParamsButton->setVisible(editMode); + ui->editSelectParamComboBox->setVisible(editMode); + ui->editSelectComponentComboBox->setVisible(editMode); + ui->editStatusLabel->setVisible(editMode); + ui->editMinSpinBox->setVisible(editMode); + ui->editMaxSpinBox->setVisible(editMode); + ui->writeButton->setVisible(!editMode); + ui->readButton->setVisible(!editMode); + ui->editLine1->setVisible(editMode); + ui->editLine2->setVisible(editMode); + + QGCToolWidgetItem::setEditMode(editMode); } -void QGCParamSlider::sendParameter() +void QGCParamSlider::setParamPending() { - if (uas) - { - // Set value, param manager handles retransmission - if (uas->getParamManager()) - { - uas->getParamManager()->setParameter(component, parameterName, parameterValue); - } - else - { - qDebug() << "UAS HAS NO PARAM MANAGER, DOING NOTHING"; - } + if (uas) { + uas->getParamManager()->setPendingParam(componentId, parameterName, parameterValue); } - else - { - qDebug() << __FILE__ << __LINE__ << "NO UAS SET, DOING NOTHING"; + else { + qWarning() << __FILE__ << __LINE__ << "NO UAS SET, DOING NOTHING"; } } @@ -301,7 +275,7 @@ void QGCParamSlider::setSliderValue(int sliderValue) if (!valueModLock && !valueModLockParam) { valueModLock = true; - switch (parameterValue.type()) + switch ((int)parameterValue.type()) { case QVariant::Char: parameterValue = QVariant(QChar((unsigned char)scaledIntToFloat(sliderValue))); @@ -337,55 +311,48 @@ void QGCParamSlider::setSliderValue(int sliderValue) * @brief parameterName Key/name of the parameter * @brief value Value of the parameter */ -void QGCParamSlider::setParameterValue(int uas, int component, int paramCount, int paramIndex, QString parameterName, QVariant value) +void QGCParamSlider::setParameterValue(int uasId, int compId, int paramCount, int paramIndex, QString paramName, QVariant value) { Q_UNUSED(paramCount); - if (ui->nameLabel->text() == "Name") - { - ui->nameLabel->setText(parameterName); + if (uasId != this->uas->getUASID()) { + return; + } + + if (ui->nameLabel->text() == "Name") { + ui->nameLabel->setText(paramName); } // Check if this component and parameter are part of the list bool found = false; - for (int i = 0; i< ui->editSelectComponentComboBox->count(); ++i) - { - if (component == ui->editSelectComponentComboBox->itemData(i).toInt()) - { + for (int i = 0; i< ui->editSelectComponentComboBox->count(); ++i) { + if (compId == ui->editSelectComponentComboBox->itemData(i).toInt()) { found = true; } } - if (!found) - { - ui->editSelectComponentComboBox->addItem(tr("Component #%1").arg(component), component); + if (!found) { + ui->editSelectComponentComboBox->addItem(tr("Component #%1").arg(compId), compId); } // Parameter checking found = false; - for (int i = 0; i < ui->editSelectParamComboBox->count(); ++i) - { - if (parameterName == ui->editSelectParamComboBox->itemText(i)) - { + for (int i = 0; i < ui->editSelectParamComboBox->count(); ++i) { + if (paramName == ui->editSelectParamComboBox->itemText(i)) { found = true; } } - if (!found) - { - ui->editSelectParamComboBox->addItem(parameterName, paramIndex); + if (!found) { + ui->editSelectParamComboBox->addItem(paramName, paramIndex); } - if (visibleParam != "") - { - if (parameterName == visibleParam) - { - if (visibleVal == value.toInt()) - { - this->uas->requestParameter(this->component,this->parameterName); + if (visibleParam != "") { + if (paramName == visibleParam) { + if (visibleVal == value.toInt()) { + uas->getParamManager()->requestParameterUpdate(compId,paramName); visibleEnabled = true; this->show(); } - else - { + else { //Disable the component here. ui->valueSlider->setEnabled(false); ui->intValueSpinBox->setEnabled(false); @@ -396,16 +363,14 @@ void QGCParamSlider::setParameterValue(int uas, int component, int paramCount, i } } Q_UNUSED(uas); - if (component == this->component && parameterName == this->parameterName) - { - if (!visibleEnabled) - { + if (compId == this->componentId && paramName == this->parameterName) { + if (!visibleEnabled) { return; } parameterValue = value; ui->valueSlider->setEnabled(true); valueModLockParam = true; - switch (value.type()) + switch ((int)value.type()) { case QVariant::Char: ui->intValueSpinBox->show(); @@ -468,8 +433,7 @@ void QGCParamSlider::setParameterValue(int uas, int component, int paramCount, i parameterMin = ui->editMinSpinBox->value(); } - if (paramIndex == paramCount - 1) - { + if (paramIndex == paramCount - 1) { ui->editStatusLabel->setText(tr("Complete parameter list received.")); } } @@ -506,7 +470,7 @@ void QGCParamSlider::writeSettings(QSettings& settings) settings.setValue("QGC_PARAM_SLIDER_DESCRIPTION", ui->nameLabel->text()); //settings.setValue("QGC_PARAM_SLIDER_BUTTONTEXT", ui->actionButton->text()); settings.setValue("QGC_PARAM_SLIDER_PARAMID", parameterName); - settings.setValue("QGC_PARAM_SLIDER_COMPONENTID", component); + settings.setValue("QGC_PARAM_SLIDER_COMPONENTID", componentId); settings.setValue("QGC_PARAM_SLIDER_MIN", ui->editMinSpinBox->value()); settings.setValue("QGC_PARAM_SLIDER_MAX", ui->editMaxSpinBox->value()); settings.setValue("QGC_PARAM_SLIDER_DISPLAY_INFO", ui->editInfoCheckBox->isChecked()); @@ -515,7 +479,7 @@ void QGCParamSlider::writeSettings(QSettings& settings) void QGCParamSlider::readSettings(const QString& pre,const QVariantMap& settings) { parameterName = settings.value(pre + "QGC_PARAM_SLIDER_PARAMID").toString(); - component = settings.value(pre + "QGC_PARAM_SLIDER_COMPONENTID").toInt(); + componentId = settings.value(pre + "QGC_PARAM_SLIDER_COMPONENTID").toInt(); ui->nameLabel->setText(settings.value(pre + "QGC_PARAM_SLIDER_DESCRIPTION").toString()); ui->editNameLabel->setText(settings.value(pre + "QGC_PARAM_SLIDER_DESCRIPTION").toString()); //settings.setValue("QGC_PARAM_SLIDER_BUTTONTEXT", ui->actionButton->text()); @@ -535,9 +499,6 @@ void QGCParamSlider::readSettings(const QString& pre,const QVariantMap& settings ui->editSelectComponentComboBox->setEnabled(true); setActiveUAS(UASManager::instance()->getActiveUAS()); - - // Get param value after settings have been loaded - //requestParameter(); } void QGCParamSlider::readSettings(const QSettings& settings) @@ -551,7 +512,7 @@ void QGCParamSlider::readSettings(const QSettings& settings) readSettings("",map); return; parameterName = settings.value("QGC_PARAM_SLIDER_PARAMID").toString(); - component = settings.value("QGC_PARAM_SLIDER_COMPONENTID").toInt(); + componentId = settings.value("QGC_PARAM_SLIDER_COMPONENTID").toInt(); ui->nameLabel->setText(settings.value("QGC_PARAM_SLIDER_DESCRIPTION").toString()); ui->editNameLabel->setText(settings.value("QGC_PARAM_SLIDER_DESCRIPTION").toString()); //settings.setValue("QGC_PARAM_SLIDER_BUTTONTEXT", ui->actionButton->text()); @@ -571,6 +532,4 @@ void QGCParamSlider::readSettings(const QSettings& settings) setActiveUAS(UASManager::instance()->getActiveUAS()); - // Get param value after settings have been loaded - //requestParameter(); } diff --git a/src/ui/designer/QGCParamSlider.h b/src/ui/designer/QGCParamSlider.h index 7160cd937ef5e48f7930ab3cb99e448936d68429..9ca92423bfa616b9821f00f041704e31b5499d1d 100644 --- a/src/ui/designer/QGCParamSlider.h +++ b/src/ui/designer/QGCParamSlider.h @@ -20,15 +20,15 @@ public: explicit QGCParamSlider(QWidget *parent = 0); ~QGCParamSlider(); + virtual void setEditMode(bool editMode); + public slots: - void startEditMode(); - void endEditMode(); - /** @brief Send the parameter to the MAV */ - void sendParameter(); + /** @brief Queue parameter for sending to the MAV (add to pending list)*/ + void setParamPending(); /** @brief Set the slider value as parameter value */ void setSliderValue(int sliderValue); /** @brief Update the UI with the new parameter value */ - void setParameterValue(int uas, int component, int paramCount, int paramIndex, QString parameterName, const QVariant value); + void setParameterValue(int uas, int componentId, int paramCount, int paramIndex, QString parameterName, const QVariant value); void writeSettings(QSettings& settings); void readSettings(const QSettings& settings); void readSettings(const QString& pre,const QVariantMap& settings); @@ -62,7 +62,7 @@ protected: double parameterScalingFactor; ///< Factor to scale the parameter between slider and true value float parameterMin; float parameterMax; - int component; ///< ID of the MAV component to address + int componentId; ///< ID of the MAV component to address double scaledInt; void changeEvent(QEvent *e); diff --git a/src/ui/designer/QGCParamSlider.ui b/src/ui/designer/QGCParamSlider.ui index 4635f01e397d193c0bbde3e5f867029135f8de02..e38c1f28f368285923838cc9753e5759da02f2fa 100644 --- a/src/ui/designer/QGCParamSlider.ui +++ b/src/ui/designer/QGCParamSlider.ui @@ -190,8 +190,8 @@
- - <Parameter Name / Label> + + Parameter Name / Label diff --git a/src/ui/designer/QGCRadioChannelDisplay.cpp b/src/ui/designer/QGCRadioChannelDisplay.cpp index 148965eb61934ac64f34424fae464e04ba103574..275afc28e7164b520f1870b92da11b1d3f3b9a44 100644 --- a/src/ui/designer/QGCRadioChannelDisplay.cpp +++ b/src/ui/designer/QGCRadioChannelDisplay.cpp @@ -1,5 +1,10 @@ #include "QGCRadioChannelDisplay.h" #include + +#define DIMMEST_COLOR QColor::fromRgb(0,100,0) +#define MIDBRIGHT_COLOR QColor::fromRgb(0,180,0) +#define BRIGHTEST_COLOR QColor::fromRgb(64,255,0) + QGCRadioChannelDisplay::QGCRadioChannelDisplay(QWidget *parent) : QWidget(parent) { m_showMinMax = false; @@ -8,6 +13,12 @@ QGCRadioChannelDisplay::QGCRadioChannelDisplay(QWidget *parent) : QWidget(parent m_value = 1500; m_orientation = Qt::Vertical; m_name = "Yaw"; + + m_fillBrush = QBrush(Qt::green, Qt::SolidPattern); + + + + } void QGCRadioChannelDisplay::setName(QString name) { @@ -20,87 +31,118 @@ void QGCRadioChannelDisplay::setOrientation(Qt::Orientation orient) m_orientation = orient; update(); } + void QGCRadioChannelDisplay::paintEvent(QPaintEvent *event) { //Values range from 0-3000. //1500 is the middle, static servo value. QPainter painter(this); - int currval = m_value; - if (currval > m_max) - { - currval = m_max; + + + + int fontHeight = painter.fontMetrics().height(); + int twiceFontHeight = fontHeight * 2; + + painter.setBrush(Qt::Dense4Pattern); + painter.setPen(QColor::fromRgb(128,128,64)); + + int curVal = m_value; + if (curVal > m_max) { + curVal = m_max; } - if (currval < m_min) - { - currval = m_min; + if (curVal < m_min) { + curVal = m_min; } if (m_orientation == Qt::Vertical) { - painter.drawRect(0,0,width()-1,(height()-1) - (painter.fontMetrics().height() * 2)); - painter.setBrush(Qt::SolidPattern); + QLinearGradient gradientBrush(0, 0, this->width(), this->height()); + gradientBrush.setColorAt(1.0,DIMMEST_COLOR); + gradientBrush.setColorAt(0.5,MIDBRIGHT_COLOR); + gradientBrush.setColorAt(0.0, BRIGHTEST_COLOR); + + //draw border + painter.drawRect(0,0,width()-1,(height()-1) - twiceFontHeight); painter.setPen(QColor::fromRgb(50,255,50)); - //m_value - m_min / m_max - m_min + painter.setBrush(Qt::SolidPattern); - if (!m_showMinMax) - { - int newval = (height()-2-(painter.fontMetrics().height() * 2)) * ((float)(currval - m_min) / ((m_max-m_min)+1)); - int newvaly = (height()-2-(painter.fontMetrics().height() * 2)) - newval; - painter.drawRect(1,newvaly,width()-3,((height()-2) - newvaly - (painter.fontMetrics().height() * 2))); - } - else - { - int newval = (height()-2-(painter.fontMetrics().height() * 2)) * ((float)(currval / 3001.0)); - int newvaly = (height()-2-(painter.fontMetrics().height() * 2)) - newval; - painter.drawRect(1,newvaly,width()-3,((height()-2) - newvaly - (painter.fontMetrics().height() * 2))); + //draw the text value of the widget, and its label + QString valStr = QString::number(m_value); + painter.setPen(QColor::fromRgb(255,255,255)); + painter.drawText((width()/2.0) - (painter.fontMetrics().width(m_name)/2.0),((height()-3) - (fontHeight*1)),m_name); + painter.drawText((width()/2.0) - (painter.fontMetrics().width(valStr)/2.0),((height()-3) - (fontHeight * 0)),valStr); + + painter.setPen(QColor::fromRgb(128,128,64)); + painter.setBrush(gradientBrush); + + if (!m_showMinMax) { + //draw just the value + int newval = (height()-2-twiceFontHeight) * ((float)(curVal - m_min) / ((m_max-m_min)+1)); + int yVal = (height()-2-twiceFontHeight) - newval; + painter.drawRect(1,yVal,width()-3,((height()-2) - yVal - twiceFontHeight)); } + else { + //draw the value + int newval = (height()-2-twiceFontHeight) * ((float)(curVal / 3001.0)); + int yVal = (height()-2-twiceFontHeight) - newval; + painter.drawRect(1,yVal,width()-3,((height()-2) - yVal - twiceFontHeight)); - QString valstr = QString::number(m_value); - painter.setPen(QColor::fromRgb(255,255,255)); - painter.drawText((width()/2.0) - (painter.fontMetrics().width(m_name)/2.0),((height()-3) - (painter.fontMetrics().height()*1)),m_name); - painter.drawText((width()/2.0) - (painter.fontMetrics().width(valstr)/2.0),((height()-3) - (painter.fontMetrics().height() * 0)),valstr); - if (m_showMinMax) - { - painter.setBrush(Qt::NoBrush); + //draw min max indicator bars painter.setPen(QColor::fromRgb(255,0,0)); - int maxyval = (height()-3 - (painter.fontMetrics().height() * 2)) - (((height()-3-(painter.fontMetrics().height() * 2)) * ((float)m_max / 3000.0))); - int minyval = (height()-3 - (painter.fontMetrics().height() * 2)) - (((height()-3-(painter.fontMetrics().height() * 2)) * ((float)m_min / 3000.0))); - painter.drawRect(2,maxyval,width()-3,minyval - maxyval); + painter.setBrush(Qt::NoBrush); + + int yMax = (height()-3 - twiceFontHeight) - (((height()-3-twiceFontHeight) * ((float)m_max / 3000.0))); + int yMin = (height()-3 - twiceFontHeight) - (((height()-3-twiceFontHeight) * ((float)m_min / 3000.0))); + painter.drawRect(2,yMax,width()-3,yMin - yMax); + + //draw min and max labels QString minstr = QString::number(m_min); - painter.drawText((width() / 2.0) - (painter.fontMetrics().width("min")/2.0),minyval,"min"); - painter.drawText((width() / 2.0) - (painter.fontMetrics().width(minstr)/2.0),minyval + painter.fontMetrics().height(),minstr); + painter.drawText((width() / 2.0) - (painter.fontMetrics().width("min")/2.0),yMin,"min"); + painter.drawText((width() / 2.0) - (painter.fontMetrics().width(minstr)/2.0),yMin + fontHeight,minstr); QString maxstr = QString::number(m_max); - painter.drawText((width() / 2.0) - (painter.fontMetrics().width("max")/2.0),maxyval,"max"); - painter.drawText((width() / 2.0) - (painter.fontMetrics().width(maxstr)/2.0),maxyval + painter.fontMetrics().height(),maxstr); + painter.drawText((width() / 2.0) - (painter.fontMetrics().width("max")/2.0),yMax,"max"); + painter.drawText((width() / 2.0) - (painter.fontMetrics().width(maxstr)/2.0),yMax + fontHeight,maxstr); - //painter.drawRect(width() * ,2,((width()-1) * ((float)m_max / 3000.0)) - (width() * ((float)m_min / 3000.0)),(height()-5) - (painter.fontMetrics().height() * 2)); } } - else + else //horizontal orientation { - painter.drawRect(0,0,width()-1,(height()-1) - (painter.fontMetrics().height() * 2)); - painter.setBrush(Qt::SolidPattern); + QLinearGradient hGradientBrush(0, 0, this->width(), this->height()); + hGradientBrush.setColorAt(0.0,DIMMEST_COLOR); + hGradientBrush.setColorAt(0.5,MIDBRIGHT_COLOR); + hGradientBrush.setColorAt(1.0, BRIGHTEST_COLOR); + + //draw the value + painter.drawRect(0,0,width()-1,(height()-1) - twiceFontHeight); painter.setPen(QColor::fromRgb(50,255,50)); - if (!m_showMinMax) - { - painter.drawRect(1,1,(width()-3) * ((float)(currval-m_min) / (m_max-m_min)),(height()-3) - (painter.fontMetrics().height() * 2)); - } - else - { - painter.drawRect(1,1,(width()-3) * ((float)currval / 3000.0),(height()-3) - (painter.fontMetrics().height() * 2)); - } + painter.setBrush(hGradientBrush); + + //draw the value string painter.setPen(QColor::fromRgb(255,255,255)); QString valstr = QString::number(m_value); - painter.drawText((width()/2.0) - (painter.fontMetrics().width(m_name)/2.0),((height()-3) - (painter.fontMetrics().height()*1)),m_name); - painter.drawText((width()/2.0) - (painter.fontMetrics().width(valstr)/2.0),((height()-3) - (painter.fontMetrics().height() * 0)),valstr); - if (m_showMinMax) - { + painter.drawText((width()/2.0) - (painter.fontMetrics().width(m_name)/2.0),((height()-3) - (fontHeight*1)),m_name); + painter.drawText((width()/2.0) - (painter.fontMetrics().width(valstr)/2.0),((height()-3) - (fontHeight * 0)),valstr); + + + painter.setPen(QColor::fromRgb(0,128,0)); + painter.setBrush(hGradientBrush); + + if (!m_showMinMax) { + //draw just the value + painter.drawRect(1,1,(width()-3) * ((float)(curVal-m_min) / (m_max-m_min)),(height()-3) - twiceFontHeight); + } + else { + //draw the value + painter.drawRect(1,1,(width()-3) * ((float)curVal / 3000.0),(height()-3) - twiceFontHeight); + + //draw the min and max bars painter.setBrush(Qt::NoBrush); painter.setPen(QColor::fromRgb(255,0,0)); - painter.drawRect(width() * ((float)m_min / 3000.0),2,((width()-1) * ((float)m_max / 3000.0)) - (width() * ((float)m_min / 3000.0)),(height()-5) - (painter.fontMetrics().height() * 2)); + painter.drawRect(width() * ((float)m_min / 3000.0),2,((width()-1) * ((float)m_max / 3000.0)) - (width() * ((float)m_min / 3000.0)),(height()-5) - twiceFontHeight); + //draw the min and max strings QString minstr = QString::number(m_min); painter.drawText((width() * ((float)m_min / 3000.0)) - (painter.fontMetrics().width("min")/2.0),((height()-3) - (painter.fontMetrics().height()*1)),"min"); painter.drawText((width() * ((float)m_min / 3000.0)) - (painter.fontMetrics().width(minstr)/2.0),((height()-3) - (painter.fontMetrics().height() * 0)),minstr); @@ -141,6 +183,19 @@ void QGCRadioChannelDisplay::hideMinMax() update(); } + +void QGCRadioChannelDisplay::setValueAndRange(int val, int min, int max) +{ + setValue(val); + setMinMax(min,max); +} + +void QGCRadioChannelDisplay::setMinMax(int min, int max) +{ + setMin(min); + setMax(max); +} + void QGCRadioChannelDisplay::setMin(int value) { m_min = value; diff --git a/src/ui/designer/QGCRadioChannelDisplay.h b/src/ui/designer/QGCRadioChannelDisplay.h index be8958a23a8bd9e63e718ebaa3ef356f4a8b6e4f..2b90a946f5f595c1d3f7a761b092d122d1119165 100644 --- a/src/ui/designer/QGCRadioChannelDisplay.h +++ b/src/ui/designer/QGCRadioChannelDisplay.h @@ -12,12 +12,15 @@ public: void setValue(int value); void showMinMax(); void hideMinMax(); + void setValueAndRange(int val, int min, int max); + void setMinMax(int min, int max); void setMin(int value); void setMax(int value); void setName(QString name); int value() { return m_value; } int min() { return m_min; } int max() { return m_max; } + protected: void paintEvent(QPaintEvent *event); private: @@ -27,6 +30,8 @@ private: int m_max; bool m_showMinMax; QString m_name; + QBrush m_fillBrush; + signals: public slots: diff --git a/src/ui/designer/QGCTextLabel.cc b/src/ui/designer/QGCTextLabel.cc index dd2bbf940ce97afeaeee45e1859ab56e1d7bfee8..0a74c9d7f4b689b98b78dcf3df9cd32749d8420f 100644 --- a/src/ui/designer/QGCTextLabel.cc +++ b/src/ui/designer/QGCTextLabel.cc @@ -7,7 +7,7 @@ #include "UASManager.h" QGCTextLabel::QGCTextLabel(QWidget *parent) : - QGCToolWidgetItem("Command Button", parent), + QGCToolWidgetItem("Text Label", parent), ui(new Ui::QGCTextLabel) { uas = 0; @@ -15,17 +15,15 @@ QGCTextLabel::QGCTextLabel(QWidget *parent) : ui->setupUi(this); connect(ui->editFinishButton, SIGNAL(clicked()), this, SLOT(endEditMode())); + connect(ui->isMavCommand, SIGNAL(toggled(bool)), this, SLOT(update_isMavCommand())); // Hide all edit items ui->editFinishButton->hide(); ui->editNameLabel->hide(); - ui->editTextParam->hide(); - ui->editComponentSpinBox->hide(); ui->editLine1->hide(); ui->editLine2->hide(); - - // Add commands to combo box - + ui->isMavCommand->hide(); + ui->textLabel->setText(QString()); } QGCTextLabel::~QGCTextLabel() @@ -33,95 +31,32 @@ QGCTextLabel::~QGCTextLabel() delete ui; } -void QGCTextLabel::startEditMode() +void QGCTextLabel::setEditMode(bool editMode) { - // Hide elements - ui->nameLabel->hide(); - - ui->editTextParam->show(); - ui->editFinishButton->show(); - ui->editNameLabel->show(); - ui->editComponentSpinBox->show(); - ui->editLine1->show(); - ui->editLine2->show(); - - // Attempt to undock the dock widget - QWidget* p = this; - QDockWidget* dock; - - do { - p = p->parentWidget(); - dock = dynamic_cast(p); - - if (dock) - { - dock->setFloating(true); - break; - } - } while (p && !dock); - - isInEditMode = true; -} - -void QGCTextLabel::endEditMode() -{ - ui->editFinishButton->hide(); - ui->editTextParam->hide(); - ui->editNameLabel->hide(); - ui->editComponentSpinBox->hide(); - ui->editLine1->hide(); - ui->editLine2->hide(); - - ui->nameLabel->show(); - - // Write to settings - emit editingFinished(); - - // Attempt to dock the dock widget - QWidget* p = this; - QDockWidget* dock; - - do { - p = p->parentWidget(); - dock = dynamic_cast(p); - - if (dock) - { - dock->setFloating(false); - break; - } - } while (p && !dock); - - isInEditMode = false; + if(!editMode) + update_isMavCommand(); + ui->editFinishButton->setVisible(editMode); + ui->editNameLabel->setVisible(editMode); + ui->editLine1->setVisible(editMode); + ui->editLine2->setVisible(editMode); + ui->isMavCommand->setVisible(editMode); + + QGCToolWidgetItem::setEditMode(editMode); } void QGCTextLabel::writeSettings(QSettings& settings) { - qDebug() << "COMMAND BUTTON WRITING SETTINGS"; - settings.setValue("TYPE", "COMMANDBUTTON"); - settings.setValue("QGC_COMMAND_BUTTON_DESCRIPTION", ui->nameLabel->text()); + settings.setValue("TYPE", "TEXT"); + settings.setValue("QGC_TEXT_TEXT", ui->editNameLabel->text()); + settings.setValue("QGC_TEXT_SOURCE", ui->isMavCommand->isChecked()?"MAV":"NONE"); settings.sync(); } void QGCTextLabel::readSettings(const QString& pre,const QVariantMap& settings) { - ui->editTextParam->setText(settings.value(pre + "QGC_TEXT_SOURCE", "UNKNOWN").toString()); - //ui->editCommandComboBox->setCurrentIndex(settings.value(pre + "QGC_COMMAND_BUTTON_COMMANDID", 0).toInt()); - if (ui->editTextParam->text() == "NONE") - { - ui->editNameLabel->setText(settings.value(pre + "QGC_TEXT_TEXT","").toString()); - ui->nameLabel->setText(ui->editNameLabel->text()); - } - else if (ui->editTextParam->text() == "MAV") - { - //MAV command text - connect(uas,SIGNAL(textMessageReceived(int,int,int,QString)),this,SLOT(textMessageReceived(int,int,int,QString))); - } - - //int commandId = settings.value(pre + "QGC_COMMAND_BUTTON_COMMANDID", 0).toInt(); - - //ui->editNameLabel->setText(settings.value(pre + "QGC_COMMAND_BUTTON_DESCRIPTION", "ERROR LOADING BUTTON").toString()); - //ui->nameLabel->setText(settings.value(pre + "QGC_COMMAND_BUTTON_DESCRIPTION", "ERROR LOADING BUTTON").toString()); + ui->editNameLabel->setText(settings.value(pre + "QGC_TEXT_TEXT","").toString()); + ui->isMavCommand->setChecked(settings.value(pre + "QGC_TEXT_SOURCE", "NONE").toString() == "MAV"); + update_isMavCommand(); } void QGCTextLabel::textMessageReceived(int uasid, int component, int severity, QString message) { @@ -148,31 +83,40 @@ void QGCTextLabel::textMessageReceived(int uasid, int component, int severity, Q void QGCTextLabel::readSettings(const QSettings& settings) { - //ui->editNameLabel->setText(settings.value("QGC_COMMAND_BUTTON_DESCRIPTION", "ERROR LOADING BUTTON").toString()); - //ui->nameLabel->setText(settings.value("QGC_COMMAND_BUTTON_DESCRIPTION", "ERROR LOADING BUTTON").toString()); - ui->editTextParam->setText(settings.value("QGC_TEXT_SOURCE", "UNKNOWN").toString()); - ui->editNameLabel->setText(settings.value("QGC_TEXT_TEXT","").toString()); - //ui->editCommandComboBox->setCurrentIndex(settings.value(pre + "QGC_COMMAND_BUTTON_COMMANDID", 0).toInt()); - if (ui->editTextParam->text() == "NONE") - { - ui->textLabel->setText(ui->editNameLabel->text()); - ui->nameLabel->setText(""); - } - else if (ui->editTextParam->text() == "MAV") - { - //MAV command text - ui->nameLabel->setText(ui->editNameLabel->text()); - ui->textLabel->setText(""); - connect(uas,SIGNAL(textMessageReceived(int,int,int,QString)),this,SLOT(textMessageReceived(int,int,int,QString))); - } + ui->editNameLabel->setText(settings.value("QGC_TEXT_TEXT","").toString()); //Place this before setting isMavCommand + ui->isMavCommand->setChecked(settings.value("QGC_TEXT_SOURCE", "NONE").toString() == "MAV"); + update_isMavCommand(); } + void QGCTextLabel::enableText(int num) { enabledNum = num; - } void QGCTextLabel::setActiveUAS(UASInterface *uas) { + if(this->uas) + this->uas->disconnect(this); this->uas = uas; + update_isMavCommand(); //Might need to update the signal connections +} + +void QGCTextLabel::update_isMavCommand() +{ + ui->textLabel->setText(""); + if (!ui->isMavCommand->isChecked()) + { + ui->nameLabel->setText(ui->editNameLabel->text()); + if(this->uas) + disconnect(uas,SIGNAL(textMessageReceived(int,int,int,QString)),this,SLOT(textMessageReceived(int,int,int,QString))); + if(ui->nameLabel->text().isEmpty()) + ui->nameLabel->setText(tr("Text Label")); //Show something, so that we don't end up with just an empty label + } + else + { + //MAV command text + ui->nameLabel->setText(ui->editNameLabel->text()); + if(this->uas) + connect(uas,SIGNAL(textMessageReceived(int,int,int,QString)),this,SLOT(textMessageReceived(int,int,int,QString))); + } } diff --git a/src/ui/designer/QGCTextLabel.h b/src/ui/designer/QGCTextLabel.h index 67ed0ae638c2aa142f1e4faf04a83de175749648..8e8cd509eab313404654f370b1f171bb92b4a93e 100644 --- a/src/ui/designer/QGCTextLabel.h +++ b/src/ui/designer/QGCTextLabel.h @@ -19,13 +19,16 @@ public: ~QGCTextLabel(); void setActiveUAS(UASInterface *uas); void enableText(int num); + virtual void setEditMode(bool editMode); public slots: - void startEditMode(); - void endEditMode(); void writeSettings(QSettings& settings); void readSettings(const QSettings& settings); void readSettings(const QString& pre,const QVariantMap& settings); - void textMessageReceived(int uasid, int component, int severity, QString message); + void textMessageReceived(int uasid, int componentId, int severity, QString message); + +private slots: + void update_isMavCommand(); + private: int enabledNum; Ui::QGCTextLabel *ui; diff --git a/src/ui/designer/QGCTextLabel.ui b/src/ui/designer/QGCTextLabel.ui index 78ba1dda55884e0df0c0dca04935d8808d11b4fb..f5f909d1fb5d60b271a5ccaf5b8f8bc1bdf79efb 100644 --- a/src/ui/designer/QGCTextLabel.ui +++ b/src/ui/designer/QGCTextLabel.ui @@ -6,34 +6,15 @@ 0 0 - 1183 - 166 + 554 + 107 Form - - - 6 - - - 3 - - - 6 - - - 3 - - - - - <Label Description Label (in front of text)> - - - - + + @@ -46,50 +27,82 @@ - - - - - 50 - 0 - - - - Description - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + + + + + + + + Label Description + + + + + + + This is only for advanced use, and allows a label to display the results of a Command Button. + + + Mav Command + + + + - - - - <Text Param> - - + + + + + + + 50 + 0 + + + + Text Label + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + mav result + + + + - - - - Done - - + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Done + + + + - - - - Component ID: - - - 0 - - - 255 - - - - + @@ -102,13 +115,6 @@ - - - - TextLabel - - - @@ -120,8 +126,8 @@ setText(QString) - 114 - 22 + 280 + 32 114 @@ -129,5 +135,21 @@
+ + editNameLabel + returnPressed() + editFinishButton + animateClick() + + + 136 + 20 + + + 498 + 86 + + +
diff --git a/src/ui/designer/QGCToolWidget.cc b/src/ui/designer/QGCToolWidget.cc index 7f976f68ae28352ac4a640f3b95a5b7d2df3061b..2eeae5b26f3a963f71d66a83463b63492ef6608d 100644 --- a/src/ui/designer/QGCToolWidget.cc +++ b/src/ui/designer/QGCToolWidget.cc @@ -13,10 +13,11 @@ #include "QGCParamSlider.h" #include "QGCComboBox.h" #include "QGCTextLabel.h" +#include "QGCXYPlot.h" #include "QGCCommandButton.h" #include "UASManager.h" -QGCToolWidget::QGCToolWidget(const QString& title, QWidget *parent, QSettings* settings) : +QGCToolWidget::QGCToolWidget(const QString& objectName, const QString& title, QWidget *parent, QSettings* settings) : QWidget(parent), mav(NULL), mainMenuAction(NULL), @@ -27,32 +28,12 @@ QGCToolWidget::QGCToolWidget(const QString& title, QWidget *parent, QSettings* s ui->setupUi(this); if (settings) loadSettings(*settings); - if (title == "Unnamed Tool") - { - widgetTitle = QString("%1 %2").arg(title).arg(QGCToolWidget::instances()->count()); - } - //qDebug() << "WidgetTitle" << widgetTitle; - - setObjectName(widgetTitle); createActions(); toolLayout = ui->toolLayout; toolLayout->setAlignment(Qt::AlignTop); toolLayout->setSpacing(8); - QDockWidget* dock = dynamic_cast(this->parentWidget()); - if (dock) { - dock->setWindowTitle(widgetTitle); - dock->setObjectName(widgetTitle+"DOCK"); - } - - // Try with parent - dock = dynamic_cast(parent); - if (dock) { - dock->setWindowTitle(widgetTitle); - dock->setObjectName(widgetTitle+"DOCK"); - } - - this->setWindowTitle(widgetTitle); + this->setTitle(widgetTitle); QList systems = UASManager::instance()->getUASList(); foreach (UASInterface* uas, systems) { @@ -63,30 +44,24 @@ QGCToolWidget::QGCToolWidget(const QString& title, QWidget *parent, QSettings* s } } connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(addUAS(UASInterface*))); - if (!instances()->contains(widgetTitle)) instances()->insert(widgetTitle, this); - // Enforce storage if this not loaded from settings - // is MUST NOT BE SAVED if it was loaded from settings! - //if (!settings) storeWidgetsToSettings(); + if(!objectName.isEmpty()) { + instances()->insert(objectName, this); + setObjectName(objectName); + } //Otherwise we must call loadSettings() immediately to set the object name } QGCToolWidget::~QGCToolWidget() { if (mainMenuAction) mainMenuAction->deleteLater(); - if (QGCToolWidget::instances()) QGCToolWidget::instances()->remove(widgetTitle); + if (QGCToolWidget::instances()) QGCToolWidget::instances()->remove(objectName()); delete ui; } void QGCToolWidget::setParent(QWidget *parent) { QWidget::setParent(parent); - // Try with parent - QDockWidget* dock = dynamic_cast(parent); - if (dock) - { - dock->setWindowTitle(getTitle()); - dock->setObjectName(getTitle()+"DOCK"); - } + setTitle(getTitle()); //Update titles } /** @@ -119,11 +94,10 @@ QList QGCToolWidget::createWidgetsFromSettings(QWidget* parent, QString name = settings->value("TITLE", "").toString(); QString objname = settings->value("OBJECT_NAME", "").toString(); - if (!instances()->contains(name) && name.length() != 0) + if (!instances()->contains(objname) && !objname.isEmpty()) { //qDebug() << "CREATED WIDGET:" << name; - QGCToolWidget* tool = new QGCToolWidget(name, parent, settings); - tool->setObjectName(objname); + QGCToolWidget* tool = new QGCToolWidget(objname, name, parent, settings); newWidgets.append(tool); } else if (name.length() == 0) @@ -175,12 +149,13 @@ bool QGCToolWidget::loadSettings(const QString& settings, bool singleinstance) QStringList groups = set.childGroups(); if (groups.length() > 0) { - QString widgetName = groups.first(); - this->setObjectName(widgetName); - if (singleinstance && QGCToolWidget::instances()->keys().contains(widgetName)) return false; + QString objectName = groups.first(); + setObjectName(objectName); + if (singleinstance && QGCToolWidget::instances()->contains(objectName)) return false; + instances()->insert(objectName, this); // Do not use setTitle() here, // interferes with loading settings - widgetTitle = widgetName; + widgetTitle = objectName; //qDebug() << "WIDGET TITLE LOADED: " << widgetName; loadSettings(set); return true; @@ -296,7 +271,12 @@ void QGCToolWidget::loadSettings(QVariantMap& settings) else if (type == "COMBO") { item = new QGCComboBox(this); - //qDebug() << "CREATED PARAM COMBOBOX"; + //qDebug() << "CREATED COMBOBOX"; + } + else if (type == "XYPLOT") + { + item = new QGCXYPlot(this); + //qDebug() << "CREATED XYPlot"; } if (item) { @@ -356,6 +336,11 @@ void QGCToolWidget::loadSettings(QSettings& settings) item->setObjectName(settings.value("QGC_TEXT_ID").toString()); item->setActiveUAS(mav); } + else if (type == "XYPLOT") + { + item = new QGCXYPlot(this); + item->setActiveUAS(mav); + } if (item) { @@ -375,26 +360,13 @@ void QGCToolWidget::loadSettings(QSettings& settings) settings.endGroup(); } -void QGCToolWidget::storeWidgetsToSettings(QString settingsFile) +void QGCToolWidget::storeWidgetsToSettings(QSettings &settings) //static { - // Store list of widgets - QSettings* settings; - if (!settingsFile.isEmpty()) - { - settings = new QSettings(settingsFile, QSettings::IniFormat); - //qDebug() << "STORING SETTINGS TO" << settings->fileName(); - } - else - { - settings = new QSettings(); - //qDebug() << "STORING SETTINGS TO DEFAULT" << settings->fileName(); - } - - settings->beginGroup("Custom_Tool_Widgets"); - int preArraySize = settings->beginReadArray("QGC_TOOL_WIDGET_NAMES"); - settings->endArray(); + settings.beginGroup("Custom_Tool_Widgets"); + int preArraySize = settings.beginReadArray("QGC_TOOL_WIDGET_NAMES"); + settings.endArray(); - settings->beginWriteArray("QGC_TOOL_WIDGET_NAMES"); + settings.beginWriteArray("QGC_TOOL_WIDGET_NAMES"); int num = 0; for (int i = 0; i < qMax(preArraySize, instances()->size()); ++i) { @@ -403,44 +375,34 @@ void QGCToolWidget::storeWidgetsToSettings(QString settingsFile) // Updating value if (!instances()->values().at(i)->fromMetaData()) { - settings->setArrayIndex(num++); - settings->setValue("TITLE", instances()->values().at(i)->getTitle()); - settings->setValue("OBJECT_NAME", instances()->values().at(i)->objectName()); - //qDebug() << "WRITING TITLE" << instances()->values().at(i)->getTitle(); + settings.setArrayIndex(num++); + settings.setValue("TITLE", instances()->values().at(i)->getTitle()); + settings.setValue("OBJECT_NAME", instances()->values().at(i)->objectName()); + qDebug() << "WRITING TITLE" << instances()->values().at(i)->getTitle() << "object:" << instances()->values().at(i)->objectName(); } } else { // Deleting old value - settings->remove("TITLE"); + settings.remove("TITLE"); } } - settings->endArray(); + settings.endArray(); // Store individual widget items for (int i = 0; i < instances()->size(); ++i) { - instances()->values().at(i)->storeSettings(*settings); + instances()->values().at(i)->storeSettings(settings); } - settings->endGroup(); - settings->sync(); - delete settings; -} - -void QGCToolWidget::storeSettings() -{ - QSettings settings; - storeSettings(settings); -} - -void QGCToolWidget::storeSettings(const QString& settingsFile) -{ - QSettings settings(settingsFile, QSettings::IniFormat); - storeSettings(settings); + settings.endGroup(); + settings.sync(); } void QGCToolWidget::storeSettings(QSettings& settings) { + /* This function should be called from storeWidgetsToSettings() which sets up the group etc */ + Q_ASSERT(settings.group() == "Custom_Tool_Widgets"); + if (isFromMetaData) { //Refuse to store if this is loaded from metadata or dynamically generated. @@ -450,17 +412,11 @@ void QGCToolWidget::storeSettings(QSettings& settings) settings.beginGroup(widgetTitle); settings.beginWriteArray("QGC_TOOL_WIDGET_ITEMS"); int k = 0; // QGCToolItem counter - for (int j = 0; j < children().size(); ++j) - { - // Store only QGCToolWidgetItems - QGCToolWidgetItem* item = dynamic_cast(children().at(j)); - if (item) - { - // Only count actual tool widget item children - settings.setArrayIndex(k++); - // Store the ToolWidgetItem - item->writeSettings(settings); - } + foreach(QGCToolWidgetItem *item, toolItemList) { + // Only count actual tool widget item children + settings.setArrayIndex(k++); + // Store the ToolWidgetItem + item->writeSettings(settings); } //qDebug() << "WROTE" << k << "SUB-WIDGETS TO SETTINGS"; settings.endArray(); @@ -482,6 +438,8 @@ void QGCToolWidget::contextMenuEvent (QContextMenuEvent* event) QMenu menu(this); menu.addAction(addParamAction); menu.addAction(addCommandAction); + menu.addAction(addLabelAction); + menu.addAction(addPlotAction); menu.addSeparator(); menu.addAction(setTitleAction); menu.addAction(exportAction); @@ -517,6 +475,14 @@ void QGCToolWidget::createActions() addCommandAction->setStatusTip(tr("Add a new action button to the tool")); connect(addCommandAction, SIGNAL(triggered()), this, SLOT(addCommand())); + addLabelAction = new QAction(tr("New &Text Label"), this); + addLabelAction->setStatusTip(tr("Add a new label to the tool")); + connect(addLabelAction, SIGNAL(triggered()), this, SLOT(addLabel())); + + addPlotAction = new QAction(tr("New &XY Plot"), this); + addPlotAction->setStatusTip(tr("Add a XY Plot to the tool")); + connect(addPlotAction, SIGNAL(triggered()), this, SLOT(addPlot())); + setTitleAction = new QAction(tr("Set Widget Title"), this); setTitleAction->setStatusTip(tr("Set the title caption of this tool widget")); connect(setTitleAction, SIGNAL(triggered()), this, SLOT(setTitle())); @@ -541,53 +507,39 @@ QMap* QGCToolWidget::instances() return instances; } -QList* QGCToolWidget::itemList() -{ - static QList* instances; - if (!instances) instances = new QList(); - return instances; -} void QGCToolWidget::addParam(int uas,int component,QString paramname,QVariant value) { isFromMetaData = true; QGCParamSlider* slider = new QGCParamSlider(this); - connect(slider, SIGNAL(destroyed()), this, SLOT(storeSettings())); - if (ui->hintLabel) - { - ui->hintLabel->deleteLater(); - ui->hintLabel = NULL; - } - toolLayout->addWidget(slider); + addToolWidget(slider); slider->setActiveUAS(mav); slider->setParameterValue(uas,component,0,-1,paramname,value); - - } void QGCToolWidget::addParam() { - QGCParamSlider* slider = new QGCParamSlider(this); - connect(slider, SIGNAL(destroyed()), this, SLOT(storeSettings())); - if (ui->hintLabel) - { - ui->hintLabel->deleteLater(); - ui->hintLabel = NULL; - } - toolLayout->addWidget(slider); - slider->startEditMode(); + addToolWidgetAndEdit(new QGCParamSlider(this)); } void QGCToolWidget::addCommand() { - QGCCommandButton* button = new QGCCommandButton(this); - connect(button, SIGNAL(destroyed()), this, SLOT(storeSettings())); - if (ui->hintLabel) - { - ui->hintLabel->deleteLater(); - ui->hintLabel = NULL; - } - toolLayout->addWidget(button); - button->startEditMode(); + addToolWidgetAndEdit(new QGCCommandButton(this)); +} + +void QGCToolWidget::addLabel() +{ + addToolWidgetAndEdit(new QGCTextLabel(this)); +} + +void QGCToolWidget::addPlot() +{ + addToolWidgetAndEdit(new QGCXYPlot(this)); +} + +void QGCToolWidget::addToolWidgetAndEdit(QGCToolWidgetItem* widget) +{ + addToolWidget(widget); + widget->startEditMode(); } void QGCToolWidget::addToolWidget(QGCToolWidgetItem* widget) @@ -597,11 +549,21 @@ void QGCToolWidget::addToolWidget(QGCToolWidgetItem* widget) ui->hintLabel->deleteLater(); ui->hintLabel = NULL; } - connect(widget, SIGNAL(destroyed()), this, SLOT(storeSettings())); + connect(widget, SIGNAL(editingFinished()), this, SLOT(storeWidgetsToSettings())); + connect(widget, SIGNAL(destroyed()), this, SLOT(widgetRemoved())); toolLayout->addWidget(widget); toolItemList.append(widget); } +void QGCToolWidget::widgetRemoved() +{ + //Must static cast and not dynamic cast since the object is in the destructor + //and we only want to use it as a pointer value + QGCToolWidgetItem *widget = static_cast(QObject::sender()); + toolItemList.removeAll(widget); + storeWidgetsToSettings(); +} + void QGCToolWidget::exportWidget() { const QString widgetFileExtension(".qgw"); @@ -610,7 +572,8 @@ void QGCToolWidget::exportWidget() { fileName = fileName.append(widgetFileExtension); } - storeSettings(fileName); + QSettings settings(fileName, QSettings::IniFormat); + storeSettings(settings); } void QGCToolWidget::importWidget() @@ -620,7 +583,7 @@ void QGCToolWidget::importWidget() loadSettings(fileName); } -const QString QGCToolWidget::getTitle() +QString QGCToolWidget::getTitle() const { return widgetTitle; } @@ -641,36 +604,20 @@ void QGCToolWidget::setTitle() } } -void QGCToolWidget::setWindowTitle(const QString& title) +void QGCToolWidget::setTitle(const QString& title) { // Sets title and calls setWindowTitle on QWidget widgetTitle = title; QWidget::setWindowTitle(title); -} - -void QGCToolWidget::setTitle(QString title) -{ - // Remove references to old title - /*QSettings settings; - settings.beginGroup(widgetTitle); - settings.remove(""); - settings.endGroup(); - settings.sync();*/ - - if (instances()->contains(widgetTitle)) instances()->remove(widgetTitle); - - // Switch to new title - widgetTitle = title; - - if (!instances()->contains(title)) instances()->insert(title, this); - QWidget::setWindowTitle(title); - QDockWidget* parent = dynamic_cast(this->parentWidget()); - if (parent) parent->setWindowTitle(title); - // Store all widgets - //storeWidgetsToSettings(); - + QDockWidget* dock = dynamic_cast(this->parentWidget()); + if (dock) + dock->setWindowTitle(widgetTitle); emit titleChanged(title); if (mainMenuAction) mainMenuAction->setText(title); + + //Do not save the settings here, because this function might be + //called while loading, and thus saving here could end up clobbering + //all of the other widgets } void QGCToolWidget::setMainMenuAction(QAction* action) @@ -684,12 +631,13 @@ void QGCToolWidget::deleteWidget() // Hide this->hide(); - instances()->remove(getTitle()); - /*QSettings settings; - settings.beginGroup(getTitle()); - settings.remove(""); + instances()->remove(objectName()); + + QSettings settings; + settings.beginGroup("QGC_MAINWINDOW"); + settings.remove(QString("TOOL_PARENT_") + objectName()); settings.endGroup(); - storeWidgetsToSettings();*/ + storeWidgetsToSettings(); // Delete diff --git a/src/ui/designer/QGCToolWidget.h b/src/ui/designer/QGCToolWidget.h index c3abb0faf240834ddb16f57315d54e8db2c1e542..7ab9ef679d8ba35752ad113c58727d77bf446f5c 100644 --- a/src/ui/designer/QGCToolWidget.h +++ b/src/ui/designer/QGCToolWidget.h @@ -19,7 +19,7 @@ class QGCToolWidget : public QWidget Q_OBJECT public: - explicit QGCToolWidget(const QString& title=QString("Unnamed Tool"), QWidget *parent = 0, QSettings* settings = 0); + explicit QGCToolWidget(const QString& objectName, const QString& title, QWidget *parent = 0, QSettings* settings = 0); ~QGCToolWidget(); /** @brief Factory method to instantiate all tool widgets */ @@ -29,12 +29,15 @@ public: /** @brief All instances of this class */ static QMap* instances(); /** @brief Get title of widget */ - const QString getTitle(); + QString getTitle() const; - int isVisible(int view) { return viewVisible.value(view, false); } + int isVisible(int view) const { return viewVisible.value(view, false); } Qt::DockWidgetArea getDockWidgetArea(int view) { return dockWidgetArea.value(view, Qt::BottomDockWidgetArea); } void setParent(QWidget *parent); + /** @brief Store all widgets of this type to QSettings */ + static void storeWidgetsToSettings(QSettings &settingsFile); + public slots: void addUAS(UASInterface* uas); /** @brief Delete this widget */ @@ -44,27 +47,24 @@ public slots: /** @brief Import settings for this widget from a file */ void importWidget(); /** @brief Store all widgets of this type to QSettings */ - static void storeWidgetsToSettings(QString settingsFile=QString()); + void storeWidgetsToSettings() { QSettings settings; QGCToolWidget::storeWidgetsToSettings(settings); } + +public: void loadSettings(QVariantMap& settings); /** @brief Load this widget from a QSettings object */ void loadSettings(QSettings& settings); /** @brief Load this widget from a settings file */ bool loadSettings(const QString& settings, bool singleinstance=false); - /** @brief Store this widget to a QSettings object */ - void storeSettings(QSettings& settings); - /** @brief Store this widget to a settings file */ - void storeSettings(const QString& settingsFile); - /** @brief Store this widget to a settings file */ - void storeSettings(); /** @brief Store the view id and dock widget area */ void setViewVisibilityAndDockWidgetArea(int view, bool visible, Qt::DockWidgetArea area); void setSettings(QVariantMap& settings); QList getParamList(); void setParameterValue(int uas, int component, QString parameterName, const QVariant value); - bool fromMetaData() { return isFromMetaData; } + bool fromMetaData() const { return isFromMetaData; } void showLabel(QString name,int num); + signals: - void titleChanged(QString); + void titleChanged(const QString &title); protected: bool isFromMetaData; @@ -74,6 +74,8 @@ protected: QVariantMap settingsMap; QAction* addParamAction; QAction* addCommandAction; + QAction* addPlotAction; + QAction* addLabelAction; QAction* setTitleAction; QAction* deleteAction; QAction* exportAction; @@ -84,27 +86,36 @@ protected: QMap dockWidgetArea; ///< Dock widget area desired by this widget QMap viewVisible; ///< Visibility in one view QString widgetTitle; - static int instanceCount; ///< Number of instances around void contextMenuEvent(QContextMenuEvent* event); void createActions(); - QList* itemList(); /** @brief Add an existing tool widget */ void addToolWidget(QGCToolWidgetItem* widget); + /** @brief Add an existing tool widget and set it to edit mode */ + void addToolWidgetAndEdit(QGCToolWidgetItem* widget); void hideEvent(QHideEvent* event); public slots: - void setTitle(QString title); + void setTitle(const QString &title); void addParam(int uas,int component,QString paramname,QVariant value); protected slots: void addParam(); void addCommand(); + void addPlot(); + void addLabel(); void setTitle(); - - void setWindowTitle(const QString& title); - + void widgetRemoved(); private: + /** Do not use this from outside the class to set the object name, + * because we cannot track changes to the object name, and the + * QObject::setObjectName() function is not virtual. Instead only + * pass in the object name to the constructor, or use the , then + * never change it again. */ + void setObjectName(const QString &name) { QWidget::setObjectName(name); } + /** Helper for storeWidgetsToSettings() */ + void storeSettings(QSettings& settings); + Ui::QGCToolWidget *ui; }; diff --git a/src/ui/designer/QGCToolWidgetItem.cc b/src/ui/designer/QGCToolWidgetItem.cc index 0d7f95e5cdc28b73a1ad6e1ceebb9ac05113dbd1..236ae6e486835f4a7af7829e99a14b7cebb46564 100644 --- a/src/ui/designer/QGCToolWidgetItem.cc +++ b/src/ui/designer/QGCToolWidgetItem.cc @@ -5,12 +5,13 @@ #include "QGCToolWidget.h" #include "UASManager.h" +#include QGCToolWidgetItem::QGCToolWidgetItem(const QString& name, QWidget *parent) : QWidget(parent), + uas(NULL), isInEditMode(false), qgcToolWidgetItemName(name), - uas(NULL), _component(-1) { startEditAction = new QAction(tr("Edit %1").arg(qgcToolWidgetItemName), this); @@ -20,11 +21,6 @@ QGCToolWidgetItem::QGCToolWidgetItem(const QString& name, QWidget *parent) : deleteAction = new QAction(tr("Delete %1").arg(qgcToolWidgetItemName), this); connect(deleteAction, SIGNAL(triggered()), this, SLOT(deleteLater())); - QGCToolWidget* tool = dynamic_cast(parent); - if (tool) { - connect(this, SIGNAL(editingFinished()), tool, SLOT(storeWidgetsToSettings())); - } - connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*))); // Set first UAS if it exists @@ -54,3 +50,25 @@ void QGCToolWidgetItem::setActiveUAS(UASInterface *uas) { this->uas = uas; } + +void QGCToolWidgetItem::setEditMode(bool editMode) +{ + isInEditMode = editMode; + + // Attempt to undock the dock widget + QWidget* p = this; + QDockWidget* dock; + + do { + p = p->parentWidget(); + dock = dynamic_cast(p); + + if (dock) + { + dock->setFloating(editMode); + break; + } + } while (p && !dock); + + emit editingFinished(); +} diff --git a/src/ui/designer/QGCToolWidgetItem.h b/src/ui/designer/QGCToolWidgetItem.h index e0a0cb0a3337e6e934ada388e3889c1f2880c436..a3b96861090809f709bd0b7024f1c4cfbae3e250 100644 --- a/src/ui/designer/QGCToolWidgetItem.h +++ b/src/ui/designer/QGCToolWidgetItem.h @@ -14,13 +14,16 @@ public: QGCToolWidgetItem(const QString& name, QWidget *parent = 0); ~QGCToolWidgetItem(); - int component() { + int componentId() { return _component; } + virtual void setEditMode(bool editMode); + bool isEditMode() const { return isInEditMode; } public slots: - virtual void startEditMode() {} - virtual void endEditMode() {} + void startEditMode() { setEditMode(true); } + void endEditMode() { setEditMode(false); } + virtual void setComponent(int comp) { _component = comp; } @@ -33,15 +36,18 @@ signals: void editingFinished(); protected: + void contextMenuEvent (QContextMenuEvent* event); + UASInterface* uas; + +private: QAction* startEditAction; QAction* stopEditAction; QAction* deleteAction; bool isInEditMode; QString qgcToolWidgetItemName; - UASInterface* uas; int _component; ///< The MAV component (the process or device ID) - void contextMenuEvent (QContextMenuEvent* event); + }; diff --git a/src/ui/designer/QGCXYPlot.cc b/src/ui/designer/QGCXYPlot.cc new file mode 100644 index 0000000000000000000000000000000000000000..58fcb0ea02611b15cda52da288b5423e3f8c6df6 --- /dev/null +++ b/src/ui/designer/QGCXYPlot.cc @@ -0,0 +1,426 @@ +#include + +#include "QGCXYPlot.h" +#include "ui_QGCXYPlot.h" + +#include "MAVLinkProtocol.h" +#include "UASManager.h" +#include "IncrementalPlot.h" +#include +#include +#include +#include + +class XYPlotCurve : public QwtPlotItem +{ +public: + XYPlotCurve() { + m_maxStorePoints = 10000; + m_maxShowPoints = 15; + setItemAttribute(QwtPlotItem::AutoScale); + minMaxSet = false; + m_color = Qt::white; + m_smoothPoints = 1; + m_startIndex = -1; //Disable + } + + void setMaxDataStorePoints(int max) { m_maxStorePoints = max; itemChanged(); } + void setMaxDataShowPoints(int max) { m_maxShowPoints = max; itemChanged(); } + void setSmoothPoints(int smoothPoints) { m_smoothPoints = smoothPoints; itemChanged(); } + int maxDataStorePoints() const { return m_maxStorePoints; } + int maxDataShowPoints() const { return m_maxShowPoints; } + int smoothPoints() const { return m_smoothPoints; } + + /** Append data, returning the number of removed items */ + int appendData(const QPointF &data) { + if(!minMaxSet) { + xmin = xmax = data.x(); + ymin = ymax = data.y(); + minMaxSet = true; + } else if(m_autoScale) { + xmin = qMin(xmin, data.x()); + xmax = qMax(xmax, data.x()); + ymin = qMin(ymin, data.y()); + ymax = qMax(ymax, data.y()); + } + + m_data.append(data); + int removed = 0; + while(m_data.size() > m_maxStorePoints) { + ++removed; + m_data.removeFirst(); + } + itemChanged(); + return removed; + } + void clear() { + minMaxSet = false; + m_data.clear(); + itemChanged(); + } + void setColor(const QColor &color) { + m_color = color; + } + void unsetMinMax() { + if(m_autoScale) + return; + m_autoScale = true; + //Recalculate the automatic scale + if(m_data.isEmpty()) + minMaxSet = false; + else { + minMaxSet = true; + xmax = xmin = m_data.at(0).x(); + ymax = ymin = m_data.at(0).y(); + for(int i = 1; i < m_data.size(); i++) { + xmin = qMin(xmin, m_data.at(i).x()); + xmax = qMax(xmax, m_data.at(i).x()); + ymin = qMin(ymin, m_data.at(i).y()); + ymax = qMax(ymax, m_data.at(i).y()); + } + } + } + void setMinMax(double xmin, double xmax, double ymin, double ymax ) + { + this->xmin = xmin; + this->xmax = xmax; + this->ymin = ymin; + this->ymax = ymax; + m_autoScale = false; + minMaxSet = true; + itemChanged(); + } + void setStartIndex(int time) { /** Set to -1 to just use latest */ + m_startIndex = time; + itemChanged(); + } + int dataSize() const { return m_data.size(); } + + double xMin() const { return xmin; } + double xMax() const { return xmax; } + double yMin() const { return ymin; } + double yMax() const { return ymax; } + + virtual QwtDoubleRect boundingRect() const { + if(!minMaxSet) + return QwtDoubleRect(1,1,-2,-2); + return QwtDoubleRect(xmin,ymin,xmax-xmin,ymax-ymin); + } + +protected: + /* From QwtPlotItem. Draw the complete series */ + virtual void draw (QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRect &canvasRect) const + { + Q_UNUSED(canvasRect); + QPointF lastPoint; + if(m_data.isEmpty()) + return; + QPointF smoothTotal(0,0); + int smoothCount = 0; + int start; + int count; + if(m_startIndex >= 0) { + int end = qMin(m_startIndex, m_data.size()-1); + start = qBound(0, end - m_maxShowPoints, m_data.size()-1); + count = end - start; + } else { + start = qMax(0,m_data.size() - m_maxShowPoints); + count = qMin(m_data.size()-start, m_maxShowPoints); + } + for(int i = qMax(0,start - m_smoothPoints); i < start; ++i) { + smoothTotal += m_data.at(i); + ++smoothCount; + } + for(int i = 0; i < count; ++i) { + QPointF point = m_data.at(i+start); + if(m_smoothPoints > 1) { + smoothTotal += point; + if(smoothCount >= m_smoothPoints) { + Q_ASSERT(i + start - m_smoothPoints >= 0); + smoothTotal -= m_data.at(i + start - m_smoothPoints); + } else + ++smoothCount; + point = smoothTotal/smoothCount; + } + QPointF paintCoord = QPointF(xMap.xTransform(point.x()), yMap.xTransform(point.y())); + m_color.setAlpha((m_maxShowPoints - count + i)*255/m_maxShowPoints); + p->setPen(m_color); + if(i != 0) + p->drawLine(lastPoint, paintCoord); + if(i == count-1) { + //Draw marker for first point + const int marker_radius = 2; + QRectF marker = QRectF(paintCoord.x()-marker_radius, paintCoord.y()-marker_radius, marker_radius*2+1,marker_radius*2+1); + p->fillRect(marker,QBrush(m_color)); + } + lastPoint = paintCoord; + } + } + +private: + QList< QPointF > m_data; + int m_maxStorePoints; + int m_maxShowPoints; + int m_smoothPoints; /** Number of points to average across */ + mutable QColor m_color; + + double xmin; + double xmax; + double ymin; + double ymax; + bool minMaxSet; + bool m_autoScale; + int m_startIndex; +}; + +QGCXYPlot::QGCXYPlot(QWidget *parent) : + QGCToolWidgetItem("XY Plot", parent), + ui(new Ui::QGCXYPlot), + plot(0), + xycurve(0), + x(0), + x_timestamp_us(0), + x_valid(false), + y(0), + y_timestamp_us(0), + y_valid(false), + max_timestamp_diff_us(10000) /* Default to 10ms tolerance between x and y values */ + + +{ + uas = 0; + ui->setupUi(this); + plot = new QwtPlot(); + + ui->xyPlotLayout->addWidget(plot); + + connect(ui->editFinishButton, SIGNAL(clicked()), this, SLOT(endEditMode())); + + connect(MainWindow::instance(), SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)), + this, SLOT(appendData(int,QString,QString,QVariant,quint64))); + + connect(ui->editXParam, SIGNAL(editTextChanged(QString)), this, SLOT(clearPlot())); + connect(ui->editYParam, SIGNAL(editTextChanged(QString)), this, SLOT(clearPlot())); + + plot->plotLayout()->setAlignCanvasToScales(true); + + QwtLinearScaleEngine* yScaleEngine = new QwtLinearScaleEngine(); + plot->setAxisScaleEngine(QwtPlot::yLeft, yScaleEngine); + + plot->setAxisAutoScale(QwtPlot::xBottom); + plot->setAxisAutoScale(QwtPlot::yLeft); + plot->setAutoReplot(); + xycurve = new XYPlotCurve(); + xycurve->attach(plot); + styleChanged(MainWindow::instance()->getStyle()); + connect(MainWindow::instance(), SIGNAL(styleChanged(MainWindow::QGC_MAINWINDOW_STYLE)), + this, SLOT(styleChanged(MainWindow::QGC_MAINWINDOW_STYLE))); + connect(ui->minX, SIGNAL(valueChanged(double)),this, SLOT(updateMinMaxSettings())); + connect(ui->maxX, SIGNAL(valueChanged(double)),this, SLOT(updateMinMaxSettings())); + connect(ui->minY, SIGNAL(valueChanged(double)),this, SLOT(updateMinMaxSettings())); + connect(ui->maxY, SIGNAL(valueChanged(double)),this, SLOT(updateMinMaxSettings())); + connect(ui->automaticAxisRange, SIGNAL(toggled(bool)),this, SLOT(updateMinMaxSettings())); + connect(ui->maxDataShowSpinBox, SIGNAL(valueChanged(int)),this, SLOT(updateMinMaxSettings())); + connect(ui->maxDataStoreSpinBox, SIGNAL(valueChanged(int)),this, SLOT(updateMinMaxSettings())); + connect(ui->smoothSpinBox, SIGNAL(valueChanged(int)),this, SLOT(updateMinMaxSettings())); + setEditMode(false); +} + +QGCXYPlot::~QGCXYPlot() +{ + delete ui; +} + +void QGCXYPlot::clearPlot() +{ + xycurve->clear(); + plot->clear(); + ui->timeScrollBar->setMaximum(xycurve->dataSize()); + ui->timeScrollBar->setValue(ui->timeScrollBar->maximum()); +} + +void QGCXYPlot::setEditMode(bool editMode) +{ + ui->lblXParam->setVisible(editMode); + ui->lblYParam->setVisible(editMode); + ui->editXParam->setVisible(editMode); + ui->editYParam->setVisible(editMode); + ui->editFinishButton->setVisible(editMode); + ui->editLine1->setVisible(editMode); + ui->editLine2->setVisible(editMode); + ui->lblMaxDataStore->setVisible(editMode); + ui->lblMaxDataShow->setVisible(editMode); + ui->lblMaxX->setVisible(editMode); + ui->lblMaxY->setVisible(editMode); + ui->lblMinX->setVisible(editMode); + ui->lblMinY->setVisible(editMode); + ui->maxX->setVisible(editMode); + ui->maxY->setVisible(editMode); + ui->minX->setVisible(editMode); + ui->minY->setVisible(editMode); + ui->maxDataShowSpinBox->setVisible(editMode); + ui->maxDataStoreSpinBox->setVisible(editMode); + ui->automaticAxisRange->setVisible(editMode); + ui->lblSmooth->setVisible(editMode); + ui->smoothSpinBox->setVisible(editMode); + + if(!editMode) { + plot->setAxisTitle(QwtPlot::xBottom, ui->editXParam->currentText()); + plot->setAxisTitle(QwtPlot::yLeft, ui->editYParam->currentText()); + } + + QGCToolWidgetItem::setEditMode(editMode); + updateMinMaxSettings(); //Do this after calling the parent +} + +void QGCXYPlot::writeSettings(QSettings& settings) +{ + settings.setValue("TYPE", "XYPLOT"); + settings.setValue("QGC_XYPLOT_X", ui->editXParam->currentText()); + settings.setValue("QGC_XYPLOT_Y", ui->editYParam->currentText()); + settings.setValue("QGC_XYPLOT_MINX", ui->minX->value()); + settings.setValue("QGC_XYPLOT_MAXX", ui->maxX->value()); + settings.setValue("QGC_XYPLOT_MINY", ui->minY->value()); + settings.setValue("QGC_XYPLOT_MAXY", ui->maxY->value()); + settings.setValue("QGC_XYPLOT_MAXDATA_STORE", ui->maxDataStoreSpinBox->value()); + settings.setValue("QGC_XYPLOT_MAXDATA_SHOW", ui->maxDataShowSpinBox->value()); + settings.setValue("QGC_XYPLOT_AUTO", ui->automaticAxisRange->isChecked()); + settings.setValue("QGC_XYPLOT_SMOOTH", ui->smoothSpinBox->value()); + + settings.sync(); +} +void QGCXYPlot::readSettings(const QString& pre,const QVariantMap& settings) +{ + ui->editXParam->setEditText(settings.value(pre + "QGC_XYPLOT_X", "").toString()); + ui->editYParam->setEditText(settings.value(pre + "QGC_XYPLOT_Y", "").toString()); + ui->automaticAxisRange->setChecked(settings.value(pre + "QGC_XYPLOT_AUTO", true).toBool()); + ui->minX->setValue(settings.value(pre + "QGC_XYPLOT_MINX", 0).toDouble()); + ui->maxX->setValue(settings.value(pre + "QGC_XYPLOT_MAXX", 0).toDouble()); + ui->minY->setValue(settings.value(pre + "QGC_XYPLOT_MINY", 0).toDouble()); + ui->maxY->setValue(settings.value(pre + "QGC_XYPLOT_MAXY", 0).toDouble()); + ui->maxDataStoreSpinBox->setValue(settings.value(pre + "QGC_XYPLOT_MAXDATA_STORE", 10000).toInt()); + ui->maxDataShowSpinBox->setValue(settings.value(pre + "QGC_XYPLOT_MAXDATA_SHOW", 15).toInt()); + ui->smoothSpinBox->setValue(settings.value(pre + "QGC_XYPLOT_SMOOTH", 1).toInt()); + plot->setAxisTitle(QwtPlot::xBottom, ui->editXParam->currentText()); + plot->setAxisTitle(QwtPlot::yLeft, ui->editYParam->currentText()); + updateMinMaxSettings(); +} + +void QGCXYPlot::readSettings(const QSettings& settings) +{ + ui->editXParam->setEditText(settings.value("QGC_XYPLOT_X", "").toString()); + ui->editYParam->setEditText(settings.value("QGC_XYPLOT_Y", "").toString()); + ui->automaticAxisRange->setChecked(settings.value("QGC_XYPLOT_AUTO", true).toBool()); + ui->minX->setValue(settings.value("QGC_XYPLOT_MINX", 0).toDouble()); + ui->maxX->setValue(settings.value("QGC_XYPLOT_MAXX", 0).toDouble()); + ui->minY->setValue(settings.value("QGC_XYPLOT_MINY", 0).toDouble()); + ui->maxY->setValue(settings.value("QGC_XYPLOT_MAXY", 0).toDouble()); + ui->maxDataStoreSpinBox->setValue(settings.value("QGC_XYPLOT_MAXDATA_STORE", 10000).toInt()); + ui->maxDataShowSpinBox->setValue(settings.value("QGC_XYPLOT_MAXDATA_SHOW", 15).toInt()); + ui->smoothSpinBox->setValue(settings.value("QGC_XYPLOT_SMOOTH", 1).toInt()); + plot->setAxisTitle(QwtPlot::xBottom, ui->editXParam->currentText()); + plot->setAxisTitle(QwtPlot::yLeft, ui->editYParam->currentText()); + updateMinMaxSettings(); +} + +void QGCXYPlot::appendData(int uasId, const QString& curve, const QString& unit, const QVariant& variant, quint64 usec) +{ + Q_UNUSED(uasId); + Q_UNUSED(unit); + if(isEditMode()) { + //When in edit mode, add all the items to the combo box + if(ui->editXParam->findText(curve) == -1) { + ui->editXParam->blockSignals(true); + ui->editYParam->blockSignals(true); + QString oldX = ui->editXParam->currentText(); + QString oldY = ui->editYParam->currentText(); + ui->editXParam->addItem(curve); //Annoyingly this can wipe out the current text + ui->editYParam->addItem(curve); + ui->editXParam->setEditText(oldX); + ui->editYParam->setEditText(oldY); + ui->editXParam->blockSignals(false); + ui->editYParam->blockSignals(false); + } + } + + if(ui->stopStartButton->isChecked()) + return; + + bool ok; + if(curve == ui->editXParam->currentText()) { + x = variant.toDouble(&ok); + if(!ok) + return; + x_timestamp_us = usec; + x_valid = true; + } else if(curve == ui->editYParam->currentText()) { + y = variant.toDouble(&ok); + if(!ok) + return; + y_timestamp_us = usec; + y_valid = true; + } else + return; + + if(x_valid && y_valid && (int)qAbs(y_timestamp_us - x_timestamp_us) <= max_timestamp_diff_us) { + int removed = xycurve->appendData( QPointF(x,y) ); + x_valid = false; + y_valid = false; + bool atMaximum = (ui->timeScrollBar->value() == ui->timeScrollBar->maximum()); + if(ui->timeScrollBar->maximum() != xycurve->dataSize()) { + ui->timeScrollBar->setMaximum(xycurve->dataSize()); + if(atMaximum) + ui->timeScrollBar->setValue(ui->timeScrollBar->maximum()); + } else if(!atMaximum) { //Move the scrollbar to keep current value selected + int value = qMax(ui->timeScrollBar->minimum(), ui->timeScrollBar->value() - removed); + ui->timeScrollBar->setValue(value); + xycurve->setStartIndex(value); + } + } +} + +void QGCXYPlot::styleChanged(MainWindow::QGC_MAINWINDOW_STYLE style) +{ + if (style == MainWindow::QGC_MAINWINDOW_STYLE_LIGHT) + xycurve->setColor(Qt::black); + else + xycurve->setColor(Qt::white); +} + +void QGCXYPlot::updateMinMaxSettings() +{ + bool automatic = ui->automaticAxisRange->isChecked(); + ui->minX->setEnabled(!automatic); + ui->maxX->setEnabled(!automatic); + ui->minY->setEnabled(!automatic); + ui->maxY->setEnabled(!automatic); + if(automatic) { + xycurve->unsetMinMax(); + } else { + xycurve->setMinMax(ui->minX->value(), ui->maxX->value(), ui->minY->value(), ui->maxY->value()); + } + xycurve->setMaxDataStorePoints(ui->maxDataStoreSpinBox->value()); + xycurve->setMaxDataShowPoints(ui->maxDataShowSpinBox->value()); + xycurve->setSmoothPoints(ui->smoothSpinBox->value()); +} + +void QGCXYPlot::on_maxDataShowSpinBox_valueChanged(int value) +{ + ui->maxDataStoreSpinBox->setMinimum(value); + if(ui->maxDataStoreSpinBox->value() < value) + ui->maxDataStoreSpinBox->setValue(value); +} + +void QGCXYPlot::on_stopStartButton_toggled(bool checked) +{ + if(!checked) + clearPlot(); +} + +void QGCXYPlot::on_timeScrollBar_valueChanged(int value) +{ + if(value == ui->timeScrollBar->maximum()) + xycurve->setStartIndex(-1); + else + xycurve->setStartIndex(value); +} diff --git a/src/ui/designer/QGCXYPlot.h b/src/ui/designer/QGCXYPlot.h new file mode 100644 index 0000000000000000000000000000000000000000..77159d6823041a8a08a3be8ecd523a732595c410 --- /dev/null +++ b/src/ui/designer/QGCXYPlot.h @@ -0,0 +1,54 @@ +#ifndef QGCXYPLOT_H +#define QGCXYPLOT_H + +#include "QGCToolWidgetItem.h" +#include "MainWindow.h" + +namespace Ui +{ +class QGCXYPlot; +} + +class UASInterface; +class QwtPlot; +class XYPlotCurve; + +class QGCXYPlot : public QGCToolWidgetItem +{ + Q_OBJECT + +public: + explicit QGCXYPlot(QWidget *parent = 0); + ~QGCXYPlot(); + virtual void setEditMode(bool editMode); + +public slots: + void writeSettings(QSettings& settings); + void readSettings(const QSettings& settings); + void readSettings(const QString& pre,const QVariantMap& settings); + void appendData(int uasId, const QString& curve, const QString& unit, const QVariant& variant, quint64 usec); + void clearPlot(); + void styleChanged(MainWindow::QGC_MAINWINDOW_STYLE style); + void updateMinMaxSettings(); + +private slots: + void on_maxDataShowSpinBox_valueChanged(int value); + void on_stopStartButton_toggled(bool checked); + + void on_timeScrollBar_valueChanged(int value); + +private: + Ui::QGCXYPlot *ui; + QwtPlot *plot; + XYPlotCurve* xycurve; + + double x; /**< Last unused value for the x-coordinate */ + quint64 x_timestamp_us; /**< Timestamp that we last recieved a value for x */ + bool x_valid; /**< Whether we have recieved an x value but so far no corresponding y value */ + double y; /**< Last unused value for the x-coordinate */ + quint64 y_timestamp_us; /**< Timestamp that we last recieved a value for x */ + bool y_valid; /**< Whether we have recieved an x value but so far no corresponding y value */ + int max_timestamp_diff_us; /**< Only combine x and y to a data point if the timestamp for both doesn't differ by more than this */ +}; + +#endif // QGCXYPLOT_H diff --git a/src/ui/designer/QGCXYPlot.ui b/src/ui/designer/QGCXYPlot.ui new file mode 100644 index 0000000000000000000000000000000000000000..ab9659517540a669a5e82c645391427fbbd2b10a --- /dev/null +++ b/src/ui/designer/QGCXYPlot.ui @@ -0,0 +1,473 @@ + + + QGCXYPlot + + + + 0 + 0 + 771 + 365 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 + + + + + + + + 50 + 0 + + + + X Parameter: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + editXParam + + + + + + + + 0 + 0 + + + + true + + + QComboBox::InsertAlphabetically + + + QComboBox::AdjustToContents + + + 10 + + + + + + + + 50 + 0 + + + + Y Parameter: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + editYParam + + + + + + + + 0 + 0 + + + + true + + + QComboBox::InsertAlphabetically + + + QComboBox::AdjustToContents + + + 10 + + + + + + + + + + + Number of data points to &show: + + + maxDataShowSpinBox + + + + + + + 2 + + + 999 + + + 15 + + + + + + + To s&tore: + + + maxDataStoreSpinBox + + + + + + + 10 + + + 999999999 + + + 15 + + + + + + + Number of points to average, to provide a smoothing effect of the plotted values + + + S&mooth: + + + smoothSpinBox + + + + + + + Number of points to average, to provide a smoothing effect of the plotted values + + + 1 + + + 99999 + + + + + + + Automatic Axis Range + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + &Min X: + + + minX + + + + + + + -999999999.000000000000000 + + + 999999999.000000000000000 + + + + + + + &Max X: + + + maxX + + + + + + + -999999999.000000000000000 + + + 999999999.000000000000000 + + + + + + + Min &Y: + + + minY + + + + + + + -999999999.000000000000000 + + + 999999999.000000000000000 + + + + + + + Ma&x Y: + + + maxY + + + + + + + -999999999.000000000000000 + + + 999999999.000000000000000 + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + + + + + + + 6 + + + + + + 0 + 0 + + + + 2 + + + true + + + Qt::Horizontal + + + + + + + + :/files/images/actions/media-playback-stop.svg + :/files/images/actions/media-playback-start.svg:/files/images/actions/media-playback-stop.svg + + + + 16 + 16 + + + + true + + + false + + + false + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Done + + + false + + + true + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + + + editXParam + editYParam + maxDataShowSpinBox + maxDataStoreSpinBox + smoothSpinBox + automaticAxisRange + minX + maxX + minY + maxY + editFinishButton + + + + + + diff --git a/src/ui/dockwidgettitlebareventfilter.cpp b/src/ui/dockwidgettitlebareventfilter.cpp deleted file mode 100644 index 52519215ade4e5fb6d1fcb8927a4366fdf6f7da5..0000000000000000000000000000000000000000 --- a/src/ui/dockwidgettitlebareventfilter.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "dockwidgettitlebareventfilter.h" -#include -#include -DockWidgetTitleBarEventFilter::DockWidgetTitleBarEventFilter(QObject *parent) : QObject(parent) -{ -} -bool DockWidgetTitleBarEventFilter::eventFilter(QObject *object,QEvent *event) -{ - if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease) - { - return true; - } - return QObject::eventFilter(object,event); -} diff --git a/src/ui/dockwidgettitlebareventfilter.h b/src/ui/dockwidgettitlebareventfilter.h deleted file mode 100644 index d57edef1fb862711ba55d810b34614bc38dfad0f..0000000000000000000000000000000000000000 --- a/src/ui/dockwidgettitlebareventfilter.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef DOCKWIDGETTITLEBAREVENTFILTER_H -#define DOCKWIDGETTITLEBAREVENTFILTER_H - -#include - -class DockWidgetTitleBarEventFilter : public QObject -{ - Q_OBJECT -public: - explicit DockWidgetTitleBarEventFilter(QObject *parent = 0); -protected: - bool eventFilter(QObject *object,QEvent *event); -signals: - -public slots: - -}; - -#endif // DOCKWIDGETTITLEBAREVENTFILTER_H diff --git a/src/ui/linechart/ChartPlot.cc b/src/ui/linechart/ChartPlot.cc index 665ff5233674f633c6cf324359ae4681020c9620..a1741f85cfb8df5c7a1bf7f9506d75a12ec7e1cf 100644 --- a/src/ui/linechart/ChartPlot.cc +++ b/src/ui/linechart/ChartPlot.cc @@ -70,7 +70,7 @@ QColor ChartPlot::getNextColor() return colors[nextColorIndex++]; } -QColor ChartPlot::getColorForCurve(QString id) +QColor ChartPlot::getColorForCurve(const QString &id) { return curves.value(id)->pen().color(); } diff --git a/src/ui/linechart/ChartPlot.h b/src/ui/linechart/ChartPlot.h index 74a232039ed2ca9bf9be9c2e09a51cd7d0d13c6c..c5196ae8b506e3ba2cbd7efd8d3b32e80bd75c8b 100644 --- a/src/ui/linechart/ChartPlot.h +++ b/src/ui/linechart/ChartPlot.h @@ -17,7 +17,7 @@ public: QColor getNextColor(); /** @brief Get color for curve id */ - QColor getColorForCurve(QString id); + QColor getColorForCurve(const QString &id); /** @brief Reset color map */ void shuffleColors(); diff --git a/src/ui/linechart/IncrementalPlot.cc b/src/ui/linechart/IncrementalPlot.cc index 4b90fcf9febfde09d639cf72aa7a292e0e01c0f3..5826d09d39890adeb2eb1f45c484edb9ac79e668 100644 --- a/src/ui/linechart/IncrementalPlot.cc +++ b/src/ui/linechart/IncrementalPlot.cc @@ -155,38 +155,45 @@ void IncrementalPlot::showLegend(bool show) * * @param style Formatting string for line/data point style */ -void IncrementalPlot::setStyleText(QString style) +void IncrementalPlot::setStyleText(const QString &style) { + styleText = style.toLower(); foreach (QwtPlotCurve* curve, curves) { - // Style of datapoints - if (style.toLower().contains("circles")) { - curve->setSymbol(QwtSymbol(QwtSymbol::Ellipse, - Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(6, 6)) ); - } else if (style.toLower().contains("crosses")) { - curve->setSymbol(QwtSymbol(QwtSymbol::XCross, - Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(5, 5)) ); - } else if (style.toLower().contains("rect")) { - curve->setSymbol(QwtSymbol(QwtSymbol::Rect, - Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(6, 6)) ); - } else if (style.toLower().contains("line")) { // Show no symbol - curve->setSymbol(QwtSymbol(QwtSymbol::NoSymbol, - Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(6, 6)) ); - } + updateStyle(curve); + } + replot(); +} - // Style of lines - if (style.toLower().contains("dotted")) { - curve->setPen(QPen(QBrush(curve->symbol().pen().color()), curveWidth, Qt::DotLine)); - } else if (style.toLower().contains("dashed")) { - curve->setPen(QPen(QBrush(curve->symbol().pen().color()), curveWidth, Qt::DashLine)); - } else if (style.toLower().contains("line") || style.toLower().contains("solid")) { - curve->setPen(QPen(QBrush(curve->symbol().pen().color()), curveWidth, Qt::SolidLine)); - } else { - curve->setPen(QPen(QBrush(curve->symbol().pen().color()), curveWidth, Qt::NoPen)); - } - curve->setStyle(QwtPlotCurve::Lines); +void IncrementalPlot::updateStyle(QwtPlotCurve *curve) +{ + if(styleText.isNull()) + return; + // Style of datapoints + if (styleText.contains("circles")) { + curve->setSymbol(QwtSymbol(QwtSymbol::Ellipse, + Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(6, 6)) ); + } else if (styleText.contains("crosses")) { + curve->setSymbol(QwtSymbol(QwtSymbol::XCross, + Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(5, 5)) ); + } else if (styleText.contains("rect")) { + curve->setSymbol(QwtSymbol(QwtSymbol::Rect, + Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(6, 6)) ); + } else if (styleText.contains("line")) { // Show no symbol + curve->setSymbol(QwtSymbol(QwtSymbol::NoSymbol, + Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(6, 6)) ); + } + // Style of lines + if (styleText.contains("dotted")) { + curve->setPen(QPen(QBrush(curve->symbol().pen().color()), curveWidth, Qt::DotLine)); + } else if (styleText.contains("dashed")) { + curve->setPen(QPen(QBrush(curve->symbol().pen().color()), curveWidth, Qt::DashLine)); + } else if (styleText.contains("line") || styleText.contains("solid")) { + curve->setPen(QPen(QBrush(curve->symbol().pen().color()), curveWidth, Qt::SolidLine)); + } else { + curve->setPen(QPen(QBrush(curve->symbol().pen().color()), curveWidth, Qt::NoPen)); } - replot(); + curve->setStyle(QwtPlotCurve::Lines); } void IncrementalPlot::resetScaling() @@ -214,6 +221,9 @@ void IncrementalPlot::resetScaling() void IncrementalPlot::updateScale() { const double margin = 0.05; + if(xmin == DBL_MAX) + return; + double xMinRange = xmin-(qAbs(xmin*margin)); double xMaxRange = xmax+(qAbs(xmax*margin)); double yMinRange = ymin-(qAbs(ymin*margin)); @@ -247,12 +257,12 @@ void IncrementalPlot::updateScale() zoomer->setZoomBase(true); } -void IncrementalPlot::appendData(QString key, double x, double y) +void IncrementalPlot::appendData(const QString &key, double x, double y) { appendData(key, &x, &y, 1); } -void IncrementalPlot::appendData(QString key, double *x, double *y, int size) +void IncrementalPlot::appendData(const QString &key, double *x, double *y, int size) { CurveData* data; QwtPlotCurve* curve; @@ -272,7 +282,7 @@ void IncrementalPlot::appendData(QString key, double *x, double *y, int size) const QColor &c = getNextColor(); curve->setSymbol(QwtSymbol(QwtSymbol::XCross, QBrush(c), QPen(c, symbolWidth), QSize(5, 5)) ); - + updateStyle(curve); //Apply any user-set style curve->attach(this); } else { curve = curves.value(key); @@ -346,7 +356,7 @@ void IncrementalPlot::appendData(QString key, double *x, double *y, int size) /** * @return Number of copied data points, 0 on failure */ -int IncrementalPlot::data(QString key, double* r_x, double* r_y, int maxSize) +int IncrementalPlot::data(const QString &key, double* r_x, double* r_y, int maxSize) { int result = 0; if (d_data.contains(key)) { @@ -371,7 +381,7 @@ void IncrementalPlot::showGrid(bool show) replot(); } -bool IncrementalPlot::gridEnabled() +bool IncrementalPlot::gridEnabled() const { return grid->isVisible(); } diff --git a/src/ui/linechart/IncrementalPlot.h b/src/ui/linechart/IncrementalPlot.h index 06dee02ff04e90449343b0392e326d39ecc81c84..cb9784ee7d15028c25d9a0841f5bb7510f4ec1c1 100644 --- a/src/ui/linechart/IncrementalPlot.h +++ b/src/ui/linechart/IncrementalPlot.h @@ -81,17 +81,17 @@ public: virtual ~IncrementalPlot(); /** @brief Get the state of the grid */ - bool gridEnabled(); + bool gridEnabled() const; /** @brief Read out data from a curve */ - int data(QString key, double* r_x, double* r_y, int maxSize); + int data(const QString &key, double* r_x, double* r_y, int maxSize); public slots: /** @brief Append one data point */ - void appendData(QString key, double x, double y); + void appendData(const QString &key, double x, double y); /** @brief Append multiple data points */ - void appendData(QString key, double* x, double* y, int size); + void appendData(const QString &key, double* x, double* y, int size); /** @brief Reset the plot scaling to the default value */ void resetScaling(); @@ -109,7 +109,7 @@ public slots: void showGrid(bool show); /** @brief Set new plot style */ - void setStyleText(QString style); + void setStyleText(const QString &style); /** @brief Set symmetric axis scaling mode */ void setSymmetric(bool symmetric); @@ -125,10 +125,12 @@ protected: double xmax; ///< Maximum x value seen double ymin; ///< Minimum y value seen double ymax; ///< Maximum y value seen - + QString styleText; ///< Curve style set by setStyleText private: QMap d_data; ///< Data points + /** Helper function to apply styleText style to the given curve */ + void updateStyle(QwtPlotCurve *curve); }; #endif /* INCREMENTALPLOT_H */ diff --git a/src/ui/linechart/LinechartPlot.cc b/src/ui/linechart/LinechartPlot.cc index 9a6c995fef8eb6dbe966e4a8349d2061e5be6bd5..4b645645977beb16367d961b2d3fac5e1d6b7094 100644 --- a/src/ui/linechart/LinechartPlot.cc +++ b/src/ui/linechart/LinechartPlot.cc @@ -566,13 +566,29 @@ quint64 LinechartPlot::getPlotInterval() **/ void LinechartPlot::setPlotInterval(int interval) { - plotInterval = interval; - QMap::iterator j; - for(j = data.begin(); j != data.end(); ++j) - { - TimeSeriesData* d = data.value(j.key()); - d->setInterval(interval); + //Only ever increase the amount of stored data, + // so that we allow the user to change between + // different intervals without constantly losing + // data points + if((unsigned)interval > plotInterval) { + + QMap::iterator j; + for(j = data.begin(); j != data.end(); ++j) + { + TimeSeriesData* d = data.value(j.key()); + d->setInterval(interval); + } } + plotInterval = interval; + if(plotInterval > 5*60*1000) //If the interval is longer than 4 minutes, change the time scale step to 2 minutes + timeScaleStep = 2*60*1000; + else if(plotInterval >= 4*60*1000) //If the interval is longer than 4 minutes, change the time scale step to 1 minutes + timeScaleStep = 1*60*1000; + else if(plotInterval >= 60*1000) //If the interval is longer than a minute, change the time scale step to 30 seconds + timeScaleStep = 30*1000; + else + timeScaleStep = DEFAULT_SCALE_INTERVAL; + } /** diff --git a/src/ui/linechart/LinechartWidget.cc b/src/ui/linechart/LinechartWidget.cc index 53dcac360cb7fe268483dfc9abc80c845d2708f6..c8652ddecc140387dd45b12590636ab541b0ba98 100644 --- a/src/ui/linechart/LinechartWidget.cc +++ b/src/ui/linechart/LinechartWidget.cc @@ -26,7 +26,7 @@ This file is part of the PIXHAWK project * @brief Line chart plot widget * * @author Lorenz Meier - * + * @author Thomas Gubler */ #include @@ -105,6 +105,8 @@ LinechartWidget::LinechartWidget(int systemid, QWidget *parent) : QWidget(parent connect(ui.recolorButton, SIGNAL(clicked()), this, SLOT(recolor())); connect(ui.shortNameCheckBox, SIGNAL(clicked(bool)), this, SLOT(setShortNames(bool))); + connect(ui.plotFilterLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(filterCurves(const QString&))); + new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F), this, SLOT(setPlotFilterLineEditFocus())); int labelRow = curvesWidgetLayout->rowCount(); @@ -138,7 +140,7 @@ LinechartWidget::LinechartWidget(int systemid, QWidget *parent) : QWidget(parent createLayout(); // And make sure we're listening for future style changes - connect(MainWindow::instance(), SIGNAL(styleChanged()), this, SLOT(recolor())); + connect(MainWindow::instance(), SIGNAL(styleChanged(MainWindow::QGC_MAINWINDOW_STYLE)), this, SLOT(recolor())); updateTimer->setInterval(updateInterval); connect(updateTimer, SIGNAL(timeout()), this, SLOT(refresh())); @@ -207,10 +209,9 @@ void LinechartWidget::createLayout() createActions(); // Setup the plot group box area layout - QGridLayout* layout = new QGridLayout(ui.diagramGroupBox); - mainLayout = layout; - layout->setSpacing(4); - layout->setMargin(2); + QVBoxLayout* vlayout = new QVBoxLayout(ui.diagramGroupBox); + vlayout->setSpacing(4); + vlayout->setMargin(2); // Create plot container widget activePlot = new LinechartPlot(this, sysid); @@ -221,27 +222,18 @@ void LinechartWidget::createLayout() // activePlot = getPlot(0); // plotContainer->setPlot(activePlot); - layout->addWidget(activePlot, 0, 0, 1, 6); - layout->setRowStretch(0, 10); - layout->setRowStretch(1, 1); + vlayout->addWidget(activePlot); - // Linear scaling button - scalingLinearButton = createButton(this); - scalingLinearButton->setDefaultAction(setScalingLinear); - scalingLinearButton->setCheckable(true); - scalingLinearButton->setToolTip(tr("Set linear scale for Y axis")); - scalingLinearButton->setWhatsThis(tr("Set linear scale for Y axis")); - layout->addWidget(scalingLinearButton, 1, 0); - layout->setColumnStretch(0, 0); + QHBoxLayout *hlayout = new QHBoxLayout; + vlayout->addLayout(hlayout); // Logarithmic scaling button scalingLogButton = createButton(this); - scalingLogButton->setDefaultAction(setScalingLogarithmic); + scalingLogButton->setText(tr("LOG")); scalingLogButton->setCheckable(true); scalingLogButton->setToolTip(tr("Set logarithmic scale for Y axis")); scalingLogButton->setWhatsThis(tr("Set logarithmic scale for Y axis")); - layout->addWidget(scalingLogButton, 1, 1); - layout->setColumnStretch(1, 0); + hlayout->addWidget(scalingLogButton); // Averaging spin box averageSpinBox = new QSpinBox(this); @@ -251,8 +243,7 @@ void LinechartWidget::createLayout() averageSpinBox->setValue(200); setAverageWindow(200); averageSpinBox->setMaximum(9999); - layout->addWidget(averageSpinBox, 1, 2); - layout->setColumnStretch(2, 0); + hlayout->addWidget(averageSpinBox); connect(averageSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setAverageWindow(int))); // Log Button @@ -260,8 +251,7 @@ void LinechartWidget::createLayout() logButton->setToolTip(tr("Start to log curve data into a CSV or TXT file")); logButton->setWhatsThis(tr("Start to log curve data into a CSV or TXT file")); logButton->setText(tr("Start Logging")); - layout->addWidget(logButton, 1, 3); - layout->setColumnStretch(3, 0); + hlayout->addWidget(logButton); connect(logButton, SIGNAL(clicked()), this, SLOT(startLogging())); // Ground time button @@ -269,17 +259,37 @@ void LinechartWidget::createLayout() timeButton->setText(tr("Ground Time")); timeButton->setToolTip(tr("Overwrite timestamp of data from vehicle with ground receive time. Helps if the plots are not visible because of missing or invalid onboard time.")); timeButton->setWhatsThis(tr("Overwrite timestamp of data from vehicle with ground receive time. Helps if the plots are not visible because of missing or invalid onboard time.")); - layout->addWidget(timeButton, 1, 4); - layout->setColumnStretch(4, 0); + hlayout->addWidget(timeButton); connect(timeButton, SIGNAL(clicked(bool)), activePlot, SLOT(enforceGroundTime(bool))); connect(timeButton, SIGNAL(clicked()), this, SLOT(writeSettings())); + hlayout->addStretch(); + + QLabel *timeScaleLabel = new QLabel("Time axis:"); + hlayout->addWidget(timeScaleLabel); + + timeScaleCmb = new QComboBox(this); + timeScaleCmb->addItem("10 seconds", 10); + timeScaleCmb->addItem("20 seconds", 20); + timeScaleCmb->addItem("30 seconds", 30); + timeScaleCmb->addItem("40 seconds", 40); + timeScaleCmb->addItem("50 seconds", 50); + timeScaleCmb->addItem("1 minute", 60); + timeScaleCmb->addItem("2 minutes", 60*2); + timeScaleCmb->addItem("3 minutes", 60*3); + timeScaleCmb->addItem("4 minutes", 60*4); + timeScaleCmb->addItem("5 minutes", 60*5); + timeScaleCmb->addItem("10 minutes", 60*10); + //timeScaleCmb->setSizeAdjustPolicy(QComboBox::AdjustToContents); + timeScaleCmb->setMinimumContentsLength(12); + + hlayout->addWidget(timeScaleCmb); + connect(timeScaleCmb, SIGNAL(currentIndexChanged(int)), this, SLOT(timeScaleChanged(int))); + // Initialize the "Show units" checkbox. This is configured in the .ui file, so all // we do here is attach the clicked() signal. connect(ui.showUnitsCheckBox, SIGNAL(clicked()), this, SLOT(writeSettings())); - ui.diagramGroupBox->setLayout(layout); - // Add actions averageSpinBox->setValue(activePlot->getAverageWindow()); @@ -294,42 +304,31 @@ void LinechartWidget::createLayout() connect(this, SIGNAL(plotWindowPositionUpdated(quint64)), activePlot, SLOT(setWindowPosition(quint64))); // Set scaling - connect(scalingLinearButton, SIGNAL(clicked()), activePlot, SLOT(setLinearScaling())); - connect(scalingLogButton, SIGNAL(clicked()), activePlot, SLOT(setLogarithmicScaling())); -} - -void LinechartWidget::appendData(int uasId, const QString& curve, const QString& unit, qint8 value, quint64 usec) -{ - appendData(uasId, curve, unit, static_cast(value), usec); -} - -void LinechartWidget::appendData(int uasId, const QString& curve, const QString& unit, quint8 value, quint64 usec) -{ - appendData(uasId, curve, unit, static_cast(value), usec); -} - -void LinechartWidget::appendData(int uasId, const QString& curve, const QString& unit, qint16 value, quint64 usec) -{ - appendData(uasId, curve, unit, static_cast(value), usec); + connect(scalingLogButton, SIGNAL(toggled(bool)), this, SLOT(toggleLogarithmicScaling(bool))); } -void LinechartWidget::appendData(int uasId, const QString& curve, const QString& unit, quint16 value, quint64 usec) +void LinechartWidget::timeScaleChanged(int index) { - appendData(uasId, curve, unit, static_cast(value), usec); + activePlot->setPlotInterval(timeScaleCmb->itemData(index).toInt()*1000); } -void LinechartWidget::appendData(int uasId, const QString& curve, const QString& unit, qint32 value, quint64 usec) +void LinechartWidget::toggleLogarithmicScaling(bool checked) { - appendData(uasId, curve, unit, static_cast(value), usec); + if(checked) + activePlot->setLogarithmicScaling(); + else + activePlot->setLinearScaling(); } -void LinechartWidget::appendData(int uasId, const QString& curve, const QString& unit, quint32 value, quint64 usec) +void LinechartWidget::appendData(int uasId, const QString& curve, const QString& unit, const QVariant &variant, quint64 usec) { - appendData(uasId, curve, unit, static_cast(value), usec); -} + QMetaType::Type type = static_cast(variant.type()); + bool ok; + double value = variant.toDouble(&ok); + if(!ok || type == QMetaType::QByteArray || type == QMetaType::QString) + return; + bool isDouble = type == QMetaType::Float || type == QMetaType::Double; -void LinechartWidget::appendData(int uasId, const QString& curve, const QString& unit, qint64 value, quint64 usec) -{ if ((selectedMAV == -1 && isVisible()) || (selectedMAV == uasId && isVisible())) { // Order matters here, first append to plot, then update curve list @@ -339,12 +338,14 @@ void LinechartWidget::appendData(int uasId, const QString& curve, const QString& // Make sure the curve will be created if it does not yet exist if(!label) { - intData.insert(curve+unit, 0); + if(!isDouble) + intData.insert(curve+unit, 0); addCurve(curve, unit); } // Add int data - intData.insert(curve+unit, value); + if(!isDouble) + intData.insert(curve+unit, variant.toInt()); } if (lastTimestamp == 0 && usec != 0) @@ -374,96 +375,6 @@ void LinechartWidget::appendData(int uasId, const QString& curve, const QString& } } -void LinechartWidget::appendData(int uasId, const QString& curve, const QString& unit, quint64 value, quint64 usec) -{ - if ((selectedMAV == -1 && isVisible()) || (selectedMAV == uasId && isVisible())) - { - // Order matters here, first append to plot, then update curve list - activePlot->appendData(curve+unit, usec, value); - // Store data - QLabel* label = curveLabels->value(curve+unit, NULL); - // Make sure the curve will be created if it does not yet exist - if(!label) - { - intData.insert(curve+unit, 0); - addCurve(curve, unit); - } - - // Add int data - intData.insert(curve+unit, value); - } - - if (lastTimestamp == 0 && usec != 0) - { - lastTimestamp = usec; - } else if (usec != 0) { - // Difference larger than 5 secs, enforce ground time - if (abs((int)((qint64)usec - (quint64)lastTimestamp)) > 5000) - { - autoGroundTimeSet = true; - if (activePlot) activePlot->groundTime(); - } - } - - // Log data - if (logging) - { - if (activePlot->isVisible(curve+unit)) - { - if (usec == 0) usec = QGC::groundTimeMilliseconds(); - if (logStartTime == 0) logStartTime = usec; - qint64 time = usec - logStartTime; - if (time < 0) time = 0; - - logFile->write(QString(QString::number(time) + "\t" + QString::number(uasId) + "\t" + curve + "\t" + QString::number(value) + "\n").toLatin1()); - logFile->flush(); - } - } -} - -void LinechartWidget::appendData(int uasId, const QString& curve, const QString& unit, double value, quint64 usec) -{ - if ((selectedMAV == -1 && isVisible()) || (selectedMAV == uasId && isVisible())) - { - // Order matters here, first append to plot, then update curve list - activePlot->appendData(curve+unit, usec, value); - // Store data - QLabel* label = curveLabels->value(curve+unit, NULL); - // Make sure the curve will be created if it does not yet exist - if(!label) - { - addCurve(curve, unit); - } - } - - if (lastTimestamp == 0 && usec != 0) - { - lastTimestamp = usec; - } else if (usec != 0) { - // Difference larger than 1 sec, enforce ground time - if (abs((int)((qint64)usec - (quint64)lastTimestamp)) > 1000) - { - autoGroundTimeSet = true; - if (activePlot) activePlot->groundTime(); - } - } - - // Log data - if (logging) - { - if (activePlot->isVisible(curve+unit)) - { - if (usec == 0) usec = QGC::groundTimeMilliseconds(); - if (logStartTime == 0) logStartTime = usec; - qint64 time = usec - logStartTime; - if (time < 0) time = 0; - - logFile->write(QString(QString::number(time) + "\t" + QString::number(uasId) + "\t" + curve + "\t" + QString::number(value,'g',18) + "\n").toLatin1()); - logFile->flush(); - } - } -} - void LinechartWidget::refresh() { setUpdatesEnabled(false); @@ -626,8 +537,6 @@ void LinechartWidget::setAverageWindow(int windowSize) void LinechartWidget::createActions() { - setScalingLogarithmic = new QAction("LOG", this); - setScalingLinear = new QAction("LIN", this); } /** @@ -657,6 +566,7 @@ void LinechartWidget::addCurve(const QString& curve, const QString& unit) checkBox->setObjectName(curve+unit); checkBox->setToolTip(tr("Enable the curve in the graph window")); checkBox->setWhatsThis(tr("Enable the curve in the graph window")); + checkBoxes.insert(curve+unit, checkBox); curvesWidgetLayout->addWidget(checkBox, labelRow, 0); // Icon @@ -686,6 +596,7 @@ void LinechartWidget::addCurve(const QString& curve, const QString& unit) unitLabel->setText(unit); unitLabel->setToolTip(tr("Unit of ") + curve); unitLabel->setWhatsThis(tr("Unit of ") + curve); + curveUnits.insert(curve+unit, unitLabel); curvesWidgetLayout->addWidget(unitLabel, labelRow, 4); unitLabel->setVisible(ui.showUnitsCheckBox->isChecked()); connect(ui.showUnitsCheckBox, SIGNAL(clicked(bool)), unitLabel, SLOT(setVisible(bool))); @@ -762,9 +673,19 @@ void LinechartWidget::removeCurve(QString curve) widget = curveVariances->take(curve); curvesWidgetLayout->removeWidget(widget); widget->deleteLater(); -// widget = colorIcons->take(curve); -// curvesWidgetLayout->removeWidget(colorIcons->take(curve)); + widget = colorIcons.take(curve); + curvesWidgetLayout->removeWidget(widget); + widget->deleteLater(); + widget = curveNameLabels.take(curve); + curvesWidgetLayout->removeWidget(widget); + widget->deleteLater(); + widget = curveUnits.take(curve); + curvesWidgetLayout->removeWidget(widget); widget->deleteLater(); + QCheckBox* checkbox; + checkbox = checkBoxes.take(curve); + curvesWidgetLayout->removeWidget(checkbox); + checkbox->deleteLater(); // intData->remove(curve); } @@ -784,6 +705,55 @@ void LinechartWidget::recolor() } } +void LinechartWidget::setPlotFilterLineEditFocus() +{ + ui.plotFilterLineEdit->setFocus(Qt::ShortcutFocusReason); +} + +void LinechartWidget::filterCurve(const QString &key, bool match) +{ + if (!checkBoxes[key]->isChecked()) + { + colorIcons[key]->setVisible(match); + curveNameLabels[key]->setVisible(match); + (*curveLabels)[key]->setVisible(match); + (*curveMeans)[key]->setVisible(match); + (*curveVariances)[key]->setVisible(match); + curveUnits[key]->setVisible(match); + checkBoxes[key]->setVisible(match); + } +} + +void LinechartWidget::filterCurves(const QString &filter) +{ + //qDebug() << "filterCurves: filter: " << filter; + + if (filter != "") + { + /* Hide Elements which do not match the filter pattern */ + QStringMatcher stringMatcher(filter, Qt::CaseInsensitive); + foreach (QString key, colorIcons.keys()) + { + if (stringMatcher.indexIn(key) < 0) + { + filterCurve(key, false); + } + else + { + filterCurve(key, true); + } + } + } + else + { + /* Show all Elements */ + foreach (QString key, colorIcons.keys()) + { + filterCurve(key, true); + } + } +} + QString LinechartWidget::getCurveName(const QString& key, bool shortEnabled) { if (shortEnabled) diff --git a/src/ui/linechart/LinechartWidget.h b/src/ui/linechart/LinechartWidget.h index a775c303f182764f4e5b25432de8ae37769ad63f..4c9fb20b625418425ca2c58359a75d868fddf20c 100644 --- a/src/ui/linechart/LinechartWidget.h +++ b/src/ui/linechart/LinechartWidget.h @@ -26,7 +26,7 @@ This file is part of the PIXHAWK project * @brief Definition of Line chart plot widget * * @author Lorenz Meier - * + * @author Thomas Gubler */ #ifndef LINECHARTWIDGET_H #define LINECHARTWIDGET_H @@ -77,25 +77,12 @@ public slots: void recolor(); /** @brief Set short names for curves */ void setShortNames(bool enable); - /** @brief Append int8 data to the given curve. */ - void appendData(int uasId, const QString& curve, const QString& unit, qint8 value, quint64 usec); - /** @brief Append uint8 data to the given curve. */ - void appendData(int uasId, const QString& curve, const QString& unit, quint8 value, quint64 usec); - /** @brief Append int16 data to the given curve. */ - void appendData(int uasId, const QString& curve, const QString& unit, qint16 value, quint64 usec); - /** @brief Append uint16 data to the given curve. */ - void appendData(int uasId, const QString& curve, const QString& unit, quint16 value, quint64 usec); - /** @brief Append int32 data to the given curve. */ - void appendData(int uasId, const QString& curve, const QString& unit, qint32 value, quint64 usec); - /** @brief Append uint32 data to the given curve. */ - void appendData(int uasId, const QString& curve, const QString& unit, quint32 value, quint64 usec); - /** @brief Append int64 data to the given curve. */ - void appendData(int uasId, const QString& curve, const QString& unit, qint64 value, quint64 usec); - /** @brief Append uint64 data to the given curve. */ - void appendData(int uasId, const QString& curve, const QString& unit, quint64 value, quint64 usec); - /** @brief Append double data to the given curve. */ - void appendData(int uasId, const QString& curve, const QString& unit, double value, quint64 usec); + /** @brief Append data to the given curve. */ + void appendData(int uasId, const QString& curve, const QString& unit, const QVariant& value, quint64 usec); + /** @brief Hide curves which do not match the filter pattern */ + void filterCurves(const QString &filter); + void toggleLogarithmicScaling(bool toggled); void takeButtonClick(bool checked); void setPlotWindowPosition(int scrollBarValue); void setPlotWindowPosition(quint64 position); @@ -121,6 +108,14 @@ public slots: void readSettings(); /** @brief Select all curves */ void selectAllCurves(bool all); + /** @brief Sets the focus to the LineEdit for plot-filtering */ + void setPlotFilterLineEditFocus(); + +private slots: + /** Called when the user changes the time scale combobox. */ + void timeScaleChanged(int index); + /** @brief Toggles visibility of curve based on bool match if corresponding checkbox is not checked */ + void filterCurve(const QString &key, bool match); protected: void addCurveToList(QString curve); @@ -143,23 +138,22 @@ protected: QMap curveNames; ///< Full curve names QMap* curveMeans; ///< References to the curve means QMap* curveMedians; ///< References to the curve medians + QMap curveUnits; ///< References to the curve units QMap* curveVariances; ///< References to the curve variances QMap intData; ///< Current values for integer-valued curves QMap colorIcons; ///< Reference to color icons + QMap checkBoxes; ///< Reference to checkboxes QWidget* curvesWidget; ///< The QWidget containing the curve selection button QGridLayout* curvesWidgetLayout; ///< The layout for the curvesWidget QWidget QScrollBar* scrollbar; ///< The plot window scroll bar QSpinBox* averageSpinBox; ///< Spin box to setup average window filter size - QAction* setScalingLogarithmic; ///< Set logarithmic scaling - QAction* setScalingLinear; ///< Set linear scaling QAction* addNewCurve; ///< Add curve candidate to the active curves QMenu* curveMenu; - QGridLayout* mainLayout; + QComboBox *timeScaleCmb; - QToolButton* scalingLinearButton; QToolButton* scalingLogButton; QToolButton* logButton; QPointer timeButton; diff --git a/src/ui/linechart/Linecharts.cc b/src/ui/linechart/Linecharts.cc index 36d86d01e6a0757905b189629873aae74fd0b2d0..19469b8b690081c79f6755f33d32ec6c7a210c76 100644 --- a/src/ui/linechart/Linecharts.cc +++ b/src/ui/linechart/Linecharts.cc @@ -100,15 +100,7 @@ void Linecharts::addSystem(UASInterface* uas) plots.insert(uasid, widget); // Connect valueChanged signals - connect(uas, SIGNAL(valueChanged(int,QString,QString,quint8,quint64)), widget, SLOT(appendData(int,QString,QString,quint8,quint64))); - connect(uas, SIGNAL(valueChanged(int,QString,QString,qint8,quint64)), widget, SLOT(appendData(int,QString,QString,qint8,quint64))); - connect(uas, SIGNAL(valueChanged(int,QString,QString,quint16,quint64)), widget, SLOT(appendData(int,QString,QString,quint16,quint64))); - connect(uas, SIGNAL(valueChanged(int,QString,QString,qint16,quint64)), widget, SLOT(appendData(int,QString,QString,qint16,quint64))); - connect(uas, SIGNAL(valueChanged(int,QString,QString,quint32,quint64)), widget, SLOT(appendData(int,QString,QString,quint32,quint64))); - connect(uas, SIGNAL(valueChanged(int,QString,QString,qint32,quint64)), widget, SLOT(appendData(int,QString,QString,qint32,quint64))); - connect(uas, SIGNAL(valueChanged(int,QString,QString,quint64,quint64)), widget, SLOT(appendData(int,QString,QString,quint64,quint64))); - connect(uas, SIGNAL(valueChanged(int,QString,QString,qint64,quint64)), widget, SLOT(appendData(int,QString,QString,qint64,quint64))); - connect(uas, SIGNAL(valueChanged(int,QString,QString,double,quint64)), widget, SLOT(appendData(int,QString,QString,double,quint64))); + connect(uas, SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)), widget, SLOT(appendData(int,QString,QString,QVariant,quint64))); connect(widget, SIGNAL(logfileWritten(QString)), this, SIGNAL(logfileWritten(QString))); // Set system active if this is the only system @@ -120,15 +112,7 @@ void Linecharts::addSystem(UASInterface* uas) // Connect generic sources for (int i = 0; i < genericSources.count(); ++i) { - connect(genericSources[i], SIGNAL(valueChanged(int,QString,QString,quint8,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,quint8,quint64))); - connect(genericSources[i], SIGNAL(valueChanged(int,QString,QString,qint8,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,qint8,quint64))); - connect(genericSources[i], SIGNAL(valueChanged(int,QString,QString,quint16,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,quint16,quint64))); - connect(genericSources[i], SIGNAL(valueChanged(int,QString,QString,qint16,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,qint16,quint64))); - connect(genericSources[i], SIGNAL(valueChanged(int,QString,QString,quint32,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,quint32,quint64))); - connect(genericSources[i], SIGNAL(valueChanged(int,QString,QString,qint32,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,qint32,quint64))); - connect(genericSources[i], SIGNAL(valueChanged(int,QString,QString,quint64,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,quint64,quint64))); - connect(genericSources[i], SIGNAL(valueChanged(int,QString,QString,qint64,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,qint64,quint64))); - connect(genericSources[i], SIGNAL(valueChanged(int,QString,QString,double,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,double,quint64))); + connect(genericSources[i], SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,QVariant,quint64))); } // Select system widget->setActive(true); @@ -145,14 +129,6 @@ void Linecharts::addSource(QObject* obj) if (plots.size() > 0) { // Connect generic source - connect(obj, SIGNAL(valueChanged(int,QString,QString,quint8,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,quint8,quint64))); - connect(obj, SIGNAL(valueChanged(int,QString,QString,qint8,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,qint8,quint64))); - connect(obj, SIGNAL(valueChanged(int,QString,QString,quint16,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,quint16,quint64))); - connect(obj, SIGNAL(valueChanged(int,QString,QString,qint16,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,qint16,quint64))); - connect(obj, SIGNAL(valueChanged(int,QString,QString,quint32,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,quint32,quint64))); - connect(obj, SIGNAL(valueChanged(int,QString,QString,qint32,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,qint32,quint64))); - connect(obj, SIGNAL(valueChanged(int,QString,QString,quint64,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,quint64,quint64))); - connect(obj, SIGNAL(valueChanged(int,QString,QString,qint64,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,qint64,quint64))); - connect(obj, SIGNAL(valueChanged(int,QString,QString,double,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,double,quint64))); + connect(obj, SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,QVariant,quint64))); } } diff --git a/src/ui/map/QGCMapToolBar.cc b/src/ui/map/QGCMapToolBar.cc index 067544bcd228941c50a5aeadeab70ef6dac2a9d4..c9596efafa68cd06694906b8393c22332ddd3b36 100644 --- a/src/ui/map/QGCMapToolBar.cc +++ b/src/ui/map/QGCMapToolBar.cc @@ -60,18 +60,27 @@ void QGCMapToolBar::setMap(QGCMapWidget* map) action = mapTypesMenu.addAction(tr("Bing Hybrid"),this,SLOT(setMapType())); action->setData(MapType::BingHybrid); action->setCheckable(true); +#ifdef MAP_DEFAULT_TYPE_BING + action->setChecked(true); +#endif mapTypesGroup->addAction(action); action = mapTypesMenu.addAction(tr("Google Hybrid"),this,SLOT(setMapType())); action->setData(MapType::GoogleHybrid); action->setCheckable(true); +#ifdef MAP_DEFAULT_TYPE_GOOGLE + action->setChecked(true); +#endif mapTypesGroup->addAction(action); action = mapTypesMenu.addAction(tr("OpenStreetMap"),this,SLOT(setMapType())); action->setData(MapType::OpenStreetMap); action->setCheckable(true); +#ifdef MAP_DEFAULT_TYPE_OSM + action->setChecked(true); +#endif mapTypesGroup->addAction(action); - //TODO check current item + optionsMenu.addMenu(&mapTypesMenu); diff --git a/src/ui/map/QGCMapWidget.cc b/src/ui/map/QGCMapWidget.cc index 9146e347ab0093e32dd03e5d3f0da6e169af3195..db76a20a2aa1ad401dcde4f52df002ab67df1974 100644 --- a/src/ui/map/QGCMapWidget.cc +++ b/src/ui/map/QGCMapWidget.cc @@ -34,10 +34,17 @@ QGCMapWidget::QGCMapWidget(QWidget *parent) : //this->SetShowTileGridLines(true); //default appears to be Google Hybrid, and is broken currently +#if defined MAP_DEFAULT_TYPE_BING this->SetMapType(MapType::BingHybrid); +#elif defined MAP_DEFAULT_TYPE_GOOGLE + this->SetMapType(MapType::GoogleHybrid); +#else + this->SetMapType(MapType::OpenStreetMap); +#endif this->setContextMenuPolicy(Qt::ActionsContextMenu); + // Go to options QAction *guidedaction = new QAction(this); guidedaction->setText("Go To Here (Guided Mode)"); connect(guidedaction,SIGNAL(triggered()),this,SLOT(guidedActionTriggered())); @@ -46,10 +53,16 @@ QGCMapWidget::QGCMapWidget(QWidget *parent) : guidedaction->setText("Go To Here Alt (Guided Mode)"); connect(guidedaction,SIGNAL(triggered()),this,SLOT(guidedAltActionTriggered())); this->addAction(guidedaction); + // Point camera option QAction *cameraaction = new QAction(this); cameraaction->setText("Point Camera Here"); connect(cameraaction,SIGNAL(triggered()),this,SLOT(cameraActionTriggered())); this->addAction(cameraaction); + // Set home location option + QAction *sethomeaction = new QAction(this); + sethomeaction->setText("Set Home Location Here"); + connect(sethomeaction,SIGNAL(triggered()),this,SLOT(setHomeActionTriggered())); + this->addAction(sethomeaction); } void QGCMapWidget::guidedActionTriggered() { @@ -68,7 +81,7 @@ void QGCMapWidget::guidedActionTriggered() } } // Create new waypoint and send it to the WPManager to send out. - internals::PointLatLng pos = map->FromLocalToLatLng(mousePressPos.x(), mousePressPos.y()); + internals::PointLatLng pos = map->FromLocalToLatLng(contextMousePressPos.x(), contextMousePressPos.y()); qDebug() << "Guided action requested. Lat:" << pos.Lat() << "Lon:" << pos.Lng(); Waypoint wp; wp.setLatitude(pos.Lat()); @@ -106,13 +119,49 @@ void QGCMapWidget::cameraActionTriggered() if (newmav) { newmav->setMountConfigure(4,true,true,true); - internals::PointLatLng pos = map->FromLocalToLatLng(mousePressPos.x(), mousePressPos.y()); + internals::PointLatLng pos = map->FromLocalToLatLng(contextMousePressPos.x(), contextMousePressPos.y()); newmav->setMountControl(pos.Lat(),pos.Lng(),100,true); } } +/** + * @brief QGCMapWidget::setHomeActionTriggered + */ +bool QGCMapWidget::setHomeActionTriggered() +{ + if (!uas) + { + QMessageBox::information(0,"Error","Please connect first"); + return false; + } + UASManager *uasManager = UASManager::instance(); + if (!uasManager) { return false; } + + // Enter an altitude + bool ok = false; + double alt = QInputDialog::getDouble(this,"Home Altitude","Enter altitude (in meters) of new home location",0.0,0.0,30000.0,2,&ok); + if (!ok) return false; //Use has chosen cancel. Do not send the waypoint + + // Create new waypoint and send it to the WPManager to send out. + internals::PointLatLng pos = map->FromLocalToLatLng(contextMousePressPos.x(), contextMousePressPos.y()); + qDebug("Set home location sent. Lat: %f, Lon: %f, Alt: %f.", pos.Lat(), pos.Lng(), alt); + + bool success = uasManager->setHomePositionAndNotify(pos.Lat(),pos.Lng(), alt); + + qDebug() << ((success)? "Set new home location." : "Failed to set new home location."); + + return success; +} + void QGCMapWidget::mousePressEvent(QMouseEvent *event) { + + // Store right-click event presses separate for context menu + // TODO add check if click was on map, or popup box. + if (event->button() == Qt::RightButton) { + contextMousePressPos = event->pos(); + } + mapcontrol::OPMapWidget::mousePressEvent(event); } @@ -520,6 +569,7 @@ void QGCMapWidget::updateHomePosition(double latitude, double longitude, double Home->SetAltitude(altitude); homeAltitude = altitude; SetShowHome(true); // display the HOME position on the map + Home->RefreshPos(); } void QGCMapWidget::goHome() diff --git a/src/ui/map/QGCMapWidget.h b/src/ui/map/QGCMapWidget.h index d6f3b53d790be4564280fb1330423f46a0190736..2f169a9ef427a9a5f8746d90a2f64ddeab1a854c 100644 --- a/src/ui/map/QGCMapWidget.h +++ b/src/ui/map/QGCMapWidget.h @@ -5,6 +5,11 @@ #include #include "../../../libs/opmapcontrol/opmapcontrol.h" +// Choose one default map type +#define MAP_DEFAULT_TYPE_BING +//#define MAP_DEFAULT_TYPE_GOOGLE +//#define MAP_DEFAULT_TYPE_OSM + class UASInterface; class UASWaypointManager; class Waypoint; @@ -46,6 +51,8 @@ public slots: void guidedActionTriggered(); /** @brief Action triggered when guided action is selected from the context menu, allows for altitude selection */ bool guidedAltActionTriggered(); + /** @brief Action triggered when set home action is selected from the context menu. */ + bool setHomeActionTriggered(); /** @brief Add system to map view */ void addUAS(UASInterface* uas); /** @brief Update the global position of a system */ @@ -136,6 +143,8 @@ protected: void mouseReleaseEvent(QMouseEvent *event); void mouseDoubleClickEvent(QMouseEvent* event); + //void contextMenuEvent(QContextMenuEvent *); + UASWaypointManager* currWPManager; ///< The current waypoint manager bool offlineMode; QMap waypointsToIcons; @@ -160,6 +169,7 @@ protected: bool mapInitialized; ///< Map initialized? float homeAltitude; ///< Home altitude QPoint mousePressPos; ///< Mouse position when the button is released. + QPoint contextMousePressPos; ///< Mouse position when context menu activated. int defaultGuidedAlt; ///< Default altitude for guided mode UASInterface *uas; ///< Currently selected UAS. diff --git a/src/ui/map/Waypoint2DIcon.cc b/src/ui/map/Waypoint2DIcon.cc index 3bf54232f556aceb02a2a136146338969d01df4a..83aad5b51ffe6b33dba7ff27fbeb9b5694fead44 100644 --- a/src/ui/map/Waypoint2DIcon.cc +++ b/src/ui/map/Waypoint2DIcon.cc @@ -291,10 +291,12 @@ void Waypoint2DIcon::paint(QPainter *painter, const QStyleOptionGraphicsItem *op redPen.setWidth(1); painter->setPen(redPen); const int acceptance = map->metersToPixels(waypoint->getAcceptanceRadius(), Coord()); - painter->setPen(penBlack); - painter->drawEllipse(QPointF(0, 0), acceptance, acceptance); - painter->setPen(redPen); - painter->drawEllipse(QPointF(0, 0), acceptance, acceptance); + if (acceptance > 0) { + painter->setPen(penBlack); + painter->drawEllipse(QPointF(0, 0), acceptance, acceptance); + painter->setPen(redPen); + painter->drawEllipse(QPointF(0, 0), acceptance, acceptance); + } } if ((waypoint) && ((waypoint->getAction() == (int)MAV_CMD_NAV_LOITER_UNLIM) || (waypoint->getAction() == (int)MAV_CMD_NAV_LOITER_TIME) || (waypoint->getAction() == (int)MAV_CMD_NAV_LOITER_TURNS))) { diff --git a/src/ui/menuactionhelper.cpp b/src/ui/menuactionhelper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..459ebaade3b6604c54b8ad7aff3d0ac89f44f867 --- /dev/null +++ b/src/ui/menuactionhelper.cpp @@ -0,0 +1,175 @@ +#include "menuactionhelper.h" + +MenuActionHelper::MenuActionHelper(QObject *parent) : QObject(parent), + m_isAdvancedMode(false), + m_dockWidgetTitleBarsEnabled(true), + m_addedCustomSeperator(false) +{ +} + +QAction *MenuActionHelper::createToolAction(const QString &title, const QString &name) +{ + QAction *action = m_menuToDockNameMap.key(name); //For sanity, check that the action is not NULL + if(action) { + qWarning() << "createToolAction was called for action" << name << "which already exists in the menu"; + return action; + } + + action = new QAction(title, NULL); + action->setCheckable(true); + connect(action,SIGNAL(triggered(bool)),this,SLOT(showTool(bool))); + m_menuToDockNameMap[action] = name; + m_menu->addAction(action); + return action; +} + +void MenuActionHelper::removeDockWidget() +{ + QObject *dockWidget = QObject::sender(); //Note that we can't cast to QDockWidget because we are in its destructor + Q_ASSERT(dockWidget); + + qDebug() << "Dockwidget:" << dockWidget->objectName() << "of type" << dockWidget->metaObject()->className(); + + QAction *action = m_menuToDockNameMap.key(dockWidget->objectName()); + if(action) { + m_menuToDockNameMap.remove(action); + action->deleteLater(); + } + QMap >::iterator it; + for (it = m_centralWidgetToDockWidgetsMap.begin(); it != m_centralWidgetToDockWidgetsMap.end(); ++it) { + QMap::iterator it2 = it.value().begin(); + while( it2 != it.value().end()) { + if(it2.value() == dockWidget) + it2 = it.value().erase(it2); + else + ++it2; + } + } + //Don't delete the dockWidget because this could have been called from the dockWidget destructor + m_dockWidgets.removeAll(static_cast(dockWidget)); +} + +QAction *MenuActionHelper::createToolActionForCustomDockWidget(const QString &title, const QString& name, QDockWidget* dockWidget, MainWindow::VIEW_SECTIONS view) { + bool found = false; + QAction *action = NULL; + foreach(QAction *act, m_menuToDockNameMap.keys()) { + if(act->text() == title) { + found = true; + action = act; + } + } + + if(!found) + action = createToolAction(title, name); + else + m_menuToDockNameMap[action] = name; + + m_centralWidgetToDockWidgetsMap[view][name] = dockWidget; + connect(dockWidget, SIGNAL(destroyed()), SLOT(removeDockWidget()),Qt::UniqueConnection); //Use UniqueConnection since we might have already created this connection in createDockWidget + connect(dockWidget, SIGNAL(visibilityChanged(bool)), action, SLOT(setChecked(bool))); + action->setChecked(dockWidget->isVisible()); + return action; +} + +QDockWidget* MenuActionHelper::createDockWidget(const QString& title,const QString& name) +{ + QDockWidget *dockWidget = new QDockWidget(title); + m_dockWidgets.append(dockWidget); + setDockWidgetTitleBar(dockWidget); + dockWidget->setObjectName(name); + connect(dockWidget, SIGNAL(destroyed()), SLOT(removeDockWidget())); + + return dockWidget; +} + +bool MenuActionHelper::containsDockWidget(MainWindow::VIEW_SECTIONS view, const QString &name) const { + + return m_centralWidgetToDockWidgetsMap.contains(view) && m_centralWidgetToDockWidgetsMap[view].contains(name); +} + +QDockWidget *MenuActionHelper::getDockWidget(MainWindow::VIEW_SECTIONS view, const QString &name) const { + if(!m_centralWidgetToDockWidgetsMap.contains(view)) + return NULL; + return m_centralWidgetToDockWidgetsMap[view].value(name); +} + +void MenuActionHelper::showTool(bool show) { + //Called when a menu item is clicked on, regardless of view. + QAction* act = qobject_cast(sender()); + Q_ASSERT(act); + if (m_menuToDockNameMap.contains(act)) { + QString name = m_menuToDockNameMap[act]; + emit needToShowDockWidget(name, show); + } +} + +void MenuActionHelper::setDockWidgetTitleBarsEnabled(bool enabled) +{ + m_dockWidgetTitleBarsEnabled = enabled; + for (int i = 0; i < m_dockWidgets.size(); i++) + setDockWidgetTitleBar(m_dockWidgets[i]); +} + + +void MenuActionHelper::setAdvancedMode(bool advancedMode) +{ + m_isAdvancedMode = advancedMode; + for (int i = 0; i < m_dockWidgets.size(); i++) + setDockWidgetTitleBar(m_dockWidgets[i]); +} + +void MenuActionHelper::setDockWidgetTitleBar(QDockWidget* widget) +{ + Q_ASSERT(widget); + QWidget* oldTitleBar = widget->titleBarWidget(); + + // In advanced mode, we use the default titlebar provided by Qt. + if (m_isAdvancedMode) + { + widget->setTitleBarWidget(0); + } + // Otherwise, if just a textlabel should be shown, make that the titlebar. + else if (m_dockWidgetTitleBarsEnabled) + { + QLabel* label = new QLabel(widget); + label->setText(widget->windowTitle()); + label->installEventFilter(this); //Ignore mouse clicks + widget->installEventFilter(this); //Update label if window title changes. See eventFilter below + widget->setTitleBarWidget(label); + } + // And if nothing should be shown, use an empty widget. + else + { + QWidget* newTitleBar = new QWidget(widget); + widget->setTitleBarWidget(newTitleBar); + } + + // Be sure to clean up the old titlebar. When using QDockWidget::setTitleBarWidget(), + // it doesn't delete the old titlebar object. + delete oldTitleBar; +} + +bool MenuActionHelper::eventFilter(QObject *object,QEvent *event) +{ + if (event->type() == QEvent::WindowTitleChange) + { + QDockWidget *dock = qobject_cast(object); + if(dock) { + // Update the dock title bar label + QLabel *label = dynamic_cast(dock->titleBarWidget()); + if(label) + label->setText(dock->windowTitle()); + // Now update the action label + QString oldObjectName = dock->objectName(); + QAction *action = m_menuToDockNameMap.key(oldObjectName); + if(action) + action->setText(dock->windowTitle()); + //Now modify the object name - it is a strange naming scheme.. + } + } else if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease) + { + if(qobject_cast(object)) + return true; + } + return QObject::eventFilter(object,event); +} diff --git a/src/ui/menuactionhelper.h b/src/ui/menuactionhelper.h new file mode 100644 index 0000000000000000000000000000000000000000..cde788348868daa6581b481128b222bb4003fb8d --- /dev/null +++ b/src/ui/menuactionhelper.h @@ -0,0 +1,50 @@ +#ifndef MENUACTIONHELPER_H +#define MENUACTIONHELPER_H + +#include "MainWindow.h" + +class MenuActionHelper : public QObject +{ + Q_OBJECT +public: + MenuActionHelper(QObject *parent = NULL); + ~MenuActionHelper() {} + + /** @brief Get title bar mode setting */ + bool dockWidgetTitleBarsEnabled() const { return m_dockWidgetTitleBarsEnabled; } + void setDockWidgetTitleBarsEnabled(bool enabled); + bool isAdvancedMode() const { return m_isAdvancedMode; } + void setAdvancedMode(bool advancedMode); + QAction *createToolAction(const QString &title, const QString &name = QString()); + QAction *createToolActionForCustomDockWidget(const QString& title, const QString& name, QDockWidget* dockWidget, MainWindow::VIEW_SECTIONS view); + QDockWidget *createDockWidget(const QString& title, const QString& name); + bool containsDockWidget(MainWindow::VIEW_SECTIONS view, const QString &name) const; + QDockWidget *getDockWidget(MainWindow::VIEW_SECTIONS view, const QString &name) const; + + /** QMenu to add QActions to */ + void setMenu(QMenu *menu) { m_menu = menu; } + +protected: + virtual bool eventFilter(QObject *object,QEvent *event); + +private slots: + void removeDockWidget(); + /** @brief Shows a Docked Widget based on the action sender */ + void showTool(bool show); + +signals: + void needToShowDockWidget(const QString& name, bool show); +private: + QMap m_menuToDockNameMap; + QList m_dockWidgets; + QMap > m_centralWidgetToDockWidgetsMap; + bool m_isAdvancedMode; ///< If enabled dock widgets can be moved and floated. + bool m_dockWidgetTitleBarsEnabled; ///< If enabled, dock widget titlebars are displayed when NOT in advanced mode. + QMenu *m_menu; ///< \see setMenu() + bool m_addedCustomSeperator; ///< Whether we have added a seperator between the actions and the custom actions + + void setDockWidgetTitleBar(QDockWidget* widget); + +}; + +#endif // MENUACTIONHELPER_H diff --git a/src/ui/px4_configuration/QGCPX4AirframeConfig.cc b/src/ui/px4_configuration/QGCPX4AirframeConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..48d321b11b17c28ff3199d4d091ebec269dd1352 --- /dev/null +++ b/src/ui/px4_configuration/QGCPX4AirframeConfig.cc @@ -0,0 +1,470 @@ +#include +#include +#include +#include + +#include "QGCPX4AirframeConfig.h" +#include "ui_QGCPX4AirframeConfig.h" + +#include "UASManager.h" +#include "LinkManager.h" +#include "UAS.h" +#include "QGC.h" + +QGCPX4AirframeConfig::QGCPX4AirframeConfig(QWidget *parent) : + QWidget(parent), + mav(NULL), + progress(NULL), + pendingParams(0), + configState(CONFIG_STATE_ABORT), + selectedId(-1), + ui(new Ui::QGCPX4AirframeConfig) +{ + ui->setupUi(this); + + // Fill the lists here manually in accordance with the list from: + // https://github.com/PX4/Firmware/blob/master/ROMFS/px4fmu_common/init.d/rcS + + ui->planeComboBox->addItem(tr("Multiplex Easystar 1/2"), 100); + ui->planeComboBox->addItem(tr("Hobbyking Bixler 1/2"), 101); + ui->planeComboBox->addItem(tr("HilStar (SIMULATION)"), 1000); + + connect(ui->planePushButton, SIGNAL(clicked()), this, SLOT(planeSelected())); + connect(ui->planeComboBox, SIGNAL(activated(int)), this, SLOT(planeSelected(int))); + ui->planePushButton->setEnabled(ui->planeComboBox->count() > 0); + + ui->flyingWingComboBox->addItem(tr("Bormatec Camflyer Q"), 30); + ui->flyingWingComboBox->addItem(tr("Phantom FPV"), 31); + + connect(ui->flyingWingPushButton, SIGNAL(clicked()), this, SLOT(flyingWingSelected())); + connect(ui->flyingWingComboBox, SIGNAL(activated(int)), this, SLOT(flyingWingSelected(int))); + + ui->quadXComboBox->addItem(tr("DJI F330 8\" Quad"), 10); + ui->quadXComboBox->addItem(tr("DJI F450 10\" Quad"), 11); + ui->quadXComboBox->addItem(tr("Turnigy Talon v2 X550 Quad"), 666); + ui->quadXComboBox->addItem(tr("AR.Drone Frame Quad"), 8); + ui->quadXComboBox->addItem(tr("AR.Drone Quad (w. PX4FLOW)"), 9); + + connect(ui->quadXPushButton, SIGNAL(clicked()), this, SLOT(quadXSelected())); + connect(ui->quadXComboBox, SIGNAL(activated(int)), this, SLOT(quadXSelected(int))); + + connect(ui->quadPlusPushButton, SIGNAL(clicked()), this, SLOT(quadPlusSelected())); + connect(ui->quadPlusComboBox, SIGNAL(activated(int)), this, SLOT(quadPlusSelected(int))); + ui->quadPlusPushButton->setEnabled(ui->quadPlusComboBox->count() > 0); + + connect(ui->hexaXPushButton, SIGNAL(clicked()), this, SLOT(hexaXSelected())); + connect(ui->hexaXComboBox, SIGNAL(activated(int)), this, SLOT(hexaXSelected(int))); + ui->hexaXPushButton->setEnabled(ui->hexaXComboBox->count() > 0); + + connect(ui->hexaPlusPushButton, SIGNAL(clicked()), this, SLOT(hexaPlusSelected())); + connect(ui->hexaPlusComboBox, SIGNAL(activated(int)), this, SLOT(hexaPlusSelected(int))); + ui->hexaPlusPushButton->setEnabled(ui->hexaPlusComboBox->count() > 0); + + connect(ui->octoXPushButton, SIGNAL(clicked()), this, SLOT(octoXSelected())); + connect(ui->octoXComboBox, SIGNAL(activated(int)), this, SLOT(octoXSelected(int))); + ui->octoXPushButton->setEnabled(ui->octoXComboBox->count() > 0); + + connect(ui->octoPlusPushButton, SIGNAL(clicked()), this, SLOT(octoPlusSelected())); + connect(ui->octoPlusComboBox, SIGNAL(activated(int)), this, SLOT(octoPlusSelected(int))); + ui->octoPlusPushButton->setEnabled(ui->octoPlusComboBox->count() > 0); + + ui->hComboBox->addItem(tr("3DR Iris"), 16); + ui->hComboBox->addItem(tr("TBS Discovery"), 15); + + connect(ui->hPushButton, SIGNAL(clicked()), this, SLOT(hSelected())); + connect(ui->hComboBox, SIGNAL(activated(int)), this, SLOT(hSelected(int))); + ui->hPushButton->setEnabled(ui->hComboBox->count() > 0); + + connect(ui->applyButton, SIGNAL(clicked()), this, SLOT(applyAndReboot())); + + connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*))); + + setActiveUAS(UASManager::instance()->getActiveUAS()); + + uncheckAll(); +} + +void QGCPX4AirframeConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + Q_UNUSED(uas); + Q_UNUSED(component); + + if (parameterName.contains("SYS_AUTOSTART")) + { + int index = value.toInt(); + if (index > 0) { + setAirframeID(index); + ui->statusLabel->setText(tr("Onboard start script ID: #%1").arg(index)); + } else { + uncheckAll(); + ui->statusLabel->setText(tr("System not configured for autostart.")); + } + } +} + +void QGCPX4AirframeConfig::setActiveUAS(UASInterface* uas) +{ + if (mav) + { + disconnect(mav, SIGNAL(parameterChanged(int,int,QString,QVariant)), this, SLOT(parameterChanged(int,int,QString,QVariant))); + mav = NULL; + } + + if (!uas) + return; + + mav = uas; + paramMgr = mav->getParamManager(); + + connect(mav, SIGNAL(parameterChanged(int,int,QString,QVariant)), this, SLOT(parameterChanged(int,int,QString,QVariant))); +} + +void QGCPX4AirframeConfig::uncheckAll() +{ + ui->planePushButton->setChecked(false); + ui->flyingWingPushButton->setChecked(false); + ui->quadXPushButton->setChecked(false); + ui->quadPlusPushButton->setChecked(false); + ui->hexaXPushButton->setChecked(false); + ui->hexaPlusPushButton->setChecked(false); + ui->octoXPushButton->setChecked(false); + ui->octoPlusPushButton->setChecked(false); + ui->hPushButton->setChecked(false); +} + +void QGCPX4AirframeConfig::setAirframeID(int id) +{ + + qDebug() << "setAirframeID" << id; + ui->statusLabel->setText(tr("Start script ID: #%1").arg(id)); + + selectedId = id; + + // XXX too much boilerplate code here - this widget is really just + // a quick hack to get started + uncheckAll(); + + if (id > 0 && id < 15) { + ui->quadXPushButton->setChecked(true); + ui->quadXComboBox->setCurrentIndex(ui->quadXComboBox->findData(id)); + ui->statusLabel->setText(tr("Selected quad X (ID: #%1)").arg(selectedId)); + } + else if (id >= 15 && id < 20) + { + ui->hPushButton->setChecked(true); + ui->hComboBox->setCurrentIndex(ui->hComboBox->findData(id)); + ui->statusLabel->setText(tr("Selected H Frame (ID: #%1)").arg(selectedId)); + } + else if (id >= 30 && id < 50) + { + ui->flyingWingPushButton->setChecked(true); + ui->flyingWingComboBox->setCurrentIndex(ui->flyingWingComboBox->findData(id)); + ui->statusLabel->setText(tr("Selected flying wing (ID: #%1)").arg(selectedId)); + } + else if (id >= 100 && id < 150 || id >= 1000 <= 2000) + { + ui->planePushButton->setChecked(true); + ui->planeComboBox->setCurrentIndex(ui->planeComboBox->findData(id)); + ui->statusLabel->setText(tr("Selected plane (ID: #%1)").arg(selectedId)); + } +} + +void QGCPX4AirframeConfig::applyAndReboot() +{ + // Guard against the case of an edit where we didn't receive all params yet + if (selectedId <= 0) + { + QMessageBox msgBox; + msgBox.setText(tr("No airframe selected")); + msgBox.setInformativeText(tr("Please select an airframe first.")); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setDefaultButton(QMessageBox::Ok); + (void)msgBox.exec(); + + return; + } + + if (!mav) + return; + + if (paramMgr->countOnboardParams() == 0 && + paramMgr->countPendingParams() == 0) + { + paramMgr->requestParameterList(); + QGC::SLEEP::msleep(300); + } + + QList components = paramMgr->getComponentForParam("SYS_AUTOSTART"); + + // Guard against the case of an edit where we didn't receive all params yet + if (paramMgr->countPendingParams() > 0 || components.count() == 0) + { + QMessageBox msgBox; + msgBox.setText(tr("Parameter sync with UAS not yet complete")); + msgBox.setInformativeText(tr("Please wait a few moments and retry")); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setDefaultButton(QMessageBox::Ok); + (void)msgBox.exec(); + + return; + } + + // Guard against multiple components responding - this will never show in practice + if (components.count() != 1) { + QMessageBox msgBox; + msgBox.setText(tr("Invalid system setup detected")); + msgBox.setInformativeText(tr("None or more than one component advertised to provide the main system configuration option. This is an invalid system setup - please check your autopilot.")); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setDefaultButton(QMessageBox::Ok); + (void)msgBox.exec(); + + return; + } + + // This is really evil: 'fake' a thread by + // periodic work queue calls and clock + // through a small state machine + // ugh.. if we just had time to do this properly. + + // To the reader who can't program and wants to whine: + // this is not beautiful, but technically completely + // sound. If you want to fix it, you'd be welcome + // to rebase the link, param manager and UI classes + // on a proper threading framework - which I'd love to do + // if I just had more time.. + + configState = CONFIG_STATE_SEND; + QTimer::singleShot(200, this, SLOT(checkConfigState())); + setEnabled(false); +} + +void QGCPX4AirframeConfig::checkConfigState() +{ + + if (configState == CONFIG_STATE_SEND) + { + QList components = paramMgr->getComponentForParam("SYS_AUTOSTART"); + qDebug() << "Setting comp" << components.first() << "SYS_AUTOSTART" << (qint32)selectedId; + + paramMgr->setPendingParam(components.first(),"SYS_AUTOSTART", (qint32)selectedId); + + //need to set autoconfig in order for PX4 to pick up the selected airframe params + if (ui->defaultGainsCheckBox->checkState() == Qt::Checked) + setAutoConfig(true); + + // Send pending params and then write them to persistent storage when done + paramMgr->sendPendingParameters(true); + + configState = CONFIG_STATE_WAIT_PENDING; + pendingParams = 0; + QTimer::singleShot(2000, this, SLOT(checkConfigState())); + return; + } + + if (configState == CONFIG_STATE_WAIT_PENDING) { + // Guard against the case of an edit where we didn't receive all params yet + if (paramMgr->countPendingParams() > 0) + { + if (pendingParams == 0) { + + pendingParams = paramMgr->countPendingParams(); + + if (progress) + delete progress; + + progress = new QProgressDialog("Writing parameters", "Abort Send", 0, pendingParams, this); + progress->setWindowModality(Qt::WindowModal); + progress->setMinimumDuration(2000); + } + + qDebug() << "PENDING" << paramMgr->countPendingParams() << "PROGRESS" << pendingParams - paramMgr->countPendingParams(); + progress->setValue(pendingParams - paramMgr->countPendingParams()); + + if (progress->wasCanceled()) { + configState = CONFIG_STATE_ABORT; + setEnabled(true); + pendingParams = 0; + return; + } + } else { + pendingParams = 0; + configState = CONFIG_STATE_REBOOT; + } + + qDebug() << "PENDING PARAMS WAIT PENDING: " << paramMgr->countPendingParams(); + QTimer::singleShot(1000, this, SLOT(checkConfigState())); + return; + } + + if (configState == CONFIG_STATE_REBOOT) { + + // Reboot + //TODO right now this relies upon the above send & persist finishing before the reboot command is received... + + unsigned pendingMax = 17; + + qDebug() << "PENDING PARAMS REBOOT BEFORE" << pendingParams; + + if (pendingParams == 0) { + pendingParams = 1; + + if (progress) + delete progress; + + progress = new QProgressDialog("Waiting for autopilot reboot", "Abort", 0, pendingMax, this); + progress->setWindowModality(Qt::WindowModal); + qDebug() << "Waiting for reboot, pending" << pendingParams; + } else { + if (progress->wasCanceled()) { + configState = CONFIG_STATE_ABORT; + setEnabled(true); + pendingParams = 0; + return; + } + } + + if (pendingParams == 3) { + qDebug() << "REQUESTING REBOOT"; + mav->executeCommand(MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN, 1, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0); + mav->executeCommand(MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN, 1, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0); + } + + if (pendingParams == 4) { + qDebug() << "DISCONNECT AIRFRAME"; + LinkManager::instance()->disconnectAll(); + } + + if (pendingParams == 14) { + qDebug() << "CONNECT AIRFRAME"; + LinkManager::instance()->connectAll(); + } + + if (pendingParams < pendingMax) { + progress->setValue(pendingParams); + QTimer::singleShot(1000, this, SLOT(checkConfigState())); + } else { + paramMgr->requestParameterList(); + progress->setValue(pendingMax); + configState = CONFIG_STATE_ABORT; + pendingParams = 0; + setEnabled(true); + return; + } + qDebug() << "PENDING PARAMS REBOOT AFTER:" << pendingParams; + pendingParams++; + return; + } +} + +void QGCPX4AirframeConfig::setAutoConfig(bool enabled) +{ + if (!mav) + return; + paramMgr->setPendingParam(0, "SYS_AUTOCONFIG", (qint32) ((enabled) ? 1 : 0)); +} + +void QGCPX4AirframeConfig::flyingWingSelected() +{ + flyingWingSelected(ui->flyingWingComboBox->currentIndex()); +} + +void QGCPX4AirframeConfig::flyingWingSelected(int index) +{ + int system_index = ui->flyingWingComboBox->itemData(index).toInt(); + setAirframeID(system_index); +} + +void QGCPX4AirframeConfig::planeSelected() +{ + planeSelected(ui->planeComboBox->currentIndex()); +} + +void QGCPX4AirframeConfig::planeSelected(int index) +{ + int system_index = ui->planeComboBox->itemData(index).toInt(); + setAirframeID(system_index); +} + + +void QGCPX4AirframeConfig::quadXSelected() +{ + quadXSelected(ui->quadXComboBox->currentIndex()); +} + +void QGCPX4AirframeConfig::quadXSelected(int index) +{ + int system_index = ui->quadXComboBox->itemData(index).toInt(); + setAirframeID(system_index); +} + +void QGCPX4AirframeConfig::quadPlusSelected() +{ + quadPlusSelected(ui->quadPlusComboBox->currentIndex()); +} + +void QGCPX4AirframeConfig::quadPlusSelected(int index) +{ + int system_index = ui->quadPlusComboBox->itemData(index).toInt(); + setAirframeID(system_index); +} + +void QGCPX4AirframeConfig::hexaXSelected() +{ + hexaXSelected(ui->hexaXComboBox->currentIndex()); +} + +void QGCPX4AirframeConfig::hexaXSelected(int index) +{ + int system_index = ui->hexaXComboBox->itemData(index).toInt(); + setAirframeID(system_index); +} + +void QGCPX4AirframeConfig::hexaPlusSelected() +{ + hexaPlusSelected(ui->hexaPlusComboBox->currentIndex()); +} + +void QGCPX4AirframeConfig::hexaPlusSelected(int index) +{ + int system_index = ui->hexaPlusComboBox->itemData(index).toInt(); + setAirframeID(system_index); +} + +void QGCPX4AirframeConfig::octoXSelected() +{ + octoXSelected(ui->octoXComboBox->currentIndex()); +} + +void QGCPX4AirframeConfig::octoXSelected(int index) +{ + int system_index = ui->octoXComboBox->itemData(index).toInt(); + setAirframeID(system_index); +} + +void QGCPX4AirframeConfig::octoPlusSelected() +{ + octoPlusSelected(ui->octoPlusComboBox->currentIndex()); +} + +void QGCPX4AirframeConfig::octoPlusSelected(int index) +{ + int system_index = ui->octoPlusComboBox->itemData(index).toInt(); + setAirframeID(system_index); +} + +void QGCPX4AirframeConfig::hSelected() +{ + hSelected(ui->hComboBox->currentIndex()); +} + +void QGCPX4AirframeConfig::hSelected(int index) +{ + int system_index = ui->hComboBox->itemData(index).toInt(); + setAirframeID(system_index); +} + + +QGCPX4AirframeConfig::~QGCPX4AirframeConfig() +{ + delete ui; +} diff --git a/src/ui/px4_configuration/QGCPX4AirframeConfig.h b/src/ui/px4_configuration/QGCPX4AirframeConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..dcbf4abc142faa3349eb7cc153e5a70149a5512d --- /dev/null +++ b/src/ui/px4_configuration/QGCPX4AirframeConfig.h @@ -0,0 +1,108 @@ +#ifndef QGCPX4AIRFRAMECONFIG_H +#define QGCPX4AIRFRAMECONFIG_H + +#include +#include + +class QProgressDialog; + +namespace Ui { +class QGCPX4AirframeConfig; +} + +class QGCPX4AirframeConfig : public QWidget +{ + Q_OBJECT + +public: + explicit QGCPX4AirframeConfig(QWidget *parent = 0); + ~QGCPX4AirframeConfig(); + +public slots: + + /** + * @brief Set the system currently operated on by this widget + * @param uas The currently active / configured system + */ + void setActiveUAS(UASInterface* uas); + + /** + * @brief Handle parameter changes + * @param uas + * @param component + * @param parameterName + * @param value + */ + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + + /** + * @brief Quadrotor in X configuration has been selected + */ + void quadXSelected(); + + /** + * @brief Quadrotor in X configuration has been selected with sub-type + * @param index The autostart index which maps to a particular sub-type + */ + void quadXSelected(int index); + + void flyingWingSelected(); + void flyingWingSelected(int index); + void planeSelected(); + void planeSelected(int index); + + void quadPlusSelected(); + void quadPlusSelected(int index); + void hexaXSelected(); + void hexaXSelected(int index); + void hexaPlusSelected(); + void hexaPlusSelected(int index); + void octoXSelected(); + void octoXSelected(int index); + void octoPlusSelected(); + void octoPlusSelected(int index); + void hSelected(); + void hSelected(int index); + + /** + * @brief Apply changes and reboot system + */ + void applyAndReboot(); + +protected slots: + void checkConfigState(); + +protected: + + /** + * @brief Set the ID of the current airframe + * @param id the ID as defined by the PX4 SYS_AUTOSTART enum + */ + void setAirframeID(int id); + + /** + * @brief Enable automatic configuration + * @param enabled If true, the system sets the default gains for this platform on the next boot + */ + void setAutoConfig(bool enabled); + + void uncheckAll(); + + enum CONFIG_STATE { + CONFIG_STATE_ABORT = 0, + CONFIG_STATE_SEND, + CONFIG_STATE_WAIT_PENDING, + CONFIG_STATE_REBOOT + }; + +private: + UASInterface* mav; + QGCUASParamManager *paramMgr; + QProgressDialog* progress; + unsigned pendingParams; + enum CONFIG_STATE configState; + int selectedId; + Ui::QGCPX4AirframeConfig *ui; +}; + +#endif // QGCPX4AIRFRAMECONFIG_H diff --git a/src/ui/px4_configuration/QGCPX4AirframeConfig.ui b/src/ui/px4_configuration/QGCPX4AirframeConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..245c3741ef40d1ac8dd87a8f9436251fb15e696c --- /dev/null +++ b/src/ui/px4_configuration/QGCPX4AirframeConfig.ui @@ -0,0 +1,385 @@ + + + QGCPX4AirframeConfig + + + + 0 + 0 + 803 + 416 + + + + Form + + + + + + Set default airframe settings + + + true + + + + + + + true + + + + + 0 + 0 + 762 + 647 + + + + + + + + + + + + + :/files/images/px4/airframes/plane_aert.png:/files/images/px4/airframes/plane_aert.png + + + + 120 + 120 + + + + true + + + + + + + + + + Standard Plane + + + + + + + + + + + + + + + :/files/images/px4/airframes/flying_wing.png:/files/images/px4/airframes/flying_wing.png + + + + 120 + 120 + + + + true + + + + + + + + + + Flying Wing + + + + + + + + + + + + + + + :/files/images/px4/airframes/quad_x.png:/files/images/px4/airframes/quad_x.png + + + + 120 + 120 + + + + true + + + + + + + + + + Quadrotor X + + + + + + + + + + + + + + + :/files/images/px4/airframes/quad_+.png:/files/images/px4/airframes/quad_+.png + + + + 120 + 120 + + + + true + + + + + + + + + + Quadrotor + + + + + + + + + + + + + + + + :/files/images/px4/airframes/hexa_x.png:/files/images/px4/airframes/hexa_x.png + + + + 120 + 120 + + + + true + + + + + + + + + + Hexarotor X + + + + + + + + + + + + + + + :/files/images/px4/airframes/hexa_+.png:/files/images/px4/airframes/hexa_+.png + + + + 120 + 120 + + + + true + + + + + + + + + + Hexarotor + + + + + + + + + + + + + + + + :/files/images/px4/airframes/octo_x.png:/files/images/px4/airframes/octo_x.png + + + + 120 + 120 + + + + true + + + + + + + + + + Octorotor X + + + + + + + + + + + + + + + :/files/images/px4/airframes/octo_+.png:/files/images/px4/airframes/octo_+.png + + + + 120 + 120 + + + + true + + + + + + + + + + Octorotor + + + + + + + + + + + + + + + + :/files/images/px4/airframes/quad_h.png:/files/images/px4/airframes/quad_h.png + + + + 120 + 120 + + + + true + + + + + + + + + + H Frame + + + + + + + + + + + + + Apply and Restart + + + + + + + No changes values + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + diff --git a/src/ui/px4_configuration/QGCPX4MulticopterConfig.cc b/src/ui/px4_configuration/QGCPX4MulticopterConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..920d708364d93c014b4df2cdf0c00d073968dd85 --- /dev/null +++ b/src/ui/px4_configuration/QGCPX4MulticopterConfig.cc @@ -0,0 +1,14 @@ +#include "QGCPX4MulticopterConfig.h" +#include "ui_QGCPX4MulticopterConfig.h" + +QGCPX4MulticopterConfig::QGCPX4MulticopterConfig(QWidget *parent) : + QWidget(parent), + ui(new Ui::QGCPX4MulticopterConfig) +{ + ui->setupUi(this); +} + +QGCPX4MulticopterConfig::~QGCPX4MulticopterConfig() +{ + delete ui; +} diff --git a/src/ui/px4_configuration/QGCPX4MulticopterConfig.h b/src/ui/px4_configuration/QGCPX4MulticopterConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..7a9140b74c61deb1b4bf87c1dc95ec0928f05208 --- /dev/null +++ b/src/ui/px4_configuration/QGCPX4MulticopterConfig.h @@ -0,0 +1,22 @@ +#ifndef QGCPX4MULTICOPTERCONFIG_H +#define QGCPX4MULTICOPTERCONFIG_H + +#include + +namespace Ui { +class QGCPX4MulticopterConfig; +} + +class QGCPX4MulticopterConfig : public QWidget +{ + Q_OBJECT + +public: + explicit QGCPX4MulticopterConfig(QWidget *parent = 0); + ~QGCPX4MulticopterConfig(); + +private: + Ui::QGCPX4MulticopterConfig *ui; +}; + +#endif // QGCPX4MULTICOPTERCONFIG_H diff --git a/src/ui/px4_configuration/QGCPX4MulticopterConfig.ui b/src/ui/px4_configuration/QGCPX4MulticopterConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..6a10dfc26d8949bbaf8956432120ab8b9a5f48e1 --- /dev/null +++ b/src/ui/px4_configuration/QGCPX4MulticopterConfig.ui @@ -0,0 +1,123 @@ + + + QGCPX4MulticopterConfig + + + + 0 + 0 + 605 + 449 + + + + Form + + + + + 130 + 150 + 341 + 22 + + + + Qt::Horizontal + + + + + + 130 + 400 + 351 + 22 + + + + Qt::Horizontal + + + + + + 30 + 160 + 62 + 16 + + + + TextLabel + + + + + + 510 + 160 + 62 + 16 + + + + TextLabel + + + + + + 40 + 400 + 62 + 16 + + + + TextLabel + + + + + + 520 + 400 + 62 + 16 + + + + TextLabel + + + + + + 30 + 10 + 62 + 16 + + + + TextLabel + + + + + + 30 + 200 + 62 + 16 + + + + TextLabel + + + + + + diff --git a/src/ui/px4_configuration/QGCPX4SensorCalibration.cc b/src/ui/px4_configuration/QGCPX4SensorCalibration.cc new file mode 100644 index 0000000000000000000000000000000000000000..a4ec8a356a44e92940e67cce86ac5d5d66317926 --- /dev/null +++ b/src/ui/px4_configuration/QGCPX4SensorCalibration.cc @@ -0,0 +1,474 @@ +#include "QGCPX4SensorCalibration.h" +#include "ui_QGCPX4SensorCalibration.h" +#include +#include +#include +#include + +QGCPX4SensorCalibration::QGCPX4SensorCalibration(QWidget *parent) : + QWidget(parent), + activeUAS(NULL), + clearAction(new QAction(tr("Clear Text"), this)), + ui(new Ui::QGCPX4SensorCalibration) +{ + ui->setupUi(this); + connect(clearAction, SIGNAL(triggered()), ui->textView, SLOT(clear())); + + connect(ui->gyroButton, SIGNAL(clicked()), this, SLOT(gyroButtonClicked())); + connect(ui->magButton, SIGNAL(clicked()), this, SLOT(magButtonClicked())); + connect(ui->accelButton, SIGNAL(clicked()), this, SLOT(accelButtonClicked())); + connect(ui->diffPressureButton, SIGNAL(clicked()), this, SLOT(diffPressureButtonClicked())); + + ui->gyroButton->setEnabled(false); + ui->magButton->setEnabled(false); + ui->accelButton->setEnabled(false); + + ui->autopilotComboBox->setEnabled(false); + ui->magComboBox->setEnabled(false); + + setInstructionImage(":/files/images/px4/calibration/accel_z-.png"); + setAutopilotImage(":/files/images/px4/calibration/accel_z-.png"); + setGpsImage(":/files/images/px4/calibration/accel_z-.png"); + + // Fill combo boxes + ui->autopilotComboBox->addItem(tr("Default Orientation"), 0); + ui->autopilotComboBox->addItem(tr("ROTATION_YAW_45"), 1); + ui->autopilotComboBox->addItem(tr("ROTATION_YAW_90"), 2); + ui->autopilotComboBox->addItem(tr("ROTATION_YAW_135"), 3); + ui->autopilotComboBox->addItem(tr("ROTATION_YAW_180"), 4); + ui->autopilotComboBox->addItem(tr("ROTATION_YAW_225"), 5); + ui->autopilotComboBox->addItem(tr("ROTATION_YAW_270"), 6); + ui->autopilotComboBox->addItem(tr("ROTATION_YAW_315"), 7); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_180"), 8); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_180_YAW_45"), 9); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_180_YAW_90"), 10); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_180_YAW_135"), 11); + ui->autopilotComboBox->addItem(tr("ROTATION_PITCH_180"), 12); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_180_YAW_225"), 13); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_180_YAW_270"), 14); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_180_YAW_315"), 15); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_90"), 16); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_90_YAW_45"), 17); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_90_YAW_90"), 18); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_90_YAW_135"), 19); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_270"), 20); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_270_YAW_45"), 21); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_270_YAW_90"), 22); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_270_YAW_135"), 23); + ui->autopilotComboBox->addItem(tr("ROTATION_PITCH_90"), 24); + ui->autopilotComboBox->addItem(tr("ROTATION_PITCH_270"), 25); + ui->autopilotComboBox->addItem(tr("ROTATION_PITCH_180_YAW_90"), 26); + ui->autopilotComboBox->addItem(tr("ROTATION_PITCH_180_YAW_270"), 27); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_90_PITCH_90"), 28); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_180_PITCH_90"), 29); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_270_PITCH_90"), 30); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_90_PITCH_180"), 31); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_270_PITCH_180"), 32); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_90_PITCH_270"), 33); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_180_PITCH_270"), 34); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_270_PITCH_270"), 35); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_90_PITCH_180_YAW_90"), 36); + ui->autopilotComboBox->addItem(tr("ROTATION_ROLL_90_YAW_270"), 37); + + ui->magComboBox->addItem(tr("Default Orientation"), 0); + ui->magComboBox->addItem(tr("ROTATION_YAW_45"), 1); + ui->magComboBox->addItem(tr("ROTATION_YAW_90"), 2); + ui->magComboBox->addItem(tr("ROTATION_YAW_135"), 3); + ui->magComboBox->addItem(tr("ROTATION_YAW_180"), 4); + ui->magComboBox->addItem(tr("ROTATION_YAW_225"), 5); + ui->magComboBox->addItem(tr("ROTATION_YAW_270"), 6); + ui->magComboBox->addItem(tr("ROTATION_YAW_315"), 7); + ui->magComboBox->addItem(tr("ROTATION_ROLL_180"), 8); + ui->magComboBox->addItem(tr("ROTATION_ROLL_180_YAW_45"), 9); + ui->magComboBox->addItem(tr("ROTATION_ROLL_180_YAW_90"), 10); + ui->magComboBox->addItem(tr("ROTATION_ROLL_180_YAW_135"), 11); + ui->magComboBox->addItem(tr("ROTATION_PITCH_180"), 12); + ui->magComboBox->addItem(tr("ROTATION_ROLL_180_YAW_225"), 13); + ui->magComboBox->addItem(tr("ROTATION_ROLL_180_YAW_270"), 14); + ui->magComboBox->addItem(tr("ROTATION_ROLL_180_YAW_315"), 15); + ui->magComboBox->addItem(tr("ROTATION_ROLL_90"), 16); + ui->magComboBox->addItem(tr("ROTATION_ROLL_90_YAW_45"), 17); + ui->magComboBox->addItem(tr("ROTATION_ROLL_90_YAW_90"), 18); + ui->magComboBox->addItem(tr("ROTATION_ROLL_90_YAW_135"), 19); + ui->magComboBox->addItem(tr("ROTATION_ROLL_270"), 20); + ui->magComboBox->addItem(tr("ROTATION_ROLL_270_YAW_45"), 21); + ui->magComboBox->addItem(tr("ROTATION_ROLL_270_YAW_90"), 22); + ui->magComboBox->addItem(tr("ROTATION_ROLL_270_YAW_135"), 23); + ui->magComboBox->addItem(tr("ROTATION_PITCH_90"), 24); + ui->magComboBox->addItem(tr("ROTATION_PITCH_270"), 25); + + setObjectName("PX4_SENSOR_CALIBRATION"); + + setStyleSheet("QScrollArea { border: 0px; } QPlainTextEdit { border: 0px }"); + + setActiveUAS(UASManager::instance()->getActiveUAS()); + connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*))); + ui->progressBar->setValue(0); + + connect(ui->autopilotComboBox, SIGNAL(activated(int)), this, SLOT(setAutopilotOrientation(int))); + connect(ui->magComboBox, SIGNAL(activated(int)), this, SLOT(setGpsOrientation(int))); + + updateIcons(); +} + +QGCPX4SensorCalibration::~QGCPX4SensorCalibration() +{ + delete ui; +} + +void QGCPX4SensorCalibration::parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + Q_UNUSED(uas); + Q_UNUSED(component); + + int index = (int)value.toFloat(); + + if (parameterName.contains("SENS_BOARD_ROT")) + { + ui->autopilotComboBox->setCurrentIndex(index); + setAutopilotImage(index); + ui->autopilotComboBox->setEnabled(true); + } + + if (parameterName.contains("SENS_EXT_MAG_ROT")) + { + ui->magComboBox->setCurrentIndex(index); + setGpsImage(index); + ui->magComboBox->setEnabled(true); + } + + // Check mag calibration naively + if (parameterName.contains("SENS_MAG_XOFF")) { + float offset = value.toFloat(); + if (offset < 0.000001f && offset > -0.000001f) { + // Must be zero, not good + setMagCalibrated(false); + } else { + setMagCalibrated(true); + } + } + + // Check gyro calibration naively + if (parameterName.contains("SENS_GYRO_XOFF")) { + float offset = value.toFloat(); + if (offset < 0.000001f && offset > -0.000001f) { + // Must be zero, not good + setGyroCalibrated(false); + } else { + setGyroCalibrated(true); + } + } + + // Check accel calibration naively + if (parameterName.contains("SENS_ACC_XOFF")) { + float offset = value.toFloat(); + if (offset < 0.000001f && offset > -0.000001f) { + // Must be zero, not good + setAccelCalibrated(false); + } else { + setAccelCalibrated(true); + } + } + + // Check differential pressure calibration naively + if (parameterName.contains("SENS_DPRES_OFF")) { + float offset = value.toFloat(); + if (offset < 0.000001f && offset > -0.000001f) { + // Must be zero, not good + setDiffPressureCalibrated(false); + } else { + setDiffPressureCalibrated(true); + } + } +} + +void QGCPX4SensorCalibration::setMagCalibrated(bool calibrated) +{ + if (calibrated) { + ui->magLabel->setText(tr("MAG CALIBRATED")); + ui->magLabel->setStyleSheet("QLabel { color: #FFFFFF;" + "background-color: #20AA20;" + "}"); + } else { + ui->magLabel->setText(tr("MAG UNCALIBRATED")); + ui->magLabel->setStyleSheet("QLabel { color: #FFFFFF;" + "background-color: #FF0037;" + "}"); + } +} + +void QGCPX4SensorCalibration::setGyroCalibrated(bool calibrated) +{ + if (calibrated) { + ui->gyroLabel->setText(tr("GYRO CALIBRATED")); + ui->gyroLabel->setStyleSheet("QLabel { color: #FFFFFF;" + "background-color: #20AA20;" + "}"); + } else { + ui->gyroLabel->setText(tr("GYRO UNCALIBRATED")); + ui->gyroLabel->setStyleSheet("QLabel { color: #FFFFFF;" + "background-color: #FF0037;" + "}"); + } +} + +void QGCPX4SensorCalibration::setAccelCalibrated(bool calibrated) +{ + if (calibrated) { + ui->accelLabel->setText(tr("ACCEL CALIBRATED")); + ui->accelLabel->setStyleSheet("QLabel { color: #FFFFFF;" + "background-color: #20AA20;" + "}"); + } else { + ui->accelLabel->setText(tr("ACCEL UNCALIBRATED")); + ui->accelLabel->setStyleSheet("QLabel { color: #FFFFFF;" + "background-color: #FF0037;" + "}"); + } +} + +void QGCPX4SensorCalibration::setDiffPressureCalibrated(bool calibrated) +{ + if (calibrated) { + ui->diffPressureLabel->setText(tr("DIFF. PRESSURE CALIBRATED")); + ui->diffPressureLabel->setStyleSheet("QLabel { color: #FFFFFF;" + "background-color: #20AA20;" + "}"); + } else { + ui->diffPressureLabel->setText(tr("DIFF. PRESSURE UNCALIBRATED")); + ui->diffPressureLabel->setStyleSheet("QLabel { color: #FFFFFF;" + "background-color: #FF0037;" + "}"); + } +} + +void QGCPX4SensorCalibration::setInstructionImage(const QString &path) +{ + instructionIcon.load(path); + + int w = ui->iconLabel->width(); + int h = ui->iconLabel->height(); + + ui->iconLabel->setPixmap(instructionIcon.scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation)); +} + +void QGCPX4SensorCalibration::setAutopilotImage(int index) +{ + setAutopilotImage(QString(":/files/images/px4/calibration/pixhawk_%1.png").arg(index, 2, 10, QChar('0'))); +} + +void QGCPX4SensorCalibration::setGpsImage(int index) +{ + setGpsImage(QString(":/files/images/px4/calibration/3dr_gps/gps_%1.png").arg(index, 2, 10, QChar('0'))); +} + +void QGCPX4SensorCalibration::setAutopilotOrientation(int index) +{ + if (activeUAS) { + activeUAS->getParamManager()->setPendingParam(0, "SENS_BOARD_ROT", (int)index); + activeUAS->getParamManager()->sendPendingParameters(true); + } +} + +void QGCPX4SensorCalibration::setGpsOrientation(int index) +{ + if (activeUAS) { + activeUAS->getParamManager()->setPendingParam(0, "SENS_EXT_MAG_ROT", (int)index); + activeUAS->getParamManager()->sendPendingParameters(true); + } +} + +void QGCPX4SensorCalibration::setAutopilotImage(const QString &path) +{ + autopilotIcon.load(path); + + int w = ui->autopilotLabel->width(); + int h = ui->autopilotLabel->height(); + + ui->autopilotLabel->setPixmap(autopilotIcon.scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation)); +} + +void QGCPX4SensorCalibration::setGpsImage(const QString &path) +{ + gpsIcon.load(path); + + int w = ui->gpsLabel->width(); + int h = ui->gpsLabel->height(); + + ui->gpsLabel->setPixmap(gpsIcon.scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation)); +} + +void QGCPX4SensorCalibration::updateIcons() +{ + int w = ui->iconLabel->width(); + int h = ui->iconLabel->height(); + ui->iconLabel->setPixmap(instructionIcon.scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + + int wa = ui->autopilotLabel->width(); + int ha = ui->autopilotLabel->height(); + ui->autopilotLabel->setPixmap(autopilotIcon.scaled(wa, ha, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + + int wg = ui->gpsLabel->width(); + int hg = ui->gpsLabel->height(); + ui->gpsLabel->setPixmap(gpsIcon.scaled(wg, hg, Qt::KeepAspectRatio, Qt::SmoothTransformation)); +} + +void QGCPX4SensorCalibration::resizeEvent(QResizeEvent* event) +{ + updateIcons(); + QWidget::resizeEvent(event); +} + +void QGCPX4SensorCalibration::setActiveUAS(UASInterface* uas) +{ + if (!uas) + return; + + if (activeUAS) { + disconnect(activeUAS, SIGNAL(textMessageReceived(int,int,int,QString)), this, SLOT(handleTextMessage(int,int,int,QString))); + disconnect(activeUAS, SIGNAL(parameterChanged(int,int,QString,QVariant)), this, SLOT(parameterChanged(int,int,QString,QVariant))); + ui->textView->clear(); + } + + ui->gyroButton->setEnabled(true); + ui->magButton->setEnabled(true); + ui->accelButton->setEnabled(true); + + connect(uas, SIGNAL(textMessageReceived(int,int,int,QString)), this, SLOT(handleTextMessage(int,int,int,QString))); + connect(uas, SIGNAL(parameterChanged(int,int,QString,QVariant)), this, SLOT(parameterChanged(int,int,QString,QVariant))); + activeUAS = uas; +} + +void QGCPX4SensorCalibration::handleTextMessage(int uasid, int compId, int severity, QString text) +{ + Q_UNUSED(uasid); + Q_UNUSED(compId); + Q_UNUSED(severity); + + if (text.startsWith("[cmd]") || + text.startsWith("[mavlink pm]")) + return; + + if (text.contains("progress <")) { + QString percent = text.split("<").last().split(">").first(); + bool ok; + int p = percent.toInt(&ok); + if (ok) + ui->progressBar->setValue(p); + return; + } + + ui->instructionLabel->setText(QString("%1").arg(text)); + + if (text.startsWith("accel measurement started: ")) { + QString axis = text.split("measurement started: ").last().left(2); + setInstructionImage(QString(":/files/images/px4/calibration/accel_%1.png").arg(axis)); + } + + if (text.startsWith("directions left: ")) { + QString axis = text.split("directions left: ").last().left(2); + setInstructionImage(QString(":/files/images/px4/calibration/accel_%1.png").arg(axis)); + } + + if (text == "rotate in a figure 8 around all axis") { + setInstructionImage(":/files/images/px4/calibration/mag_calibration_figure8.png"); + } + + if (text.endsWith(" calibration: done") || text.endsWith(" calibration: failed")) { + // XXX use a confirmation image or something + setInstructionImage(":/files/images/px4/calibration/accel_z-.png"); + if (text.endsWith(" calibration: done")) { + ui->progressBar->setValue(100); + } else { + ui->progressBar->setValue(0); + } + + if (activeUAS) { + if (text.startsWith("accel ")) { + activeUAS->requestParameter(0, "SENS_ACC_XOFF"); + activeUAS->requestParameter(0, "SENS_ACC_YOFF"); + activeUAS->requestParameter(0, "SENS_ACC_ZOFF"); + activeUAS->requestParameter(0, "SENS_ACC_XSCALE"); + activeUAS->requestParameter(0, "SENS_ACC_YSCALE"); + activeUAS->requestParameter(0, "SENS_ACC_ZSCALE"); + activeUAS->requestParameter(0, "SENS_BOARD_ROT"); + } + if (text.startsWith("gyro ")) { + activeUAS->requestParameter(0, "SENS_GYRO_XOFF"); + activeUAS->requestParameter(0, "SENS_GYRO_YOFF"); + activeUAS->requestParameter(0, "SENS_GYRO_ZOFF"); + activeUAS->requestParameter(0, "SENS_GYRO_XSCALE"); + activeUAS->requestParameter(0, "SENS_GYRO_YSCALE"); + activeUAS->requestParameter(0, "SENS_GYRO_ZSCALE"); + activeUAS->requestParameter(0, "SENS_BOARD_ROT"); + } + if (text.startsWith("mag ")) { + activeUAS->requestParameter(0, "SENS_MAG_XOFF"); + activeUAS->requestParameter(0, "SENS_MAG_YOFF"); + activeUAS->requestParameter(0, "SENS_MAG_ZOFF"); + activeUAS->requestParameter(0, "SENS_MAG_XSCALE"); + activeUAS->requestParameter(0, "SENS_MAG_YSCALE"); + activeUAS->requestParameter(0, "SENS_MAG_ZSCALE"); + activeUAS->requestParameter(0, "SENS_EXT_MAG_ROT"); + } + + if (text.startsWith("dpress ")) { + activeUAS->requestParameter(0, "SENS_DPRES_OFF"); + activeUAS->requestParameter(0, "SENS_DPRES_ANA"); + } + } + } + + if (text.endsWith(" calibration: started")) { + setInstructionImage(":/files/images/px4/calibration/accel_z-.png"); + } + + // XXX color messages according to severity + + QPlainTextEdit *msgWidget = ui->textView; + + //turn off updates while we're appending content to avoid breaking the autoscroll behavior + msgWidget->setUpdatesEnabled(false); + QScrollBar *scroller = msgWidget->verticalScrollBar(); + + msgWidget->appendHtml(QString("%4").arg(text)); + + // Ensure text area scrolls correctly + scroller->setValue(scroller->maximum()); + msgWidget->setUpdatesEnabled(true); +} + +void QGCPX4SensorCalibration::gyroButtonClicked() +{ + setInstructionImage(":/files/images/px4/calibration/accel_z-.png"); + activeUAS->executeCommand(MAV_CMD_PREFLIGHT_CALIBRATION, 1, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0); + ui->progressBar->setValue(0); +} + +void QGCPX4SensorCalibration::magButtonClicked() +{ + setInstructionImage(":/files/images/px4/calibration/accel_z-.png"); + activeUAS->executeCommand(MAV_CMD_PREFLIGHT_CALIBRATION, 1, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0); + ui->progressBar->setValue(0); +} + +void QGCPX4SensorCalibration::accelButtonClicked() +{ + setInstructionImage(":/files/images/px4/calibration/accel_z-.png"); + activeUAS->executeCommand(MAV_CMD_PREFLIGHT_CALIBRATION, 1, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0); + ui->progressBar->setValue(0); +} + +void QGCPX4SensorCalibration::diffPressureButtonClicked() +{ + setInstructionImage(":/files/images/px4/calibration/accel_z-.png"); + activeUAS->executeCommand(MAV_CMD_PREFLIGHT_CALIBRATION, 1, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0); + ui->progressBar->setValue(0); +} + +void QGCPX4SensorCalibration::contextMenuEvent(QContextMenuEvent* event) +{ + QMenu menu(this); + menu.addAction(clearAction); + menu.exec(event->globalPos()); +} diff --git a/src/ui/px4_configuration/QGCPX4SensorCalibration.h b/src/ui/px4_configuration/QGCPX4SensorCalibration.h new file mode 100644 index 0000000000000000000000000000000000000000..1bddf458f0ecf445894c6a3982af787803304568 --- /dev/null +++ b/src/ui/px4_configuration/QGCPX4SensorCalibration.h @@ -0,0 +1,83 @@ +#ifndef QGCPX4SENSORCALIBRATION_H +#define QGCPX4SENSORCALIBRATION_H + +#include +#include +#include + +namespace Ui { +class QGCPX4SensorCalibration; +} + +class QGCPX4SensorCalibration : public QWidget +{ + Q_OBJECT + +public: + explicit QGCPX4SensorCalibration(QWidget *parent = 0); + ~QGCPX4SensorCalibration(); + +public slots: + /** + * @brief Set currently active UAS + * @param uas the current active UAS + */ + void setActiveUAS(UASInterface* uas); + /** + * @brief Handle text message from current active UAS + * @param uasid + * @param componentid + * @param severity + * @param text + */ + void handleTextMessage(int uasid, int componentid, int severity, QString text); + + void gyroButtonClicked(); + void magButtonClicked(); + void accelButtonClicked(); + void diffPressureButtonClicked(); + + /** + * @brief Hand context menu event + * @param event + */ + virtual void contextMenuEvent(QContextMenuEvent* event); + + void setAutopilotOrientation(int index); + void setGpsOrientation(int index); + void parameterChanged(int uas, int component, QString parameterName, QVariant value); + +protected slots: + + void setInstructionImage(const QString &path); + + void setAutopilotImage(const QString &path); + + void setGpsImage(const int index); + + void setAutopilotImage(const int index); + + void setGpsImage(const QString &path); + +protected: + UASInterface* activeUAS; + QAction* clearAction; + QPixmap instructionIcon; + QPixmap autopilotIcon; + QPixmap gpsIcon; + + virtual void resizeEvent(QResizeEvent* event); + + void setMagCalibrated(bool calibrated); + void setGyroCalibrated(bool calibrated); + void setAccelCalibrated(bool calibrated); + void setDiffPressureCalibrated(bool calibrated); + + void updateIcons(); + +private: + Ui::QGCPX4SensorCalibration *ui; + +}; + +#endif // QGCPX4SENSORCALIBRATION_H diff --git a/src/ui/px4_configuration/QGCPX4SensorCalibration.ui b/src/ui/px4_configuration/QGCPX4SensorCalibration.ui new file mode 100644 index 0000000000000000000000000000000000000000..b1fd81425e547ba98420fb32634d757b78ffc095 --- /dev/null +++ b/src/ui/px4_configuration/QGCPX4SensorCalibration.ui @@ -0,0 +1,234 @@ + + + QGCPX4SensorCalibration + + + + 0 + 0 + 659 + 603 + + + + Form + + + QPushButton#magButton { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #73D95D, stop: 1 #18A154); + border-radius: 8px; + min-height: 25px; + max-height: 30px; + min-width: 60px; + max-width: 140px; + margin: 5px; + border: 2px solid #465158; +} + +QPushButton#gyroButton, QPushButton#accelButton, QPushButton#diffPressureButton { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #D3795D, stop: 1 #A81154); + border-radius: 8px; + min-height: 25px; + max-height: 30px; + min-width: 60px; + max-width: 140px; + margin: 5px; + border: 2px solid #465158; +} + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Vertical + + + + 498 + 5 + + + + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + Gyroscope + + + + :/files/images/px4/calibration/arrows.png:/files/images/px4/calibration/arrows.png + + + + + + + Magnetometer + + + + :/files/images/px4/calibration/arrows.png:/files/images/px4/calibration/arrows.png + + + + + + + Accelerometer + + + + :/files/images/px4/calibration/arrows.png:/files/images/px4/calibration/arrows.png + + + + + + + Diff. pressure + + + + :/files/images/px4/calibration/arrows.png:/files/images/px4/calibration/arrows.png + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + 24 + + + + + + + Autopilot Orientation + + + + + + + 0 + 250 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Magnetometer Orientation + + + + + + + 150 + 120 + + + + + + + + + + + + + + + + + + + + diff --git a/src/ui/uas/QGCMessageView.cc b/src/ui/uas/QGCMessageView.cc index 67a28216f377c1ef70c5d5a6cc72d50dfe24e150..5c583e0e2f53d3e1096481a8af136cb8b39ca16d 100644 --- a/src/ui/uas/QGCMessageView.cc +++ b/src/ui/uas/QGCMessageView.cc @@ -1,11 +1,15 @@ #include "QGCMessageView.h" -#include "ui_QGCMessageView.h" -#include "UASManager.h" -#include "QGCUnconnectedInfoWidget.h" #include #include + +#include "GAudioOutput.h" +#include "QGCUnconnectedInfoWidget.h" +#include "UASManager.h" +#include "ui_QGCMessageView.h" + + QGCMessageView::QGCMessageView(QWidget *parent) : QWidget(parent), activeUAS(NULL), @@ -22,6 +26,7 @@ QGCMessageView::QGCMessageView(QWidget *parent) : ui->horizontalLayout->addWidget(connectWidget); ui->plainTextEdit->hide(); + setActiveUAS(UASManager::instance()->getActiveUAS()); connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*))); } @@ -52,7 +57,7 @@ void QGCMessageView::setActiveUAS(UASInterface* uas) activeUAS = uas; } -void QGCMessageView::handleTextMessage(int uasid, int componentid, int severity, QString text) +void QGCMessageView::handleTextMessage(int uasid, int compId, int severity, QString text) { // XXX color messages according to severity @@ -63,7 +68,17 @@ void QGCMessageView::handleTextMessage(int uasid, int componentid, int severity, QScrollBar *scroller = msgWidget->verticalScrollBar(); UASInterface *uas = UASManager::instance()->getUASForId(uasid); - msgWidget->appendHtml(QString("[%2:%3] %4\n").arg(uas->getColor().name()).arg(uas->getUASName()).arg(componentid).arg(text)); + QString uasName(uas->getUASName()); + QString colorName(uas->getColor().name()); + //change styling based on severity + if (160 == severity ) { //TODO where is the constant for "critical" severity? + GAudioOutput::instance()->say(text.toLower()); + msgWidget->appendHtml(QString("

[%1:%2] %3

").arg(uasName).arg(compId).arg(text)); + } + else { + msgWidget->appendHtml(QString("

[%2:%3] %4

").arg(colorName).arg(uasName).arg(compId).arg(text)); + } + // Ensure text area scrolls correctly scroller->setValue(scroller->maximum()); msgWidget->setUpdatesEnabled(true); @@ -72,7 +87,9 @@ void QGCMessageView::handleTextMessage(int uasid, int componentid, int severity, void QGCMessageView::contextMenuEvent(QContextMenuEvent* event) { - QMenu menu(this); - menu.addAction(clearAction); - menu.exec(event->globalPos()); + if(activeUAS) { + QMenu menu(this); + menu.addAction(clearAction); + menu.exec(event->globalPos()); + } } diff --git a/src/ui/uas/UASControlWidget.cc b/src/ui/uas/UASControlWidget.cc index b7d8cf798144797df42414bcb927d3a2e4a02dc9..91c2d0605c8b404106611b31365ed6e4c0741cfe 100644 --- a/src/ui/uas/UASControlWidget.cc +++ b/src/ui/uas/UASControlWidget.cc @@ -33,7 +33,6 @@ This file is part of the PIXHAWK project #include #include #include -#include #include #include @@ -42,71 +41,121 @@ This file is part of the PIXHAWK project #include #include "QGC.h" +static struct full_mode_s modes_list_common[] = { + { MAV_MODE_FLAG_MANUAL_INPUT_ENABLED, + 0 }, + { (MAV_MODE_FLAG_MANUAL_INPUT_ENABLED | MAV_MODE_FLAG_STABILIZE_ENABLED), + 0 }, + { (MAV_MODE_FLAG_MANUAL_INPUT_ENABLED | MAV_MODE_FLAG_STABILIZE_ENABLED | MAV_MODE_FLAG_GUIDED_ENABLED), + 0 }, + { (MAV_MODE_FLAG_AUTO_ENABLED | MAV_MODE_FLAG_STABILIZE_ENABLED | MAV_MODE_FLAG_GUIDED_ENABLED), + 0 }, +}; + +static struct full_mode_s modes_list_px4[4]; + UASControlWidget::UASControlWidget(QWidget *parent) : QWidget(parent), - uas(0), - uasMode(0), - engineOn(false) + uasID(-1), + modesList(NULL), + modesNum(0), + modeIdx(0), + armed(false) { ui.setupUi(this); + this->setUAS(UASManager::instance()->getActiveUAS()); + connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setUAS(UASInterface*))); - ui.modeComboBox->clear(); - int modes[] = { - MAV_MODE_PREFLIGHT, - MAV_MODE_FLAG_MANUAL_INPUT_ENABLED, - MAV_MODE_FLAG_STABILIZE_ENABLED | MAV_MODE_FLAG_MANUAL_INPUT_ENABLED, - MAV_MODE_FLAG_STABILIZE_ENABLED | MAV_MODE_FLAG_AUTO_ENABLED, - MAV_MODE_FLAG_MANUAL_INPUT_ENABLED | MAV_MODE_FLAG_TEST_ENABLED, - }; - for (int i = 0; i < sizeof(modes) / sizeof(int); i++) { - int mode = modes[i]; - ui.modeComboBox->insertItem(i, UAS::getShortModeTextFor(mode).remove(0, 2), mode); - } connect(ui.modeComboBox, SIGNAL(activated(int)), this, SLOT(setMode(int))); connect(ui.setModeButton, SIGNAL(clicked()), this, SLOT(transmitMode())); - uasMode = ui.modeComboBox->itemData(ui.modeComboBox->currentIndex()).toInt(); + ui.gridLayout->setAlignment(Qt::AlignTop); +} + +void UASControlWidget::updateModesList() +{ + union px4_custom_mode px4_cm; + px4_cm.data = 0; + modes_list_px4[0].baseMode = MAV_MODE_FLAG_CUSTOM_MODE_ENABLED | MAV_MODE_FLAG_MANUAL_INPUT_ENABLED; + px4_cm.main_mode = PX4_CUSTOM_MAIN_MODE_MANUAL; + modes_list_px4[0].customMode = px4_cm.data; + modes_list_px4[1].baseMode = MAV_MODE_FLAG_CUSTOM_MODE_ENABLED | MAV_MODE_FLAG_MANUAL_INPUT_ENABLED | MAV_MODE_FLAG_STABILIZE_ENABLED; + px4_cm.main_mode = PX4_CUSTOM_MAIN_MODE_SEATBELT; + modes_list_px4[1].customMode = px4_cm.data; + modes_list_px4[2].baseMode = MAV_MODE_FLAG_CUSTOM_MODE_ENABLED | MAV_MODE_FLAG_MANUAL_INPUT_ENABLED | MAV_MODE_FLAG_STABILIZE_ENABLED | MAV_MODE_FLAG_GUIDED_ENABLED; + px4_cm.main_mode = PX4_CUSTOM_MAIN_MODE_EASY; + modes_list_px4[2].customMode = px4_cm.data; + modes_list_px4[3].baseMode = MAV_MODE_FLAG_CUSTOM_MODE_ENABLED | MAV_MODE_FLAG_AUTO_ENABLED | MAV_MODE_FLAG_STABILIZE_ENABLED | MAV_MODE_FLAG_GUIDED_ENABLED; + px4_cm.main_mode = PX4_CUSTOM_MAIN_MODE_AUTO; + modes_list_px4[3].customMode = px4_cm.data; + + // Detect autopilot type + int autopilot = 0; + if (this->uasID >= 0) { + UASInterface *uas = UASManager::instance()->getUASForId(this->uasID); + if (uas) { + autopilot = UASManager::instance()->getUASForId(this->uasID)->getAutopilotType(); + } + } - ui.modeComboBox->setCurrentIndex(0); + // Use corresponding modes list + if (autopilot == MAV_AUTOPILOT_PX4) { + modesList = modes_list_px4; + modesNum = sizeof(modes_list_px4) / sizeof(struct full_mode_s); + } else { + modesList = modes_list_common; + modesNum = sizeof(modes_list_common) / sizeof(struct full_mode_s); + } - ui.gridLayout->setAlignment(Qt::AlignTop); + // Set combobox items + ui.modeComboBox->clear(); + for (int i = 0; i < modesNum; i++) { + struct full_mode_s mode = modesList[i]; + ui.modeComboBox->insertItem(i, UAS::getShortModeTextFor(mode.baseMode, mode.customMode, autopilot).remove(0, 2), i); + } + // Select first mode in list + modeIdx = 0; + ui.modeComboBox->setCurrentIndex(modeIdx); + ui.modeComboBox->update(); } void UASControlWidget::setUAS(UASInterface* uas) { - if (this->uas) - { - UASInterface* oldUAS = UASManager::instance()->getUASForId(this->uas); - disconnect(ui.controlButton, SIGNAL(clicked()), oldUAS, SLOT(armSystem())); - disconnect(ui.liftoffButton, SIGNAL(clicked()), oldUAS, SLOT(launch())); - disconnect(ui.landButton, SIGNAL(clicked()), oldUAS, SLOT(home())); - disconnect(ui.shutdownButton, SIGNAL(clicked()), oldUAS, SLOT(shutdown())); - //connect(ui.setHomeButton, SIGNAL(clicked()), uas, SLOT(setLocalOriginAtCurrentGPSPosition())); - disconnect(uas, SIGNAL(modeChanged(int,QString,QString)), this, SLOT(updateMode(int,QString,QString))); - disconnect(uas, SIGNAL(statusChanged(int)), this, SLOT(updateState(int))); + if (this->uasID > 0) { + UASInterface* oldUAS = UASManager::instance()->getUASForId(this->uasID); + if (oldUAS) { + disconnect(ui.controlButton, SIGNAL(clicked()), oldUAS, SLOT(armSystem())); + disconnect(ui.liftoffButton, SIGNAL(clicked()), oldUAS, SLOT(launch())); + disconnect(ui.landButton, SIGNAL(clicked()), oldUAS, SLOT(home())); + disconnect(ui.shutdownButton, SIGNAL(clicked()), oldUAS, SLOT(shutdown())); + //connect(ui.setHomeButton, SIGNAL(clicked()), uas, SLOT(setLocalOriginAtCurrentGPSPosition())); + disconnect(oldUAS, SIGNAL(modeChanged(int,QString,QString)), this, SLOT(updateMode(int, QString, QString))); + disconnect(oldUAS, SIGNAL(statusChanged(int)), this, SLOT(updateState(int))); + } } // Connect user interface controls - if (uas) - { - connect(ui.controlButton, SIGNAL(clicked()), this, SLOT(cycleContextButton())); - connect(ui.liftoffButton, SIGNAL(clicked()), uas, SLOT(launch())); - connect(ui.landButton, SIGNAL(clicked()), uas, SLOT(home())); - connect(ui.shutdownButton, SIGNAL(clicked()), uas, SLOT(shutdown())); - //connect(ui.setHomeButton, SIGNAL(clicked()), uas, SLOT(setLocalOriginAtCurrentGPSPosition())); - connect(uas, SIGNAL(modeChanged(int,QString,QString)), this, SLOT(updateMode(int,QString,QString))); - connect(uas, SIGNAL(statusChanged(int)), this, SLOT(updateState(int))); - - ui.controlStatusLabel->setText(tr("Connected to ") + uas->getUASName()); - - this->uas = uas->getUASID(); - setBackgroundColor(uas->getColor()); - } - else - { - this->uas = -1; - } + if (uas) { + connect(ui.controlButton, SIGNAL(clicked()), this, SLOT(cycleContextButton())); + connect(ui.liftoffButton, SIGNAL(clicked()), uas, SLOT(launch())); + connect(ui.landButton, SIGNAL(clicked()), uas, SLOT(home())); + connect(ui.shutdownButton, SIGNAL(clicked()), uas, SLOT(shutdown())); + //connect(ui.setHomeButton, SIGNAL(clicked()), uas, SLOT(setLocalOriginAtCurrentGPSPosition())); + connect(uas, SIGNAL(modeChanged(int, QString, QString)), this, SLOT(updateMode(int, QString, QString))); + connect(uas, SIGNAL(statusChanged(int)), this, SLOT(updateState(int))); + + ui.controlStatusLabel->setText(tr("Connected to ") + uas->getUASName()); + + this->uasID = uas->getUASID(); + setBackgroundColor(uas->getColor()); + + this->updateModesList(); + this->updateArmText(); + + } else { + this->uasID = -1; + } } UASControlWidget::~UASControlWidget() @@ -114,15 +163,11 @@ UASControlWidget::~UASControlWidget() } -void UASControlWidget::updateStatemachine() +void UASControlWidget::updateArmText() { - - if (engineOn) - { + if (armed) { ui.controlButton->setText(tr("DISARM SYSTEM")); - } - else - { + } else { ui.controlButton->setText(tr("ARM SYSTEM")); } } @@ -138,7 +183,7 @@ void UASControlWidget::setBackgroundColor(QColor color) QString colorstyle; QString borderColor = "#4A4A4F"; borderColor = "#FA4A4F"; - uasColor = uasColor.darker(900); + uasColor = uasColor.darker(400); colorstyle = colorstyle.sprintf("QLabel { border-radius: 3px; padding: 0px; margin: 0px; background-color: #%02X%02X%02X; border: 0px solid %s; }", uasColor.red(), uasColor.green(), uasColor.blue(), borderColor.toStdString().c_str()); setStyleSheet(colorstyle); @@ -149,7 +194,7 @@ void UASControlWidget::setBackgroundColor(QColor color) } -void UASControlWidget::updateMode(int uas,QString mode,QString description) +void UASControlWidget::updateMode(int uas, QString mode, QString description) { Q_UNUSED(uas); Q_UNUSED(mode); @@ -158,17 +203,15 @@ void UASControlWidget::updateMode(int uas,QString mode,QString description) void UASControlWidget::updateState(int state) { - switch (state) - { + switch (state) { case (int)MAV_STATE_ACTIVE: - engineOn = true; - ui.controlButton->setText(tr("DISARM SYSTEM")); + armed = true; break; case (int)MAV_STATE_STANDBY: - engineOn = false; - ui.controlButton->setText(tr("ARM SYSTEM")); + armed = false; break; } + this->updateArmText(); } /** @@ -177,7 +220,7 @@ void UASControlWidget::updateState(int state) void UASControlWidget::setMode(int mode) { // Adapt context button mode - uasMode = ui.modeComboBox->itemData(mode).toInt(); + modeIdx = mode; ui.modeComboBox->blockSignals(true); ui.modeComboBox->setCurrentIndex(mode); ui.modeComboBox->blockSignals(false); @@ -187,43 +230,36 @@ void UASControlWidget::setMode(int mode) void UASControlWidget::transmitMode() { - UASInterface* mav = UASManager::instance()->getUASForId(this->uas); - if (mav) - { - // include armed state - if (engineOn) - uasMode |= MAV_MODE_FLAG_SAFETY_ARMED; - else - uasMode &= ~MAV_MODE_FLAG_SAFETY_ARMED; - - mav->setMode(uasMode); - QString mode = ui.modeComboBox->currentText(); - - ui.lastActionLabel->setText(QString("Sent new mode %1 to %2").arg(mode).arg(mav->getUASName())); + UASInterface* uas = UASManager::instance()->getUASForId(this->uasID); + if (uas) { + if (modeIdx >= 0 && modeIdx < modesNum) { + struct full_mode_s mode = modesList[modeIdx]; + // include armed state + if (armed) { + mode.baseMode |= MAV_MODE_FLAG_SAFETY_ARMED; + } else { + mode.baseMode &= ~MAV_MODE_FLAG_SAFETY_ARMED; + } + + uas->setMode(mode.baseMode, mode.customMode); + QString modeText = ui.modeComboBox->currentText(); + + ui.lastActionLabel->setText(QString("Sent new mode %1 to %2").arg(modeText).arg(uas->getUASName())); + } } } void UASControlWidget::cycleContextButton() { - UAS* mav = dynamic_cast(UASManager::instance()->getUASForId(this->uas)); - if (mav) - { - - if (!engineOn) - { - mav->armSystem(); - ui.lastActionLabel->setText(QString("Enabled motors on %1").arg(mav->getUASName())); + UAS* uas = dynamic_cast(UASManager::instance()->getUASForId(this->uasID)); + if (uas) { + if (!armed) { + uas->armSystem(); + ui.lastActionLabel->setText(QString("Arm %1").arg(uas->getUASName())); } else { - mav->disarmSystem(); - ui.lastActionLabel->setText(QString("Disabled motors on %1").arg(mav->getUASName())); + uas->disarmSystem(); + ui.lastActionLabel->setText(QString("Disarm %1").arg(uas->getUASName())); } - // Update state now and in several intervals when MAV might have changed state - updateStatemachine(); - - QTimer::singleShot(50, this, SLOT(updateStatemachine())); - QTimer::singleShot(200, this, SLOT(updateStatemachine())); - } - } diff --git a/src/ui/uas/UASControlWidget.h b/src/ui/uas/UASControlWidget.h index 4ec60f6930fefe0bbfc90369bdb708e92acec918..9601bf506dc6cabb74ba81b778497f53a0c79371 100644 --- a/src/ui/uas/UASControlWidget.h +++ b/src/ui/uas/UASControlWidget.h @@ -38,6 +38,12 @@ This file is part of the QGROUNDCONTROL project #include #include #include +#include + +struct full_mode_s { + uint8_t baseMode; + uint32_t customMode; +}; /** * @brief Widget controlling one MAV @@ -51,8 +57,10 @@ public: ~UASControlWidget(); public slots: + /** @brief Update modes list for selected system */ + void updateModesList(); /** @brief Set the system this widget controls */ - void setUAS(UASInterface* uas); + void setUAS(UASInterface* uasID); /** @brief Trigger next context action */ void cycleContextButton(); /** @brief Set the operation mode of the MAV */ @@ -60,11 +68,11 @@ public slots: /** @brief Transmit the operation mode */ void transmitMode(); /** @brief Update the mode */ - void updateMode(int uas,QString mode,QString description); + void updateMode(int uasID, QString mode, QString description); /** @brief Update state */ void updateState(int state); /** @brief Update internal state machine */ - void updateStatemachine(); + void updateArmText(); signals: void changedMode(int); @@ -75,9 +83,11 @@ protected slots: void setBackgroundColor(QColor color); protected: - int uas; ///< Reference to the current uas - unsigned int uasMode; ///< Current uas mode - bool engineOn; ///< Engine state + int uasID; ///< Reference to the current uas + struct full_mode_s *modesList; ///< Modes list for the current UAS + int modesNum; ///< Number of modes in list for the current UAS + int modeIdx; ///< Current uas mode index + bool armed; ///< Engine state private: Ui::uasControl ui; diff --git a/src/ui/uas/UASListWidget.cc b/src/ui/uas/UASListWidget.cc index d1cdde02eb62aa7582dc7ad5b1e1c7a74f02d375..bc92aa44e029a6c5ec6b6b70e502056addb992c6 100644 --- a/src/ui/uas/UASListWidget.cc +++ b/src/ui/uas/UASListWidget.cc @@ -64,6 +64,8 @@ UASListWidget::UASListWidget(QWidget *parent) : QWidget(parent), this->setVisible(false); + connect(LinkManager::instance(), SIGNAL(linkRemoved(LinkInterface*)), this, SLOT(removeLink(LinkInterface*))); + // Listen for when UASes are added or removed. This does not manage the UASView // widgets that are displayed within this widget. connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), @@ -96,12 +98,33 @@ void UASListWidget::changeEvent(QEvent *e) } } +// XXX This is just to prevent +// upfront crashes, will probably need further inspection +void UASListWidget::removeLink(LinkInterface* link) +{ + QGroupBox* box = linkToBoxMapping.value(link, NULL); + + if (box) { + // Just stop updating the status for now - we should + // remove the UAS probably + linkToBoxMapping.remove(link); + } +} + void UASListWidget::updateStatus() { QMapIterator i(linkToBoxMapping); while (i.hasNext()) { i.next(); LinkInterface* link = i.key(); + + // Paranoid sanity check + if (!LinkManager::instance()->getLinks().contains(link)) + continue; + + if (!link) + continue; + ProtocolInterface* p = LinkManager::instance()->getProtocolForLink(link); // Build the tooltip out of the protocol parsing data: received, dropped, and parsing errors. @@ -149,7 +172,7 @@ void UASListWidget::addUAS(UASInterface* uas) QList* x = uas->getLinks(); if (x->size()) { - LinkInterface* li = x->at(0); + LinkInterface* li = x->first(); // Find an existing QGroupBox for this LinkInterface or create a // new one. diff --git a/src/ui/uas/UASListWidget.h b/src/ui/uas/UASListWidget.h index b14e1e97de6fdb58dbe1585726b3b0644b182c27..494d16fdb892c7db395ce1c49297b009aab8794e 100644 --- a/src/ui/uas/UASListWidget.h +++ b/src/ui/uas/UASListWidget.h @@ -53,6 +53,7 @@ public slots: void addUAS(UASInterface* uas); void activeUAS(UASInterface* uas); void removeUAS(UASInterface* uas); + void removeLink(LinkInterface* link); protected: // Keep a mapping from UASes to their GroupBox. Useful for determining when groupboxes are empty. diff --git a/src/ui/uas/UASQuickView.cc b/src/ui/uas/UASQuickView.cc index 13a198f96a0452f577d40d74db31556549ba821b..4eeeab5f4cc1563742aa8899962927fa0a531df7 100644 --- a/src/ui/uas/UASQuickView.cc +++ b/src/ui/uas/UASQuickView.cc @@ -4,13 +4,17 @@ #include "UASQuickViewItemSelect.h" #include "UASQuickViewTextItem.h" #include - -UASQuickView::UASQuickView(QWidget *parent) : - QWidget(parent), - m_ui(new Ui::UASQuickView) +#include +UASQuickView::UASQuickView(QWidget *parent) : QWidget(parent) { - m_ui->setupUi(this); quickViewSelectDialog=0; + m_columnCount=2; + m_currentColumn=0; + ui.setupUi(this); + + ui.horizontalLayout->setMargin(0); + m_verticalLayoutList.append(new QVBoxLayout()); + ui.horizontalLayout->addItem(m_verticalLayoutList[0]); connect(UASManager::instance(),SIGNAL(activeUASSet(UASInterface*)),this,SLOT(setActiveUAS(UASInterface*))); connect(UASManager::instance(),SIGNAL(UASCreated(UASInterface*)),this,SLOT(addUAS(UASInterface*))); @@ -21,23 +25,50 @@ UASQuickView::UASQuickView(QWidget *parent) : this->setContextMenuPolicy(Qt::ActionsContextMenu); loadSettings(); + //If we don't have any predefined settings, set some defaults. if (uasPropertyValueMap.size() == 0) { valueEnabled("altitude"); valueEnabled("groundSpeed"); - valueEnabled("distToWaypoint"); + valueEnabled("distToWP"); valueEnabled("yaw"); valueEnabled("roll"); } - QAction *action = new QAction("Add Item",this); + QAction *action = new QAction("Add/Remove Items",this); action->setCheckable(false); connect(action,SIGNAL(triggered()),this,SLOT(actionTriggered())); this->addAction(action); + QAction *columnaction = new QAction("Set Column Count",this); + columnaction->setCheckable(false); + connect(columnaction,SIGNAL(triggered()),this,SLOT(columnActionTriggered())); + this->addAction(columnaction); + updateTimer = new QTimer(this); connect(updateTimer,SIGNAL(timeout()),this,SLOT(updateTimerTick())); + updateTimer->start(1000); + +} +UASQuickView::~UASQuickView() +{ + if (quickViewSelectDialog) + { + delete quickViewSelectDialog; + } +} +void UASQuickView::columnActionTriggered() +{ + bool ok = false; + int newcolumns = QInputDialog::getInt(this,"Columns","Enter number of columns",1,0,100,1,&ok); + if (!ok) + { + return; + } + m_columnCount = newcolumns; + sortItems(newcolumns); + saveSettings(); } void UASQuickView::actionTriggered() @@ -58,7 +89,6 @@ void UASQuickView::actionTriggered() } quickViewSelectDialog->show(); } - void UASQuickView::saveSettings() { QSettings settings; @@ -71,12 +101,13 @@ void UASQuickView::saveSettings() settings.setValue("type","text"); } settings.endArray(); + settings.setValue("UAS_QUICK_VIEW_COLUMNS",m_columnCount); settings.sync(); } - void UASQuickView::loadSettings() { QSettings settings; + m_columnCount = settings.value("UAS_QUICK_VIEW_COLUMNS",1).toInt(); int size = settings.beginReadArray("UAS_QUICK_VIEW_ITEMS"); for (int i=0;isetTitle(value); - m_ui->verticalLayout->addWidget(item); + //ui.verticalLayout->addWidget(item); + //m_currentColumn + m_verticalLayoutList[m_currentColumn]->addWidget(item); + m_PropertyToLayoutIndexMap[value] = m_currentColumn; + m_currentColumn++; + if (m_currentColumn >= m_columnCount-1) + { + m_currentColumn = 0; + } uasPropertyToLabelMap[value] = item; uasEnabledPropertyList.append(value); + if (!uasPropertyValueMap.contains(value)) { uasPropertyValueMap[value] = 0; } saveSettings(); + item->show(); + sortItems(m_columnCount); } - -void UASQuickView::valueDisabled(QString value) +void UASQuickView::sortItems(int columncount) { - if (uasPropertyToLabelMap.contains(value)) + QList itemlist; + for (QMap::const_iterator i = uasPropertyToLabelMap.constBegin();i!=uasPropertyToLabelMap.constEnd();i++) { - UASQuickViewItem *item = uasPropertyToLabelMap[value]; - uasPropertyToLabelMap.remove(value); - item->hide(); - m_ui->verticalLayout->removeWidget(item); - item->deleteLater(); - uasEnabledPropertyList.removeOne(value); - saveSettings(); + m_verticalLayoutList[m_PropertyToLayoutIndexMap[i.key()]]->removeWidget(i.value()); + m_PropertyToLayoutIndexMap.remove(i.key()); + itemlist.append(i.value()); } -} - -void UASQuickView::selectDialogClosed() -{ - quickViewSelectDialog = 0; -} - -void UASQuickView::updateTimerTick() -{ - //uasPropertyValueMap - for (QMap::const_iterator i = uasPropertyToLabelMap.constBegin(); i != uasPropertyToLabelMap.constEnd();i++) + //Item list has all the widgets availble, now re-add them to the layouts. + for (int i=0;isetValue(uasPropertyValueMap[i.key()]); - } + ui.horizontalLayout->removeItem(m_verticalLayoutList[i]); + m_verticalLayoutList[i]->deleteLater(); //removeItem de-parents the item. } -} + m_verticalLayoutList.clear(); -void UASQuickView::addUAS(UASInterface* uas) -{ - if (uas) + //Create a vertical layout for every intended column + for (int i=0;iuas) - { - setActiveUAS(uas); - } + QVBoxLayout *layout = new QVBoxLayout(); + ui.horizontalLayout->addItem(layout); + m_verticalLayoutList.append(layout); + layout->setMargin(0); } -} -void UASQuickView::setActiveUAS(UASInterface* uas) -{ - // Clean up from the old UAS - if (this->uas) + //Cycle through all items and add them to the layout + int currcol = 0; + for (int i=0;iaddWidget(itemlist[i]); + currcol++; + if (currcol >= columncount) { - i->deleteLater(); - } - uasPropertyToLabelMap.clear(); - - updateTimer->stop(); - foreach (QAction* i, this->actions()) - { - i->deleteLater(); + currcol = 0; } } - - // Update the UAS to point to the new one. - this->uas = uas; - - if (this->uas) - { - connect(uas,SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)),this,SLOT(valueChanged(int,QString,QString,QVariant,quint64))); - updateTimer->start(1000); - } + m_currentColumn = currcol; + QApplication::processEvents(); + recalculateItemTextSizing(); } - -void UASQuickView::addSource(MAVLinkDecoder *decoder) +void UASQuickView::resizeEvent(QResizeEvent *evt) { - connect(decoder,SIGNAL(valueChanged(int,QString,QString,double,quint64)),this,SLOT(valueChanged(int,QString,QString,double,quint64))); - connect(decoder,SIGNAL(valueChanged(int,QString,QString,qint8,quint64)),this,SLOT(valueChanged(int,QString,QString,qint8,quint64))); - connect(decoder,SIGNAL(valueChanged(int,QString,QString,qint16,quint64)),this,SLOT(valueChanged(int,QString,QString,qint16,quint64))); - connect(decoder,SIGNAL(valueChanged(int,QString,QString,qint32,quint64)),this,SLOT(valueChanged(int,QString,QString,qint32,quint64))); - connect(decoder,SIGNAL(valueChanged(int,QString,QString,qint64,quint64)),this,SLOT(valueChanged(int,QString,QString,qint64,quint64))); - connect(decoder,SIGNAL(valueChanged(int,QString,QString,quint8,quint64)),this,SLOT(valueChanged(int,QString,QString,quint8,quint64))); - connect(decoder,SIGNAL(valueChanged(int,QString,QString,quint16,quint64)),this,SLOT(valueChanged(int,QString,QString,quint16,quint64))); - connect(decoder,SIGNAL(valueChanged(int,QString,QString,quint32,quint64)),this,SLOT(valueChanged(int,QString,QString,quint32,quint64))); - connect(decoder,SIGNAL(valueChanged(int,QString,QString,quint64,quint64)),this,SLOT(valueChanged(int,QString,QString,quint64,quint64))); + recalculateItemTextSizing(); } - -void UASQuickView::valueChanged(const int uasId, const QString& name, const QString& unit, const quint8 value, const quint64 msec) +void UASQuickView::recalculateItemTextSizing() { - Q_UNUSED(uasId); - Q_UNUSED(unit); - Q_UNUSED(msec); - if (!uasPropertyValueMap.contains(name)) + int minpixelsize = 65535; + for (QMap::const_iterator i = uasPropertyToLabelMap.constBegin();i!=uasPropertyToLabelMap.constEnd();i++) { - if (quickViewSelectDialog) + int tempmin = i.value()->minValuePixelSize(); + if (tempmin < minpixelsize) { - quickViewSelectDialog->addItem(name); + minpixelsize = tempmin; } } - uasPropertyValueMap[name] = value; -} - -void UASQuickView::valueChanged(const int uasId, const QString& name, const QString& unit, const qint8 value, const quint64 msec) -{ - Q_UNUSED(uasId); - Q_UNUSED(unit); - Q_UNUSED(msec); - if (!uasPropertyValueMap.contains(name)) + for (QMap::const_iterator i = uasPropertyToLabelMap.constBegin();i!=uasPropertyToLabelMap.constEnd();i++) { - if (quickViewSelectDialog) - { - quickViewSelectDialog->addItem(name); - } + i.value()->setValuePixelSize(minpixelsize); } - uasPropertyValueMap[name] = value; } -void UASQuickView::valueChanged(const int uasId, const QString& name, const QString& unit, const quint16 value, const quint64 msec) +void UASQuickView::valueDisabled(QString value) { - Q_UNUSED(uasId); - Q_UNUSED(unit); - Q_UNUSED(msec); - if (!uasPropertyValueMap.contains(name)) + if (uasPropertyToLabelMap.contains(value)) { - if (quickViewSelectDialog) - { - quickViewSelectDialog->addItem(name); - } + UASQuickViewItem *item = uasPropertyToLabelMap[value]; + uasPropertyToLabelMap.remove(value); + item->hide(); + //ui.verticalLayout->removeWidget(item); + //layout->removeWidget(item); + m_verticalLayoutList[m_PropertyToLayoutIndexMap[value]]->removeWidget(item); + sortItems(m_columnCount); + item->deleteLater(); + uasEnabledPropertyList.removeOne(value); + saveSettings(); } - uasPropertyValueMap[name] = value; } -void UASQuickView::valueChanged(const int uasId, const QString& name, const QString& unit, const qint16 value, const quint64 msec) +void UASQuickView::selectDialogClosed() { - Q_UNUSED(uasId); - Q_UNUSED(unit); - Q_UNUSED(msec); - if (!uasPropertyValueMap.contains(name)) - { - if (quickViewSelectDialog) - { - quickViewSelectDialog->addItem(name); - } - } - uasPropertyValueMap[name] = value; + quickViewSelectDialog = 0; } -void UASQuickView::valueChanged(const int uasId, const QString& name, const QString& unit, const quint32 value, const quint64 msec) +void UASQuickView::updateTimerTick() { - Q_UNUSED(uasId); - Q_UNUSED(unit); - Q_UNUSED(msec); - if (!uasPropertyValueMap.contains(name)) + //uasPropertyValueMap + for (QMap::const_iterator i = uasPropertyToLabelMap.constBegin(); i != uasPropertyToLabelMap.constEnd();i++) { - if (quickViewSelectDialog) + if (uasPropertyValueMap.contains(i.key())) { - quickViewSelectDialog->addItem(name); + i.value()->setValue(uasPropertyValueMap[i.key()]); } - - // And periodically update the view. - updateTimer->start(1000); } - uasPropertyValueMap[name] = value; } -void UASQuickView::valueChanged(const int uasId, const QString& name, const QString& unit, const qint32 value, const quint64 msec) +void UASQuickView::addUAS(UASInterface* uas) { - Q_UNUSED(uasId); - Q_UNUSED(unit); - Q_UNUSED(msec); - if (!uasPropertyValueMap.contains(name)) + if (uas) { - if (quickViewSelectDialog) + if (!this->uas) { - quickViewSelectDialog->addItem(name); + setActiveUAS(uas); } } - uasPropertyValueMap[name] = value; } -void UASQuickView::valueChanged(const int uasId, const QString& name, const QString& unit, const quint64 value, const quint64 msec) +void UASQuickView::setActiveUAS(UASInterface* uas) { - Q_UNUSED(uasId); - Q_UNUSED(unit); - Q_UNUSED(msec); - if (!uasPropertyValueMap.contains(name)) + if (!uas) { - if (quickViewSelectDialog) - { - quickViewSelectDialog->addItem(name); - } + return; } - uasPropertyValueMap[name] = value; + this->uas = uas; + connect(uas,SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)),this,SLOT(valueChanged(int,QString,QString,QVariant,quint64))); + //connect(uas,SIGNAL()) } - -void UASQuickView::valueChanged(const int uasId, const QString& name, const QString& unit, const qint64 value, const quint64 msec) +void UASQuickView::addSource(MAVLinkDecoder *decoder) { - Q_UNUSED(uasId); - Q_UNUSED(unit); - Q_UNUSED(msec); - if (!uasPropertyValueMap.contains(name)) - { - if (quickViewSelectDialog) - { - quickViewSelectDialog->addItem(name); - } - - // And periodically update the view. - updateTimer->start(1000); - } - uasPropertyValueMap[name] = value; + connect(decoder,SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)),this,SLOT(valueChanged(int,QString,QString,QVariant,quint64))); } -void UASQuickView::valueChanged(const int uasId, const QString& name, const QString& unit, const double value, const quint64 msec) +void UASQuickView::valueChanged(const int uasId, const QString& name, const QString& unit, const QVariant &variant, const quint64 msec) { Q_UNUSED(uasId); Q_UNUSED(unit); - Q_UNUSED(msec); - if (!uasPropertyValueMap.contains(name)) - { - if (quickViewSelectDialog) - { - quickViewSelectDialog->addItem(name); - } - } - uasPropertyValueMap[name] = value; -} + bool ok; + double value = variant.toDouble(&ok); + if(!ok || variant.type() == QMetaType::QString || variant.type() == QMetaType::QByteArray) + return; -void UASQuickView::valueChanged(const int uasId, const QString& name, const QString& unit, const QVariant value,const quint64 msec) -{ - Q_UNUSED(uasId); - Q_UNUSED(unit); - Q_UNUSED(msec); if (!uasPropertyValueMap.contains(name)) { if (quickViewSelectDialog) @@ -342,7 +286,7 @@ void UASQuickView::valueChanged(const int uasId, const QString& name, const QStr quickViewSelectDialog->addItem(name); } } - uasPropertyValueMap[name] = value.toDouble(); + uasPropertyValueMap[name] = value; } void UASQuickView::actionTriggered(bool checked) @@ -354,22 +298,26 @@ void UASQuickView::actionTriggered(bool checked) } if (checked) { - UASQuickViewItem *item = new UASQuickViewTextItem(this); + valueEnabled(senderlabel->text()); + /*UASQuickViewItem *item = new UASQuickViewTextItem(this); item->setTitle(senderlabel->text()); - this->layout()->addWidget(item); - uasPropertyToLabelMap[senderlabel->text()] = item; + layout->addWidget(item); + //ui.verticalLayout->addWidget(item); + m_currentColumn++; + if (m_currentColumn >= m_verticalLayoutList.size()) + { + m_currentColumn = 0; + } + uasPropertyToLabelMap[senderlabel->text()] = item;*/ + + } else { - this->layout()->removeWidget(uasPropertyToLabelMap[senderlabel->text()]); + valueDisabled(senderlabel->text()); + /*layout->removeWidget(uasPropertyToLabelMap[senderlabel->text()]); uasPropertyToLabelMap[senderlabel->text()]->deleteLater(); - uasPropertyToLabelMap.remove(senderlabel->text()); + uasPropertyToLabelMap.remove(senderlabel->text());*/ } } - -void UASQuickView::valChanged(double val,QString type) -{ - Q_UNUSED(val); - Q_UNUSED(type); -} diff --git a/src/ui/uas/UASQuickView.h b/src/ui/uas/UASQuickView.h index 943fa8c66542f000b2d84d45a0782ce45e7622ae..1204f5952570b68615509c265d177138baf01518 100644 --- a/src/ui/uas/UASQuickView.h +++ b/src/ui/uas/UASQuickView.h @@ -15,12 +15,9 @@ class UASQuickView : public QWidget Q_OBJECT public: UASQuickView(QWidget *parent = 0); + ~UASQuickView(); void addSource(MAVLinkDecoder *decoder); private: - /** - * Adds a default set of actions to the widget's menu. - */ - void addDefaultActions(); UASInterface *uas; /** List of enabled properties */ @@ -34,7 +31,6 @@ private: /** Timer for updating the UI */ QTimer *updateTimer; - Ui::UASQuickView* m_ui; /** Selection dialog for selectin/deselecting gauge items */ UASQuickViewItemSelect *quickViewSelectDialog; @@ -44,30 +40,35 @@ private: /** Loads gauge layout from settings file */ void loadSettings(); + + void recalculateItemTextSizing(); + + /** Column Count */ + int m_columnCount; + + QList m_verticalLayoutList; + void sortItems(int columncount); + QList m_verticalLayoutItemCount; + int m_currentColumn; + QMap m_PropertyToLayoutIndexMap; + + //FlowLayout *layout; protected: + Ui::Form ui; + void resizeEvent(QResizeEvent *evt); signals: - + public slots: - void valueChanged(const int uasId, const QString& name, const QString& unit, const quint8 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const qint8 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const quint16 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const qint16 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const quint32 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const qint32 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const quint64 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const qint64 value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const double value, const quint64 msec); - void valueChanged(const int uasId, const QString& name, const QString& unit, const QVariant value, const quint64 msec); - + void valueChanged(const int uasid, const QString& name, const QString& unit, const QVariant& value,const quint64 msecs); void actionTriggered(bool checked); void actionTriggered(); void updateTimerTick(); void addUAS(UASInterface* uas); void setActiveUAS(UASInterface* uas); - void valChanged(double val,QString type); void selectDialogClosed(); void valueEnabled(QString value); void valueDisabled(QString value); + void columnActionTriggered(); }; #endif // UASQUICKVIEW_H diff --git a/src/ui/uas/UASQuickView.ui b/src/ui/uas/UASQuickView.ui index 50f17082a0fe822ebd6ee6f3bf453aab7ed4e273..f11c734b7cc8ae1a57fdf65b9497f9eb55f5d8c0 100644 --- a/src/ui/uas/UASQuickView.ui +++ b/src/ui/uas/UASQuickView.ui @@ -1,7 +1,7 @@ - UASQuickView - + Form + 0 @@ -10,12 +10,6 @@ 300 - - - 0 - 0 - - 100 @@ -26,12 +20,9 @@ Form - - QLayout::SetMinimumSize - - - 0 - + + + diff --git a/src/ui/uas/UASQuickViewItem.h b/src/ui/uas/UASQuickViewItem.h index 8bba60ba3c8633264be811679d82e89849b6cdf2..dea59a980fc3ecafb10907db6c74c0f3a1a20e90 100644 --- a/src/ui/uas/UASQuickViewItem.h +++ b/src/ui/uas/UASQuickViewItem.h @@ -9,6 +9,8 @@ public: explicit UASQuickViewItem(QWidget *parent = 0); virtual void setValue(double value)=0; virtual void setTitle(QString title)=0; + virtual int minValuePixelSize()=0; + virtual void setValuePixelSize(int size)=0; }; #endif // UASQUICKVIEWITEM_H diff --git a/src/ui/uas/UASQuickViewItemSelect.cc b/src/ui/uas/UASQuickViewItemSelect.cc index 537d1aafb2b7d8ad14be0858f0f475820807ad98..6536529cae513debfa7dc251e0e1489eff3c9fe1 100644 --- a/src/ui/uas/UASQuickViewItemSelect.cc +++ b/src/ui/uas/UASQuickViewItemSelect.cc @@ -6,24 +6,76 @@ UASQuickViewItemSelect::UASQuickViewItemSelect(QWidget *parent) : QWidget(parent ui.setupUi(this); currcol = 0; currrow = 0; + ui.gridLayout->setSpacing(5); + ui.gridLayout->setMargin(0); } void UASQuickViewItemSelect::addItem(QString item,bool enabled) { + QString category = "."; + QString name = item; + if (item.indexOf(":") != -1 && item.indexOf(".") != -1) + { + //Item has a subcateogry + category = item.mid(item.indexOf(":")+1,item.indexOf(".") - item.indexOf(":")-1); + name = item.mid(item.indexOf(".")+1); + } + int col = -1; + if (m_categoryToIndexMap.contains(category)) + { + col = m_categoryToIndexMap[category]; + } + else + { + m_categoryToIndexMap[category] = currcol++; + col = m_categoryToIndexMap[category]; + //New column. + QLabel *titlelabel = new QLabel(this); + titlelabel->setText(category); + titlelabel->show(); + ui.gridLayout->addWidget(titlelabel,0,col); + } QCheckBox *label = new QCheckBox(this); + m_checkboxToValueMap[label] = item; + m_checkBoxList.append(label); if (enabled) { label->setChecked(true); } connect(label,SIGNAL(clicked(bool)),this,SLOT(checkBoxClicked(bool))); - label->setText(item); + label->setText(name); label->show(); - ui.gridLayout->addWidget(label,currrow,currcol++); - if (currcol > 10) + //ui.gridLayout->addWidget(label,currrow,currcol++); + bool breakout = false; + int row = -1; + while (!breakout) + { + if (!ui.gridLayout->itemAtPosition(++row,col) || row > 100) + { + breakout = true; + } + } + //Row is the next invalid object, and col is the proper column. + ui.gridLayout->addWidget(label,row,col); +} +void UASQuickViewItemSelect::resizeEvent(QResizeEvent *event) +{ + /*for (int i=0;iremoveWidget(m_checkBoxList[i]); } + int row = 0; + int col = 0; + for (int i=0;iaddWidget(m_checkBoxList[i],row,col); + col++; + ui.gridLayout->widget()->width() > this->width(); + //need to reduce column number. + + }*/ + } + void UASQuickViewItemSelect::checkBoxClicked(bool checked) { QCheckBox *check = qobject_cast(sender()); @@ -31,13 +83,19 @@ void UASQuickViewItemSelect::checkBoxClicked(bool checked) { return; } + QString checkval = check->text(); + if (m_checkboxToValueMap.contains(check)) + { + checkval = m_checkboxToValueMap[check]; + } if (checked) { - emit valueEnabled(check->text()); + + emit valueEnabled(checkval); } else { - emit valueDisabled(check->text()); + emit valueDisabled(checkval); } } diff --git a/src/ui/uas/UASQuickViewItemSelect.h b/src/ui/uas/UASQuickViewItemSelect.h index 4be402c5e1530f342594a0671cfd6393a234d93f..efd769cb3ae5930674bf4937110bcfbe44fdd3eb 100644 --- a/src/ui/uas/UASQuickViewItemSelect.h +++ b/src/ui/uas/UASQuickViewItemSelect.h @@ -2,6 +2,7 @@ #define UASQUICKVIEWITEMSELECT_H #include +#include #include "ui_UASQuickViewItemSelect.h" class UASQuickViewItemSelect : public QWidget @@ -14,7 +15,12 @@ public: void addItem(QString item,bool enabled = false); int currrow; int currcol; +protected: + void resizeEvent(QResizeEvent *event); private: + QMap m_categoryToIndexMap; + QMap m_checkboxToValueMap; + QList m_checkBoxList; Ui::UASQuickViewItemSelect ui; private slots: void checkBoxClicked(bool checked); diff --git a/src/ui/uas/UASQuickViewItemSelect.ui b/src/ui/uas/UASQuickViewItemSelect.ui index 9a35660c0e1beab619198e580ca1ff78dc059e7b..5371e2248ddf8881a6a03948a8d2808e34279025 100644 --- a/src/ui/uas/UASQuickViewItemSelect.ui +++ b/src/ui/uas/UASQuickViewItemSelect.ui @@ -6,12 +6,12 @@ 0 0 - 571 - 474 + 947 + 248 - Form + Select Item @@ -24,14 +24,27 @@ 0 0 - 551 - 454 + 927 + 228 - + + + + + Qt::Vertical + + + + 20 + 40 + + + + diff --git a/src/ui/uas/UASQuickViewTextItem.cc b/src/ui/uas/UASQuickViewTextItem.cc index 520ad948e9e1719eac57dc34187c5b3f6288251f..5f8b5cc50564561fcd3d9534dfb2d2aa5c4580b5 100644 --- a/src/ui/uas/UASQuickViewTextItem.cc +++ b/src/ui/uas/UASQuickViewTextItem.cc @@ -1,5 +1,6 @@ #include "UASQuickViewTextItem.h" #include +#include UASQuickViewTextItem::UASQuickViewTextItem(QWidget *parent) : UASQuickViewItem(parent) { // Set a standard vertical layout. @@ -9,20 +10,33 @@ UASQuickViewTextItem::UASQuickViewTextItem(QWidget *parent) : UASQuickViewItem(p // Create the title label. Scale the font based on available size. titleLabel = new QLabel(this); - titleLabel->setAlignment(Qt::AlignHCenter); - titleLabel->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Minimum); - titleLabel->setObjectName(QString::fromUtf8("title")); - QFont titlefont = titleLabel->font(); - titlefont.setPixelSize(this->height() / 4.0); - titleLabel->setFont(titlefont); - layout->addWidget(titleLabel); - - // Create the value label. Scale the font based on available size. - valueLabel = new QLabel(this); - valueLabel->setAlignment(Qt::AlignHCenter); - valueLabel->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Minimum); - valueLabel->setObjectName(QString::fromUtf8("value")); - valueLabel->setText("0.00"); +// <<<<<<< HEAD + titleLabel->setAlignment(Qt::AlignHCenter); + titleLabel->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Minimum); + titleLabel->setObjectName(QString::fromUtf8("title")); + QFont titlefont = titleLabel->font(); + titlefont.setPixelSize(this->height() / 4.0); + titleLabel->setFont(titlefont); + layout->addWidget(titleLabel); + + // Create the value label. Scale the font based on available size. + valueLabel = new QLabel(this); + valueLabel->setAlignment(Qt::AlignHCenter); + valueLabel->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Minimum); + valueLabel->setObjectName(QString::fromUtf8("value")); + valueLabel->setText("0.00"); +// ======= +// titleLabel->setSizePolicy(QSizePolicy::Ignored,QSizePolicy::Ignored); +// titleLabel->setAlignment(Qt::AlignHCenter | Qt::AlignBottom); +// this->layout()->addWidget(titleLabel); +// valueLabel = new QLabel(this); +// valueLabel->setSizePolicy(QSizePolicy::Ignored,QSizePolicy::Ignored); +// valueLabel->setAlignment(Qt::AlignHCenter | Qt::AlignTop); +// valueLabel->setText("0.00"); +// this->layout()->addWidget(valueLabel); +// //spacerItem = new QSpacerItem(20,40,QSizePolicy::Minimum,QSizePolicy::Ignored); +// //layout->addSpacerItem(spacerItem); +// >>>>>>> 34eaf1fb422146f5df3b01fad4d756343b3127c9 QFont valuefont = valueLabel->font(); valuefont.setPixelSize(this->height() / 2.0); valueLabel->setFont(valuefont); @@ -34,19 +48,126 @@ UASQuickViewTextItem::UASQuickViewTextItem(QWidget *parent) : UASQuickViewItem(p } void UASQuickViewTextItem::setValue(double value) { - valueLabel->setText(QString::number(value,'f',4)); + if (value < 10 && value > -10) + { + valueLabel->setText(QString::number(value,'f',4)); + } + else if (value < 100 && value > -100) + { + valueLabel->setText(QString::number(value,'f',3)); + } + else if (value < 1000 && value > -1000) + { + valueLabel->setText(QString::number(value,'f',2)); + } + else if (value < 10000 && value > -10000) + { + valueLabel->setText(QString::number(value,'f',1)); + } + else if (value >= 100000 || value <= -100000) + { + valueLabel->setText(QString::number(value,'f',0)); + } } void UASQuickViewTextItem::setTitle(QString title) { - titleLabel->setText(title); + if (title.indexOf(".") != -1 && title.indexOf(":") != -1) + { + titleLabel->setText(title.mid(title.indexOf(".")+1)); + } + else + { + titleLabel->setText(title); + } +} +int UASQuickViewTextItem::minValuePixelSize() +{ + QFont valuefont = valueLabel->font(); + QFont titlefont = titleLabel->font(); + valuefont.setPixelSize(this->height()); + titlefont.setPixelSize(valuefont.pixelSize() / 2.0); + //spacerItem->setGeometry(QRect(0,0,20,this->height()/10.0)); + + QFontMetrics metrics(valuefont); + //valuefont.setPixelSize(this->height() / 2.0); + bool fit = false; + while (!fit) + { + + QFontMetrics valfm( valuefont ); + QRect valbound = valfm.boundingRect(0,0, valueLabel->width(), valueLabel->height(), Qt::TextWordWrap | Qt::AlignLeft, "12345678.00"/*valueLabel->text()*/); + //QFontMetrics titlefm( titlefont ); + //QRect titlebound = titlefm.boundingRect(0,0, titleLabel->width(), titleLabel->height(), Qt::TextWordWrap | Qt::AlignLeft, titleLabel->text()); + + if ((valbound.width() <= valueLabel->width() && valbound.height() <= valueLabel->height()))// && (titlebound.width() <= titleLabel->width() && titlebound.height() <= titleLabel->height())) + fit = true; + else + { + if (valuefont.pixelSize()-5 <= 0) + { + fit = true; + valuefont.setPixelSize(5); + } + else + { + valuefont.setPixelSize(valuefont.pixelSize() - 5); + } + //titlefont.setPixelSize(valuefont.pixelSize() / 2.0); + //qDebug() << "Point size:" << valuefont.pixelSize() << valueLabel->width() << valueLabel->height(); + } + } + return valuefont.pixelSize(); +} +void UASQuickViewTextItem::setValuePixelSize(int size) +{ + QFont valuefont = valueLabel->font(); + QFont titlefont = titleLabel->font(); + valuefont.setPixelSize(size); + titlefont.setPixelSize(valuefont.pixelSize() / 2.0); + valueLabel->setFont(valuefont); + titleLabel->setFont(titlefont); + update(); } + void UASQuickViewTextItem::resizeEvent(QResizeEvent *event) { + return; QFont valuefont = valueLabel->font(); QFont titlefont = titleLabel->font(); - valuefont.setPixelSize(this->height() / 2.0); - titlefont.setPixelSize(this->height() / 4.0); + valuefont.setPixelSize(this->height()); + titlefont.setPixelSize(valuefont.pixelSize() / 2.0); + //spacerItem->setGeometry(QRect(0,0,20,this->height()/10.0)); + + QFontMetrics metrics(valuefont); + //valuefont.setPixelSize(this->height() / 2.0); + bool fit = false; + while (!fit) + { + + QFontMetrics valfm( valuefont ); + QRect valbound = valfm.boundingRect(0,0, valueLabel->width(), valueLabel->height(), Qt::TextWordWrap | Qt::AlignLeft, valueLabel->text()); + //QFontMetrics titlefm( titlefont ); + //QRect titlebound = titlefm.boundingRect(0,0, titleLabel->width(), titleLabel->height(), Qt::TextWordWrap | Qt::AlignLeft, titleLabel->text()); + + if ((valbound.width() <= valueLabel->width() && valbound.height() <= valueLabel->height()))// && (titlebound.width() <= titleLabel->width() && titlebound.height() <= titleLabel->height())) + fit = true; + else + { + if (valuefont.pixelSize()-5 <= 0) + { + fit = true; + valuefont.setPixelSize(5); + } + else + { + valuefont.setPixelSize(valuefont.pixelSize() - 5); + } + //titlefont.setPixelSize(valuefont.pixelSize() / 2.0); + //qDebug() << "Point size:" << valuefont.pixelSize() << valueLabel->width() << valueLabel->height(); + } + } +titlefont.setPixelSize(valuefont.pixelSize() / 2.0); valueLabel->setFont(valuefont); titleLabel->setFont(titlefont); update(); diff --git a/src/ui/uas/UASQuickViewTextItem.h b/src/ui/uas/UASQuickViewTextItem.h index ba3eb8193c3363c2f382168f2f7f781c3ee3ce20..698c358f9120eecf2ba40eb37ae8cfa9740e5ec8 100644 --- a/src/ui/uas/UASQuickViewTextItem.h +++ b/src/ui/uas/UASQuickViewTextItem.h @@ -3,17 +3,21 @@ #include "UASQuickViewItem.h" #include +#include class UASQuickViewTextItem : public UASQuickViewItem { public: UASQuickViewTextItem(QWidget *parent=0); void setValue(double value); void setTitle(QString title); + int minValuePixelSize(); + void setValuePixelSize(int size); protected: void resizeEvent(QResizeEvent *event); private: QLabel *titleLabel; QLabel *valueLabel; + QSpacerItem *spacerItem; }; #endif // UASQUICKVIEWTEXTITEM_H diff --git a/tools/fix_code_style.sh b/tools/fix_code_style.sh new file mode 100755 index 0000000000000000000000000000000000000000..a6543998868e9eeb25d6224bfaca4ccd4585dfc5 --- /dev/null +++ b/tools/fix_code_style.sh @@ -0,0 +1,19 @@ +#!/bin/sh +astyle \ + --style=allman \ + --indent=spaces=4 \ + --indent-cases \ + --indent-preprocessor \ + --break-blocks=all \ + --pad-oper \ + --pad-header \ + --unpad-paren \ + --keep-one-line-blocks \ + --keep-one-line-statements \ + --align-pointer=name \ + --align-reference=name \ + --suffix=none \ + --ignore-exclude-errors-x \ + --lineend=linux \ + --exclude=EASTL \ + $*