pax_global_header 0000666 0000000 0000000 00000000064 12706171405 0014515 g ustar 00root root 0000000 0000000 52 comment=84665a7b7013285b9f3ee799ee1d9ca7bc6f0e55
mxt-app-1.27/ 0000775 0000000 0000000 00000000000 12706171405 0013034 5 ustar 00root root 0000000 0000000 mxt-app-1.27/.editorconfig 0000664 0000000 0000000 00000000330 12706171405 0015505 0 ustar 00root root 0000000 0000000 # editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[Makefile.am]
indent_style = tab
indent_size = 8
mxt-app-1.27/.gitignore 0000664 0000000 0000000 00000000677 12706171405 0015036 0 ustar 00root root 0000000 0000000 /aclocal.m4
/ar-lib
/config.guess
/config.h
/config.h.in
/config.log
/config.status
/config.sub
/configure
/compile
/depcomp
/install-sh
/libtool
/ltmain.sh
/stamp-h1
.dirstamp
/git-version
Makefile
Makefile.in
/missing
/mxt-app
/run-unit-tests
/run-unit-tests.log
/run-unit-tests.trs
/test-driver
/test-suite.log
/man1/mxt-app.1
/autom4te.cache/
/m4/
/obj/
/libs/
*.lo
*.o
*.la
.deps/
/.libs/
.reviewboardrc
doc/html
doc/doxygen_sqlite3.db
/tags
mxt-app-1.27/.gitmodules 0000664 0000000 0000000 00000000160 12706171405 0015206 0 ustar 00root root 0000000 0000000 [submodule "lib/libusbdroid/code"]
path = lib/libusbdroid/code
url = https://github.com/ndyer/libusbdroid.git
mxt-app-1.27/AndroidManifest.xml 0000664 0000000 0000000 00000000172 12706171405 0016625 0 ustar 00root root 0000000 0000000
mxt-app-1.27/LICENSE 0000664 0000000 0000000 00000002360 12706171405 0014042 0 ustar 00root root 0000000 0000000 Copyright (c) 2011, Atmel Corporation.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
mxt-app-1.27/Makefile.am 0000664 0000000 0000000 00000005767 12706171405 0015107 0 ustar 00root root 0000000 0000000 ACLOCAL_AMFLAGS = -I m4
EXTRA_DIST = autogen.sh build-aux/version.sh README.md doc/doxygen.cfg
GIT_VERSION := $(shell $(top_srcdir)/build-aux/version.sh)
.PHONY: force
git-version: force
echo '$(GIT_VERSION)' | cmp -s - $@ || echo '$(GIT_VERSION)' > $@
AM_MAKEFLAGS = --no-print-directory
AM_CFLAGS = \
-I$(top_srcdir)/src \
-DMXT_VERSION=\"$(GIT_VERSION)\" \
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -D_GNU_SOURCE=1
AM_LDFLAGS = \
-Wl,--gc-sections \
-Wl,--as-needed
if !DEBUG
AM_CFLAGS += -DNDEBUG
endif
bin_PROGRAMS = mxt-app
noinst_LTLIBRARIES = libmaxtouch.la
check_PROGRAMS = run-unit-tests
run_unit_tests_SOURCES =\
src/test/run_unit_tests.c \
src/test/test_utilfuncs.c
run_unit_tests_CFLAGS =\
-I$(top_srcdir)/src \
-fvisibility=hidden \
-ffunction-sections \
-fdata-sections \
-Wall -Werror -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
-Wpointer-arith -Wsign-compare -Wchar-subscripts -Wstrict-prototypes \
-Wwrite-strings -Wshadow -Wformat-security -Wtype-limits \
-DMXT_VERSION=\"$(GIT_VERSION)\" \
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0
run_unit_tests_LDFLAGS = -lcmocka -lmaxtouch
TESTS = run-unit-tests
libmaxtouch_la_SOURCES =\
src/libmaxtouch/libmaxtouch.h \
src/libmaxtouch/libmaxtouch.c \
src/libmaxtouch/info_block.h \
src/libmaxtouch/info_block.c \
src/libmaxtouch/log.h \
src/libmaxtouch/log.c \
src/libmaxtouch/utilfuncs.h \
src/libmaxtouch/utilfuncs.c \
src/libmaxtouch/msg.h \
src/libmaxtouch/msg.c \
src/libmaxtouch/config.c \
src/libmaxtouch/sysfs/sysfs_device.h \
src/libmaxtouch/sysfs/sysfs_device.c \
src/libmaxtouch/sysfs/dmesg.h \
src/libmaxtouch/sysfs/dmesg.c \
src/libmaxtouch/i2c_dev/i2c_dev_device.h \
src/libmaxtouch/i2c_dev/i2c_dev_device.c \
src/libmaxtouch/hidraw/hidraw_device.h \
src/libmaxtouch/hidraw/hidraw_device.c
if HAVE_LIBUSB
libmaxtouch_la_SOURCES += \
src/libmaxtouch/usb/usb_device.h \
src/libmaxtouch/usb/usb_device.c
AM_CFLAGS += -DHAVE_LIBUSB
libmaxtouch_la_LIBS = @USBLIBS@
libmaxtouch_la_LDFLAGS = -lusb-1.0
endif
mxt_app_LDADD = libmaxtouch.la
EXTRA_mxt_app_DEPENDENCIES = git-version
mxt_app_SOURCES =\
src/mxt-app/mxt_app.h \
src/mxt-app/mxt_app.c \
src/mxt-app/menu.c \
src/mxt-app/bootloader.c \
src/mxt-app/diagnostic_data.c \
src/mxt-app/touch_app.c \
src/mxt-app/self_test.c \
src/mxt-app/bridge.c \
src/mxt-app/gr.c \
src/mxt-app/serial_data.c \
src/mxt-app/buffer.c \
src/mxt-app/buffer.h \
src/mxt-app/self_cap.c \
src/mxt-app/signal.c
.PHONY: doc
doc: doc/doxygen.cfg
doxygen doc/doxygen.cfg
if ENABLE_MAN
man1_MANS = man1/mxt-app.1
man1/mxt-app.1: README.md
@$(MKDIR_P) man1/
-pandoc -s -t man \
-V title="MXT-APP" \
-V section="1" \
-V description="\"mxt-app $(GIT_VERSION)\"" \
$(top_srcdir)/README.md -o man1/mxt-app.1
endif
clean-local:
-rm git-version
-rm man1/mxt-app.1
-rm -Rf doc/html
dist-hook:
echo $(VERSION) > $(distdir)/VERSION
indent:
astyle --style=linux --indent=spaces=2 \
$(mxt_app_SOURCES) $(libmaxtouch_la_SOURCES)
ctags:
find src -type f -name "*.[ch]" | xargs @CTAGS@
mxt-app-1.27/README.md 0000664 0000000 0000000 00000031776 12706171405 0014331 0 ustar 00root root 0000000 0000000 # NAME
mxt-app - command line utility for maXTouch devices
# SYNOPSIS
mxt-app [*command*] \[*options*\]...
# DESCRIPTION
mxt-app is a utility for managing Atmel maXTouch touch controllers and other
devices that support Atmel Object Based Protocol.
If no *command* is not given, mxt-app will provide an interactive menu based
interface.
# OBJECT PROTOCOL
The Atmel Object Based Protocol defines how device registers (normally
accessed via I2C) are mapped to different functions within the devices. This
interface organises the register map into separate objects each of which is
given a T number. *mxt-app* can inspect and alter the object configuration,
and view diagnostic data, while the device is running.
For a description of object protocol, see *Atmel AT42QT1085
Object Protocol Guide*, available from atmel.com.
The meaning of the configuration bytes within the objects may be found in the
Protocol Guide documentation released with each device, and is only provided
by Atmel under NDA.
# GENERAL COMMANDS
`-h [--help]`
: Display a brief summary of available options and exit.
`-i [--info]`
: Print the ID information and object table.
`-M [--messages] [*timeout*]`
: Prints the messages until *timeout* seconds have passed. If no *timeout*
is provided, continue until user presses Ctrl-C. Zero timeout reads once.
Provide `-F [--msg-filter]` option to filter by a specific object.
`-F [--msg-filter] *TYPE*`
: Filters messages by object *TYPE*.
`--reset`
: Reset device.
`--calibrate`
: Send calibrate command.
`--backup[*=COMMAND*]`
: Backup configuration to NVRAM where the optional argument, *COMMAND*, is the BACKUPNV command.
`-g`
: Write Golden Reference calibration to NVRAM.
`--self-cap-tune-config`
: Tune and calibrate the self capacitance settings and store them to the device configuration.
`--self-cap-tune-nvram`
: Tune and calibrate the self capacitance settings and store them to NVRAM without updating the Config Checksum.
`--version`
: print version of mxt-app.
`--block-size *BLOCKSIZE*`
: Sets the i2c block size.
# CONFIGURATION FILE COMMANDS
`--load *FILE*`
: Upload config from *FILE*, write it to NVRAM, and reset device. The
configuration may be in `.xcfg` or `OBP_RAW` format.
`--save *FILE*`
: Save config to *FILE* in either `OBP_RAW` or `.xcfg` format.
`--checksum *FILE*`
: Read the contents of *FILE* and recalculate the configuration checksum.
# REGISTER READ/WRITE COMMANDS
`-R [--read]`
: Read data from the device.
`-W [--write]`
: Write data to the device.
`-n [--count] *COUNT*`
: read/write *COUNT* registers
`-f [--format]`
: format register output
`-I [--instance] *INSTANCE*`
: select object *INSTANCE*
`-r [--register] *REGISTER*`
: start at *REGISTER* (offset in object when used with *TYPE*)
`-T [--type] *TYPE*`
: select object *TYPE*
`--zero`
: zero all configuration settings
## EXAMPLES
### Read info block:
$ mxt-app -R -n7 -r0
82 19 11 AA 18 0E 16
### Read T7 Power Config object:
$ mxt-app -R -T7
32 FF 05 43
### Zero first two bytes of T7:
$ mxt-app -W -T7 0000
### Read T7 Power Config object, formatted output:
$ mxt-app -R -T7 --format
GEN_POWERCONFIG_T7
00: 0x00 0 0000 0000
01: 0x00 0 0000 0000
02: 0x05 5 0000 0101
03: 0x43 67 0100 0011
# TCP SOCKET COMMANDS
*mxt-app* supports connection over TCP using a ASCII protocol which allows
mxt-app to act as a bridge so that Atmel proprietary tools such as *Object
Server* can access the device.
`-C [--bridge-client] *HOST*`
: Connect over TCP to *HOST*
`-S [--bridge-server]`
: Start TCP socket server
`-p [--port] PORT`
: TCP port (default 4000)
# BOOTLOADER COMMANDS
`--bootloader-version`
: Query and print ID and version of bootloader.
`--flash *FIRMWARE*`
: Flash *FIRMWARE* to device. The firmware file should be in `.enc` format.
`--reset-bootloader`
: Reset device in bootloader mode. In bootloader mode the device will cease
normal operation until a firmware is sent. The I2C address or USB PID will
change. The only valid command in this mode is `--flash`. A hard power
cycle will return the device to normal Object Protocol mode, unless the
firmware image is corrupted. This command is only provided for debugging
purposes: in most cases `--flash` will manage the change to/from
bootloader mode before/after flash.
`--firmware-version *VERSION*`
: The .enc file format does not provide the firmware version in a form
available to mxt-app. If it is provided via this switch, mxt-app can check
firmware *VERSION* before and after flash. It will skip the flash process
if the firmware version is already correct. It will also check for a
successful flash on completion. The version must be provided in the format
`1.0.AA`.
# T25 SELF TEST OPTIONS
The Self Test T25 object runs self-test routines in the device to find faults
in the sense lines and electrodes. The Self Test T25 object runs a series of
test sequences.
`-t [--test]`
: Run all self tests.
`-t*XX* [--test=*XX*]`
: Run individual self test specified by the *CMD* hex value.
`-t01`
: run analog power test.
`-t11`
: run pin fault test.
`-t12`
: run pin fault 2 test.
`-t13`
: run AND gate test.
`-t17`
: run signal limit test.
`-t20`
: run gain test.
`-t21`
: run offset fault test.
# T37 DIAGNOSTIC DATA OPTIONS
Capture frames of diagnostic data. The default mode is to capture touch
deltas. Self capacitance measurements are only available on some devices.
`--debug-dump *FILE*`
: The T37 Diagnostic Data object provides raw access to touch reference/delta
measurements from the touch screen. Diagnostic data is written to *FILE* in
CSV format. The format is compatible with the Atmel Hawkeye utility.
`--frames *N*`
: Capture *N* frames of data.
`--references`
: Capture references data.
`--self-cap-signals`
: Capture self cap signals.
`--self-cap-deltas`
: Capture self cap deltas.
`--self-cap-refs`
: Capture self cap references.
`--active-stylus-deltas`
: Capture active stylus deltas.
`--active-stylus-refs`
: Capture active stylus references.
# T68 SERIAL DATA COMMANDS
`--t68-file *FILE*`
: Upload *FILE* to the device via the T68 Serial Data object.
`--t68-datatype *DATATYPE*`
: Set *DATATYPE* of the file. This will be automatically detected from the
file itself in most cases.
# FINDING AND SPECIFYING DEVICE
By default mxt-app will scan available devices and connect to the first device
it finds.
`-q [--query]`
: Scan for devices and output a list.
`-d [--device] *DEVICESTRING*`
: Connect to a particular device specified by *DEVICESTRING* which is given
in the same format as output by `--query`.
There are three connection methods supported for hardware access:
## sysfs
This is used in conjunction with the Linux kernel driver. It accesses sysfs
attributes under the directory
/sys/bus/i2c/drivers/dddddddd/b-00xx/
Where
d
: driver name - `atmel_mxt_ts`, `Atmel MXTXXXX`, etc
b
: i2c adapter
xx
: i2c address
A specific USB device can be specified by giving a device
option `-d sysfs:PATH` as given by `-q/--query` option
The sysfs attributes used under this directory are
`mem_access`
: Access to raw I2C address space.
`debug_enable`
: Output messages from the device to dmesg log as hexadecimal.
`debug_v2_enable`, `debug_msg`, `debug_notify`
: Optional improved binary interface to retrieve messages
They are provided when using the Atmel kernel driver from github, and may be
supported by other devices.
## USB
Many maXTouch devices support a USB mode which reports touches via USB HID. In
addition, evaluation boards may use a "bridge chip" which interfaces I2C to the
same protocol.
USB mode will be built by autotools when libusb is available.
A specific USB device can be specified by giving a device
option `-d usb:001-003` which corresponds to the bus and device numbers
given by the `-q/--query` option and lsusb.
## I2C debug interface
Devices can be accessed directly via the *i2c-dev* I2C debug interface by giving
adapter and address on command line.
The i2c-dev interface is documented in the Linux kernel source, in
Documentation/i2c/dev-interface
The I2C debug interface support must be enabled using the `CONFIG_I2C_CHARDEV`
kernel configuration option. It is enabled on a system if files `/dev/i2c-*`
are present.
To use i2c-dev, provide a device string such as `-d i2c-dev:1-004a`.
Messages from the maXTouch devices are read by polling. If a kernel driver is
also present on the system, reading messages on interrupt, then no messages
will be received by the tool. A workaround is to set T18.COMMAND (byte 1) to 2
"Force the CHG line high (inactive)" so the kernel driver does not receive an
interrupt.
There is no scanning support. This is because reading from every possible
maXTouch address on every I2C bus might adversely affect some unrelated
hardware that does not understand Object Protocol. You must manually identify
the correct adapter and address by reference to the protocol guide or to the
platform setup.
It is possible to use the `--flash` command with a device already in bootloader
mode, by specifying the bootloader address.
## HIDRAW
The hidraw backend supports maXTouch devices which connect using USB or HID
over I2C.
The hidraw interface is documented in the Linux kernel source, in
Documentation/hid/hidraw.txt
The device must have /dev/hidraw raw HID device support enabled using the
CONFIG_HIDRAW kernel configuration option.
To use hidraw, provide a device string such as `-d hidraw:/dev/hidraw0`.
There is no scanning support.
Bootloading is not supported in this mode.
# DEBUG OPTIONS
`-v [--verbose] *LEVEL*`
: set debug level. *LEVEL* is one of 0 (Silent), 1 (Warnings and Errors),
2 (Info - default), 3 (Debug), 4 (Verbose). Debug and Verbose are
only available if built in.
# EXIT VALUES
0
: Success
1
: Internal error/assert
2
: Input/output error
3
: Memory allocation failure
4
: Timeout
5
: Could not find a device or device went away
6
: Permission denied
7
: Operation not allowed for this device type
8
: Interrupt function call
9
: Object not available on device
10
: Received unexpected invalid message from message processor
11
: Self test invalid test command
12
: Self test AVdd Analog power is not present
13
: Self test Pin fault
14
: Self test AND Gate Fault
15
: Self test Signal limit fault
16
: Self test Gain error
17
: Information block checksum error
18
: Bootloader already unlocked
19
: Bootloader CRC failure (transmission failure)
20
: File format error
21
: Device firmware already required version
22
: Could not identify bootloader address
23
: Version on device did not match version given after bootloading operation
24
: Device did not reset
25
: Device in unexpected state
26
: Incorrect command line parameters or menu input given
27
: Bridge TCP protocol parse error
28
: Bridge connection error
29
: Serial data download failed
30
: No such file or directory
31
: Error processing self cap command
# COMPILING FROM SOURCE
To download the source code using git:
git clone https://github.com/atmel-maxtouch/mxt-app.git
There are two build harnesses, for Android and autotools:
## Android
To download libusbdroid submodule:
git submodule init
git submodule update
To compile using Android NDK:
ndk-build
To enable debug:
ndk-build NDK_DEBUG=1
To enable PIE support (for Android L):
ndk-build APP_PLATFORM=android-16
Binaries will be placed in libs/
The Android NDK is available from https://developer.android.com/tools/sdk/ndk/
### Running on Android
adb push libs/armeabi/mxt-app /data/local/tmp/
adb shell /data/local/tmp/mxt-app [command]
If executable permissions have not been set, run:
adb shell chmod 777 /data/local/tmp/mxt-app
## autotools
To compile using autotools:
./autogen.sh && make
To cross-compile:
./autogen.sh --host=arm-linux-gnueabi && make
To enable debug:
./autogen.sh --enable-debug
To enable generation of the man page using pandoc:
./autogen.sh --enable-man
To build the doxygen documentation (this requires doxygen and graphviz to be
installed):
make doc
# VERSION NUMBERING
A version number is generated by `git describe` during the build process and
is reported by `--version` and to debug logs.
A typical version might be `1.15-29-g8321` which means, 29 commits after the
release tag 1.15, with a git SHA id beginning with 8321.
If the source is not checked out using git (for example by clicking on the
github "Download ZIP" link), then the version from the file VERSION in the
source archive is used.
The suffix `-mod` is appended if there are uncommitted changes in the source
code.
# TROUBLESHOOTING
## klogctl error
If you see the warning
W: klogctl error 1 (Operation not permitted)
this indicates that mxt-app has been unable to retrieve messages from dmesg.
Various features will not work properly. It may be possible to unrestrict dmesg
by doing
# echo 0 > /proc/sys/kernel/dmesg_restrict
mxt-app-1.27/VERSION 0000664 0000000 0000000 00000000005 12706171405 0014077 0 ustar 00root root 0000000 0000000 1.27
mxt-app-1.27/autogen.sh 0000775 0000000 0000000 00000000272 12706171405 0015036 0 ustar 00root root 0000000 0000000 #!/bin/sh -e
# Remove dependency cache otherwise file renames confuse autoconf
find . -type d -name \.deps | xargs rm -rf
[ -d m4 ] || mkdir m4
autoreconf -v --install
./configure $@
mxt-app-1.27/build-aux/ 0000775 0000000 0000000 00000000000 12706171405 0014726 5 ustar 00root root 0000000 0000000 mxt-app-1.27/build-aux/version.sh 0000775 0000000 0000000 00000000357 12706171405 0016757 0 ustar 00root root 0000000 0000000 #!/bin/sh
TOPDIR=$(dirname "$0")/..
if [ -d "$TOPDIR/.git" ]
then
VERSION=$(cd "$TOPDIR" && git describe --dirty=-mod --always | sed s/^v//)
fi
if [ -z "$VERSION" ]
then
VERSION=$(tr -d '\n' < "$TOPDIR/VERSION")
fi
echo "$VERSION"
mxt-app-1.27/build-mxt-app.sh 0000775 0000000 0000000 00000004522 12706171405 0016061 0 ustar 00root root 0000000 0000000 #!/bin/bash
set -e
set -x
if [ "$1" == "master" ]
then
git clean -xfd
git stash
git fetch
git submodule init
git submodule update
git checkout -B build origin/master
fi
VERSION=$(build-aux/version.sh)
OUTDIR=mxt-app-$VERSION
rm -rf "$OUTDIR"
mkdir "$OUTDIR"
# Build both normal and debug versions
for DEBUG in 0 1
do
case "$DEBUG" in
0)
CFLAGS="-O2"
AUTOGEN_OPTIONS=""
LIBDIR="libs"
TARGET="install-strip"
BINARY_NAME="mxt-app"
;;
1)
CFLAGS="-O0 -g3"
AUTOGEN_OPTIONS="--enable-debug"
LIBDIR="obj/local"
TARGET="install"
BINARY_NAME="mxt-app-debug"
;;
esac
# Build all Android archs using NDK
# -B force rebuild
for PIE in 0 1
do
case "$PIE" in
0)
APP_PLATFORM="android-15"
PIE_SUFFIX=""
;;
1)
APP_PLATFORM="android-16"
PIE_SUFFIX="-PIE"
;;
esac
ndk-build clean
ndk-build -B NDK_DEBUG=$DEBUG APP_PLATFORM=$APP_PLATFORM V=1
for ARCH in $(basename -a libs/*)
do
# Copy Android binaries
ANDROID_OUTDIR="$OUTDIR/android/$ARCH"
mkdir -p -v "$ANDROID_OUTDIR"
cp -v "$LIBDIR/$ARCH/mxt-app" "$ANDROID_OUTDIR/$BINARY_NAME$PIE_SUFFIX"
done
done
for ARCH in x86 32bit arm armhf
do
case "$ARCH" in
32bit)
AUTOGEN_OPTIONS+=" --build=i686-pc-linux-gnu"
LDFLAGS="LDFLAGS=\"-m32\""
EXTRA_CFLAGS=" -m32"
;;
arm)
AUTOGEN_OPTIONS+=" --host=arm-linux-gnueabi"
EXTRA_CFLAGS=""
LDFLAGS=""
;;
armhf)
AUTOGEN_OPTIONS+=" --host=arm-linux-gnueabihf"
EXTRA_CFLAGS=""
LDFLAGS=""
;;
esac
# Build and copy binaries using autotool toolchain
./autogen.sh "$AUTOGEN_OPTIONS"
make clean
make DESTDIR="$(pwd)/out" CFLAGS="$CFLAGS $EXTRA_CFLAGS" $LDFLAGS $TARGET
mkdir -p -v "$OUTDIR/gnueabi/$ARCH"
cp -v "out/usr/local/bin/mxt-app" "$OUTDIR/gnueabi/$ARCH/$BINARY_NAME"
done
done
# Generate HTML documentation
pandoc --smart \
--css=github-pandoc.css \
--self-contained \
-t html -o "$OUTDIR/README.html" \
-V title="mxt-app v$VERSION user manual" \
-V date="$(date +"%Y-%m-%d")" \
README.md
# Generate changelog from git commit log
gitlog-to-changelog > "$OUTDIR/CHANGELOG.txt"
zip -r "mxt-app-$VERSION.zip" "mxt-app-$VERSION"
mxt-app-1.27/configure.ac 0000664 0000000 0000000 00000004052 12706171405 0015323 0 ustar 00root root 0000000 0000000 # -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.63])
AC_INIT([mxt-app], m4_esyscmd([tr -d '\n' < VERSION]),
[nick.dyer@itdev.co.uk])
AM_INIT_AUTOMAKE([foreign subdir-objects -Wall])
AC_CONFIG_SRCDIR([src/libmaxtouch/libmaxtouch.c])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) dnl Workaround for earlier Automake
LT_INIT
# Check for usb support
AC_CHECK_LIB([usb-1.0], [libusb_init], [libusb=true])
AM_CONDITIONAL([HAVE_LIBUSB], [test x$libusb = xtrue])
# Handle debug/release build
AC_ARG_ENABLE(debug,
AS_HELP_STRING([--enable-debug],
[enable debugging, default: no]),
[case "${enableval}" in
yes) debug=true ;;
no) debug=false ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;;
esac],
[debug=false])
AM_CONDITIONAL(DEBUG, test x"$debug" = x"true")
# Handle generation of man page
AC_ARG_ENABLE(man,
AS_HELP_STRING([--enable-man],
[generate the man page, default: no]),
enable_man=${enableval}, enable_man=no)
AM_CONDITIONAL(ENABLE_MAN, test x"$enable_man" = x"yes")
# Checks for header files.
AC_HEADER_STDBOOL
AC_CHECK_HEADERS([arpa/inet.h fcntl.h netinet/in.h stdint.h stdlib.h])
AC_CHECK_HEADERS([string.h sys/ioctl.h sys/socket.h sys/statfs.h unistd.h])
AC_CHECK_HEADERS([limits.h malloc.h netdb.h sys/time.h ctype.h cmocka.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_INLINE
AC_TYPE_INT16_T
AC_TYPE_INT8_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
AC_TYPE_UINT8_T
AC_TYPE_SIZE_T
AC_PATH_PROG(CTAGS, ctags, /bin/true)
# Checks for library functions.
AC_FUNC_MALLOC
AC_FUNC_REALLOC
AC_CHECK_FUNCS([bzero])
AC_CHECK_FUNCS([gettimeofday])
AC_CHECK_FUNCS([select])
AC_CHECK_FUNCS([setlocale])
AC_CHECK_FUNCS([socket])
AC_CHECK_FUNCS([strerror])
AC_CHECK_FUNCS([strncasecmp])
AC_CHECK_FUNCS([tolower])
AC_CHECK_FUNCS([asprintf])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
mxt-app-1.27/doc/ 0000775 0000000 0000000 00000000000 12706171405 0013601 5 ustar 00root root 0000000 0000000 mxt-app-1.27/doc/doxygen.cfg 0000664 0000000 0000000 00000313441 12706171405 0015745 0 ustar 00root root 0000000 0000000 # Doxyfile 1.8.9.1
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
#
# All text after a double hash (##) is considered a comment and is placed in
# front of the TAG it is preceding.
#
# All text after a single hash (#) is considered a comment and will be ignored.
# The format is:
# TAG = value [value, ...]
# For lists, items can also be appended using:
# TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (\" \").
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
# This tag specifies the encoding used for all characters in the config file
# that follow. The default is UTF-8 which is also the encoding used for all text
# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
# for the list of possible encodings.
# The default value is: UTF-8.
DOXYFILE_ENCODING = UTF-8
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
# double-quotes, unless you are using Doxywizard) that should identify the
# project for which the documentation is generated. This name is used in the
# title of most generated pages and in a few other places.
# The default value is: My Project.
PROJECT_NAME = mxt-app
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER =
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = "Command line utility for Atmel maXTouch devices"
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory.
PROJECT_LOGO =
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
OUTPUT_DIRECTORY = doc
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
# will distribute the generated files over these directories. Enabling this
# option can be useful when feeding doxygen a huge amount of source files, where
# putting all generated files in the same directory would otherwise causes
# performance problems for the file system.
# The default value is: NO.
CREATE_SUBDIRS = NO
# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
# characters to appear in the names of generated files. If set to NO, non-ASCII
# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
# U+3044.
# The default value is: NO.
ALLOW_UNICODE_NAMES = NO
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
# Ukrainian and Vietnamese.
# The default value is: English.
OUTPUT_LANGUAGE = English
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
# descriptions after the members that are listed in the file and class
# documentation (similar to Javadoc). Set to NO to disable this.
# The default value is: YES.
BRIEF_MEMBER_DESC = YES
# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
# description of a member or function before the detailed description
#
# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
# brief descriptions will be completely suppressed.
# The default value is: YES.
REPEAT_BRIEF = YES
# This tag implements a quasi-intelligent brief description abbreviator that is
# used to form the text in various listings. Each string in this list, if found
# as the leading text of the brief description, will be stripped from the text
# and the result, after processing the whole list, is used as the annotated
# text. Otherwise, the brief description is used as-is. If left blank, the
# following values are used ($name is automatically replaced with the name of
# the entity):The $name class, The $name widget, The $name file, is, provides,
# specifies, contains, represents, a, an and the.
ABBREVIATE_BRIEF =
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
# doxygen will generate a detailed section even if there is only a brief
# description.
# The default value is: NO.
ALWAYS_DETAILED_SEC = NO
# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
# inherited members of a class in the documentation of that class as if those
# members were ordinary class members. Constructors, destructors and assignment
# operators of the base classes will not be shown.
# The default value is: NO.
INLINE_INHERITED_MEMB = NO
# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
# before files name in the file list and in the header files. If set to NO the
# shortest path that makes the file name unique will be used
# The default value is: YES.
FULL_PATH_NAMES = YES
# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
# Stripping is only done if one of the specified strings matches the left-hand
# part of the path. The tag can be used to show relative paths in the file list.
# If left blank the directory from which doxygen is run is used as the path to
# strip.
#
# Note that you can specify absolute paths here, but also relative paths, which
# will be relative from the directory where doxygen is started.
# This tag requires that the tag FULL_PATH_NAMES is set to YES.
STRIP_FROM_PATH =
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
# path mentioned in the documentation of a class, which tells the reader which
# header file to include in order to use a class. If left blank only the name of
# the header file containing the class definition is used. Otherwise one should
# specify the list of include paths that are normally passed to the compiler
# using the -I flag.
STRIP_FROM_INC_PATH =
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
# less readable) file names. This can be useful is your file systems doesn't
# support long names like on DOS, Mac, or CD-ROM.
# The default value is: NO.
SHORT_NAMES = NO
# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
# first line (until the first dot) of a Javadoc-style comment as the brief
# description. If set to NO, the Javadoc-style will behave just like regular Qt-
# style comments (thus requiring an explicit @brief command for a brief
# description.)
# The default value is: NO.
JAVADOC_AUTOBRIEF = NO
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
# line (until the first dot) of a Qt-style comment as the brief description. If
# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
# requiring an explicit \brief command for a brief description.)
# The default value is: NO.
QT_AUTOBRIEF = NO
# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
# a brief description. This used to be the default behavior. The new default is
# to treat a multi-line C++ comment block as a detailed description. Set this
# tag to YES if you prefer the old behavior instead.
#
# Note that setting this tag to YES also means that rational rose comments are
# not recognized any more.
# The default value is: NO.
MULTILINE_CPP_IS_BRIEF = NO
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
# documentation from any documented member that it re-implements.
# The default value is: YES.
INHERIT_DOCS = YES
# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
# page for each member. If set to NO, the documentation of a member will be part
# of the file/class/namespace that contains it.
# The default value is: NO.
SEPARATE_MEMBER_PAGES = NO
# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
# uses this value to replace tabs by spaces in code fragments.
# Minimum value: 1, maximum value: 16, default value: 4.
TAB_SIZE = 2
# This tag can be used to specify a number of aliases that act as commands in
# the documentation. An alias has the form:
# name=value
# For example adding
# "sideeffect=@par Side Effects:\n"
# will allow you to put the command \sideeffect (or @sideeffect) in the
# documentation, which will result in a user-defined paragraph with heading
# "Side Effects:". You can put \n's in the value part of an alias to insert
# newlines.
ALIASES =
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding "class=itcl::class"
# will allow you to use the command class in the itcl::class meaning.
TCL_SUBST =
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For
# instance, some of the names that are used will be different. The list of all
# members will be omitted, etc.
# The default value is: NO.
OPTIMIZE_OUTPUT_FOR_C = YES
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
# Python sources only. Doxygen will then generate output that is more tailored
# for that language. For instance, namespaces will be presented as packages,
# qualified scopes will look different, etc.
# The default value is: NO.
OPTIMIZE_OUTPUT_JAVA = NO
# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
# sources. Doxygen will then generate output that is tailored for Fortran.
# The default value is: NO.
OPTIMIZE_FOR_FORTRAN = NO
# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
# sources. Doxygen will then generate output that is tailored for VHDL.
# The default value is: NO.
OPTIMIZE_OUTPUT_VHDL = NO
# Doxygen selects the parser to use depending on the extension of the files it
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
# Fortran. In the later case the parser tries to guess whether the code is fixed
# or free formatted code, this is the default for Fortran type files), VHDL. For
# instance to make doxygen treat .inc files as Fortran files (default is PHP),
# and .f files as C (default is Fortran), use: inc=Fortran f=C.
#
# Note: For files without extension you can use no_extension as a placeholder.
#
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
# the files are not read by doxygen.
EXTENSION_MAPPING =
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
# according to the Markdown format, which allows for more readable
# documentation. See http://daringfireball.net/projects/markdown/ for details.
# The output of markdown processing is further processed by doxygen, so you can
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
# case of backward compatibilities issues.
# The default value is: YES.
MARKDOWN_SUPPORT = YES
# When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can
# be prevented in individual cases by putting a % sign in front of the word or
# globally by setting AUTOLINK_SUPPORT to NO.
# The default value is: YES.
AUTOLINK_SUPPORT = YES
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
# to include (a tag file for) the STL sources as input, then you should set this
# tag to YES in order to let doxygen match functions declarations and
# definitions whose arguments contain STL classes (e.g. func(std::string);
# versus func(std::string) {}). This also make the inheritance and collaboration
# diagrams that involve STL classes more complete and accurate.
# The default value is: NO.
BUILTIN_STL_SUPPORT = NO
# If you use Microsoft's C++/CLI language, you should set this option to YES to
# enable parsing support.
# The default value is: NO.
CPP_CLI_SUPPORT = NO
# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
# will parse them like normal C++ but will assume all classes use public instead
# of private inheritance when no explicit protection keyword is present.
# The default value is: NO.
SIP_SUPPORT = NO
# For Microsoft's IDL there are propget and propput attributes to indicate
# getter and setter methods for a property. Setting this option to YES will make
# doxygen to replace the get and set methods by a property in the documentation.
# This will only work if the methods are indeed getting or setting a simple
# type. If this is not the case, or you want to show the methods anyway, you
# should set this option to NO.
# The default value is: YES.
IDL_PROPERTY_SUPPORT = YES
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
# tag is set to YES then doxygen will reuse the documentation of the first
# member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly.
# The default value is: NO.
DISTRIBUTE_GROUP_DOC = NO
# Set the SUBGROUPING tag to YES to allow class member groups of the same type
# (for instance a group of public functions) to be put as a subgroup of that
# type (e.g. under the Public Functions section). Set it to NO to prevent
# subgrouping. Alternatively, this can be done per class using the
# \nosubgrouping command.
# The default value is: YES.
SUBGROUPING = YES
# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
# are shown inside the group in which they are included (e.g. using \ingroup)
# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
# and RTF).
#
# Note that this feature does not work in combination with
# SEPARATE_MEMBER_PAGES.
# The default value is: NO.
INLINE_GROUPED_CLASSES = NO
# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
# with only public data fields or simple typedef fields will be shown inline in
# the documentation of the scope in which they are defined (i.e. file,
# namespace, or group documentation), provided this scope is documented. If set
# to NO, structs, classes, and unions are shown on a separate page (for HTML and
# Man pages) or section (for LaTeX and RTF).
# The default value is: NO.
INLINE_SIMPLE_STRUCTS = NO
# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
# enum is documented as struct, union, or enum with the name of the typedef. So
# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
# with name TypeT. When disabled the typedef will appear as a member of a file,
# namespace, or class. And the struct will be named TypeS. This can typically be
# useful for C code in case the coding convention dictates that all compound
# types are typedef'ed and only the typedef is referenced, never the tag name.
# The default value is: NO.
TYPEDEF_HIDES_STRUCT = NO
# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
# cache is used to resolve symbols given their name and scope. Since this can be
# an expensive process and often the same symbol appears multiple times in the
# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
# doxygen will become slower. If the cache is too large, memory is wasted. The
# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
# symbols. At the end of a run doxygen will report the cache usage and suggest
# the optimal cache size from a speed point of view.
# Minimum value: 0, maximum value: 9, default value: 0.
LOOKUP_CACHE_SIZE = 0
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
# documentation are documented, even if no documentation was available. Private
# class members and static file members will be hidden unless the
# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
# Note: This will also disable the warnings about undocumented members that are
# normally produced when WARNINGS is set to YES.
# The default value is: NO.
EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
# be included in the documentation.
# The default value is: NO.
EXTRACT_PRIVATE = YES
# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
# scope will be included in the documentation.
# The default value is: NO.
EXTRACT_PACKAGE = NO
# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
# included in the documentation.
# The default value is: NO.
EXTRACT_STATIC = YES
# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
# locally in source files will be included in the documentation. If set to NO,
# only classes defined in header files are included. Does not have any effect
# for Java sources.
# The default value is: YES.
EXTRACT_LOCAL_CLASSES = YES
# This flag is only useful for Objective-C code. If set to YES, local methods,
# which are defined in the implementation section but not in the interface are
# included in the documentation. If set to NO, only methods in the interface are
# included.
# The default value is: NO.
EXTRACT_LOCAL_METHODS = NO
# If this flag is set to YES, the members of anonymous namespaces will be
# extracted and appear in the documentation as a namespace called
# 'anonymous_namespace{file}', where file will be replaced with the base name of
# the file that contains the anonymous namespace. By default anonymous namespace
# are hidden.
# The default value is: NO.
EXTRACT_ANON_NSPACES = NO
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
# undocumented members inside documented classes or files. If set to NO these
# members will be included in the various overviews, but no documentation
# section is generated. This option has no effect if EXTRACT_ALL is enabled.
# The default value is: NO.
HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy. If set
# to NO, these classes will be included in the various overviews. This option
# has no effect if EXTRACT_ALL is enabled.
# The default value is: NO.
HIDE_UNDOC_CLASSES = NO
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
# (class|struct|union) declarations. If set to NO, these declarations will be
# included in the documentation.
# The default value is: NO.
HIDE_FRIEND_COMPOUNDS = NO
# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
# documentation blocks found inside the body of a function. If set to NO, these
# blocks will be appended to the function's detailed documentation block.
# The default value is: NO.
HIDE_IN_BODY_DOCS = NO
# The INTERNAL_DOCS tag determines if documentation that is typed after a
# \internal command is included. If the tag is set to NO then the documentation
# will be excluded. Set it to YES to include the internal documentation.
# The default value is: NO.
INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
# names in lower-case letters. If set to YES, upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
# The default value is: system dependent.
CASE_SENSE_NAMES = YES
# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
# their full class and namespace scopes in the documentation. If set to YES, the
# scope will be hidden.
# The default value is: NO.
HIDE_SCOPE_NAMES = NO
# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
# append additional text to a page's title, such as Class Reference. If set to
# YES the compound reference will be hidden.
# The default value is: NO.
HIDE_COMPOUND_REFERENCE= NO
# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
# the files that are included by a file in the documentation of that file.
# The default value is: YES.
SHOW_INCLUDE_FILES = YES
# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
# grouped member an include statement to the documentation, telling the reader
# which file to include in order to use the member.
# The default value is: NO.
SHOW_GROUPED_MEMB_INC = NO
# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
# files with double quotes in the documentation rather than with sharp brackets.
# The default value is: NO.
FORCE_LOCAL_INCLUDES = NO
# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
# documentation for inline members.
# The default value is: YES.
INLINE_INFO = YES
# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
# (detailed) documentation of file and class members alphabetically by member
# name. If set to NO, the members will appear in declaration order.
# The default value is: YES.
SORT_MEMBER_DOCS = YES
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
# descriptions of file, namespace and class members alphabetically by member
# name. If set to NO, the members will appear in declaration order. Note that
# this will also influence the order of the classes in the class list.
# The default value is: NO.
SORT_BRIEF_DOCS = NO
# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
# (brief and detailed) documentation of class members so that constructors and
# destructors are listed first. If set to NO the constructors will appear in the
# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
# member documentation.
# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
# detailed member documentation.
# The default value is: NO.
SORT_MEMBERS_CTORS_1ST = NO
# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
# of group names into alphabetical order. If set to NO the group names will
# appear in their defined order.
# The default value is: NO.
SORT_GROUP_NAMES = NO
# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
# fully-qualified names, including namespaces. If set to NO, the class list will
# be sorted only by class name, not including the namespace part.
# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
# Note: This option applies only to the class list, not to the alphabetical
# list.
# The default value is: NO.
SORT_BY_SCOPE_NAME = NO
# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
# type resolution of all parameters of a function it will reject a match between
# the prototype and the implementation of a member function even if there is
# only one candidate or it is obvious which candidate to choose by doing a
# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
# accept a match between prototype and implementation in such cases.
# The default value is: NO.
STRICT_PROTO_MATCHING = NO
# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
# list. This list is created by putting \todo commands in the documentation.
# The default value is: YES.
GENERATE_TODOLIST = YES
# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
# list. This list is created by putting \test commands in the documentation.
# The default value is: YES.
GENERATE_TESTLIST = YES
# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
# list. This list is created by putting \bug commands in the documentation.
# The default value is: YES.
GENERATE_BUGLIST = YES
# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
# the deprecated list. This list is created by putting \deprecated commands in
# the documentation.
# The default value is: YES.
GENERATE_DEPRECATEDLIST= YES
# The ENABLED_SECTIONS tag can be used to enable conditional documentation
# sections, marked by \if ... \endif and \cond
# ... \endcond blocks.
ENABLED_SECTIONS =
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
# initial value of a variable or macro / define can have for it to appear in the
# documentation. If the initializer consists of more lines than specified here
# it will be hidden. Use a value of 0 to hide initializers completely. The
# appearance of the value of individual variables and macros / defines can be
# controlled using \showinitializer or \hideinitializer command in the
# documentation regardless of this setting.
# Minimum value: 0, maximum value: 10000, default value: 30.
MAX_INITIALIZER_LINES = 30
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
# the bottom of the documentation of classes and structs. If set to YES, the
# list will mention the files that were used to generate the documentation.
# The default value is: YES.
SHOW_USED_FILES = YES
# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
# will remove the Files entry from the Quick Index and from the Folder Tree View
# (if specified).
# The default value is: YES.
SHOW_FILES = YES
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
# page. This will remove the Namespaces entry from the Quick Index and from the
# Folder Tree View (if specified).
# The default value is: YES.
SHOW_NAMESPACES = YES
# The FILE_VERSION_FILTER tag can be used to specify a program or script that
# doxygen should invoke to get the current version for each file (typically from
# the version control system). Doxygen will invoke the program by executing (via
# popen()) the command command input-file, where command is the value of the
# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
# by doxygen. Whatever the program writes to standard output is used as the file
# version. For an example see the documentation.
FILE_VERSION_FILTER =
# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
# by doxygen. The layout file controls the global structure of the generated
# output files in an output format independent way. To create the layout file
# that represents doxygen's defaults, run doxygen with the -l option. You can
# optionally specify a file name after the option, if omitted DoxygenLayout.xml
# will be used as the name of the layout file.
#
# Note that if you run doxygen from a directory containing a file called
# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
# tag is left empty.
LAYOUT_FILE =
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
# the reference definitions. This must be a list of .bib files. The .bib
# extension is automatically appended if omitted. This requires the bibtex tool
# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
# For LaTeX the style of the bibliography can be controlled using
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
# search path. See also \cite for info how to create references.
CITE_BIB_FILES =
#---------------------------------------------------------------------------
# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
# The QUIET tag can be used to turn on/off the messages that are generated to
# standard output by doxygen. If QUIET is set to YES this implies that the
# messages are off.
# The default value is: NO.
QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are
# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
# this implies that the warnings are on.
#
# Tip: Turn warnings on while writing the documentation.
# The default value is: YES.
WARNINGS = YES
# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
# will automatically be disabled.
# The default value is: YES.
WARN_IF_UNDOCUMENTED = YES
# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
# potential errors in the documentation, such as not documenting some parameters
# in a documented function, or documenting parameters that don't exist or using
# markup commands wrongly.
# The default value is: YES.
WARN_IF_DOC_ERROR = YES
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
# are documented, but have no documentation for their parameters or return
# value. If set to NO, doxygen will only warn about wrong or incomplete
# parameter documentation, but not about the absence of documentation.
# The default value is: NO.
WARN_NO_PARAMDOC = YES
# The WARN_FORMAT tag determines the format of the warning messages that doxygen
# can produce. The string should contain the $file, $line, and $text tags, which
# will be replaced by the file and line number from which the warning originated
# and the warning text. Optionally the format may contain $version, which will
# be replaced by the version of the file (if it could be obtained via
# FILE_VERSION_FILTER)
# The default value is: $file:$line: $text.
WARN_FORMAT = "$file:$line: $text"
# The WARN_LOGFILE tag can be used to specify a file to which warning and error
# messages should be written. If left blank the output is written to standard
# error (stderr).
WARN_LOGFILE =
#---------------------------------------------------------------------------
# Configuration options related to the input files
#---------------------------------------------------------------------------
# The INPUT tag is used to specify the files and/or directories that contain
# documented source files. You may enter file names like myfile.cpp or
# directories like /usr/src/myproject. Separate the files or directories with
# spaces.
# Note: If this tag is empty the current directory is searched.
INPUT = src
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see: http://www.gnu.org/software/libiconv) for the list of
# possible encodings.
# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
# *.h) to filter out the source-files in the directories. If left blank the
# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
# *.qsf, *.as and *.js.
FILE_PATTERNS = *.c \
*.h \
*.md
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
# The default value is: NO.
RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should be
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
#
# Note that relative paths are relative to the directory from which doxygen is
# run.
EXCLUDE =
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
# from the input.
# The default value is: NO.
EXCLUDE_SYMLINKS = NO
# If the value of the INPUT tag contains directories, you can use the
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
# certain files from those directories.
#
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories for example use the pattern */test/*
EXCLUDE_PATTERNS = */Library/* \
*_test.cpp \
*Tools/*
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test
#
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */test/*
EXCLUDE_SYMBOLS =
# The EXAMPLE_PATH tag can be used to specify one or more files or directories
# that contain example code fragments that are included (see the \include
# command).
EXAMPLE_PATH =
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
# *.h) to filter out the source-files in the directories. If left blank all
# files are included.
EXAMPLE_PATTERNS =
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
# searched for input files to be used with the \include or \dontinclude commands
# irrespective of the value of the RECURSIVE tag.
# The default value is: NO.
EXAMPLE_RECURSIVE = NO
# The IMAGE_PATH tag can be used to specify one or more files or directories
# that contain images that are to be included in the documentation (see the
# \image command).
IMAGE_PATH =
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
# by executing (via popen()) the command:
#
#
#
# where is the value of the INPUT_FILTER tag, and is the
# name of an input file. Doxygen will then use the output that the filter
# program writes to standard output. If FILTER_PATTERNS is specified, this tag
# will be ignored.
#
# Note that the filter must not add or remove lines; it is applied before the
# code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly.
INPUT_FILTER =
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
# basis. Doxygen will compare the file name with each pattern and apply the
# filter if there is a match. The filters are a list of the form: pattern=filter
# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
# patterns match the file name, INPUT_FILTER is applied.
FILTER_PATTERNS =
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
# INPUT_FILTER) will also be used to filter the input files that are used for
# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
# The default value is: NO.
FILTER_SOURCE_FILES = NO
# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
# it is also possible to disable source filtering for a specific pattern using
# *.ext= (so without naming a filter).
# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
FILTER_SOURCE_PATTERNS =
# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
# is part of the input, its contents will be placed on the main page
# (index.html). This can be useful if you have a project on for instance GitHub
# and want to reuse the introduction page also for the doxygen output.
USE_MDFILE_AS_MAINPAGE = README.md
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
# generated. Documented entities will be cross-referenced with these sources.
#
# Note: To get rid of all source code in the generated output, make sure that
# also VERBATIM_HEADERS is set to NO.
# The default value is: NO.
SOURCE_BROWSER = NO
# Setting the INLINE_SOURCES tag to YES will include the body of functions,
# classes and enums directly into the documentation.
# The default value is: NO.
INLINE_SOURCES = YES
# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
# special comment blocks from generated source code fragments. Normal C, C++ and
# Fortran comments will always remain visible.
# The default value is: YES.
STRIP_CODE_COMMENTS = NO
# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
# function all documented functions referencing it will be listed.
# The default value is: NO.
REFERENCED_BY_RELATION = NO
# If the REFERENCES_RELATION tag is set to YES then for each documented function
# all documented entities called/used by that function will be listed.
# The default value is: NO.
REFERENCES_RELATION = NO
# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
# to YES then the hyperlinks from functions in REFERENCES_RELATION and
# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
# link to the documentation.
# The default value is: YES.
REFERENCES_LINK_SOURCE = YES
# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
# source code will show a tooltip with additional information such as prototype,
# brief description and links to the definition and documentation. Since this
# will make the HTML file larger and loading of large files a bit slower, you
# can opt to disable this feature.
# The default value is: YES.
# This tag requires that the tag SOURCE_BROWSER is set to YES.
SOURCE_TOOLTIPS = YES
# If the USE_HTAGS tag is set to YES then the references to source code will
# point to the HTML generated by the htags(1) tool instead of doxygen built-in
# source browser. The htags tool is part of GNU's global source tagging system
# (see http://www.gnu.org/software/global/global.html). You will need version
# 4.8.6 or higher.
#
# To use it do the following:
# - Install the latest version of global
# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
# - Make sure the INPUT points to the root of the source tree
# - Run doxygen as normal
#
# Doxygen will invoke htags (and that will in turn invoke gtags), so these
# tools must be available from the command line (i.e. in the search path).
#
# The result: instead of the source browser generated by doxygen, the links to
# source code will now point to the output of htags.
# The default value is: NO.
# This tag requires that the tag SOURCE_BROWSER is set to YES.
USE_HTAGS = NO
# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
# verbatim copy of the header file for each class for which an include is
# specified. Set to NO to disable this.
# See also: Section \class.
# The default value is: YES.
VERBATIM_HEADERS = YES
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
# cost of reduced performance. This can be particularly helpful with template
# rich C++ code for which doxygen's built-in parser lacks the necessary type
# information.
# Note: The availability of this option depends on whether or not doxygen was
# compiled with the --with-libclang option.
# The default value is: NO.
CLANG_ASSISTED_PARSING = NO
# If clang assisted parsing is enabled you can provide the compiler with command
# line options that you would normally use when invoking the compiler. Note that
# the include paths will already be set by doxygen for the files and directories
# specified with INPUT and INCLUDE_PATH.
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
CLANG_OPTIONS =
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
# compounds will be generated. Enable this if the project contains a lot of
# classes, structs, unions or interfaces.
# The default value is: YES.
ALPHABETICAL_INDEX = YES
# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
# which the alphabetical index list will be split.
# Minimum value: 1, maximum value: 20, default value: 5.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all classes will
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
# can be used to specify a prefix (or a list of prefixes) that should be ignored
# while generating the index headers.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
# The default value is: YES.
GENERATE_HTML = YES
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
# it.
# The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = html
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp).
# The default value is: .html.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FILE_EXTENSION = .html
# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
# each generated HTML page. If the tag is left blank doxygen will generate a
# standard header.
#
# To get valid HTML the header file that includes any scripts and style sheets
# that doxygen needs, which is dependent on the configuration options used (e.g.
# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
# default header using
# doxygen -w html new_header.html new_footer.html new_stylesheet.css
# YourConfigFile
# and then modify the file new_header.html. See also section "Doxygen usage"
# for information on how to generate the default header that doxygen normally
# uses.
# Note: The header is subject to change so you typically have to regenerate the
# default header when upgrading to a newer version of doxygen. For a description
# of the possible markers and block names see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_HEADER =
# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
# generated HTML page. If the tag is left blank doxygen will generate a standard
# footer. See HTML_HEADER for more information on how to generate a default
# footer and what special commands can be used inside the footer. See also
# section "Doxygen usage" for information on how to generate the default footer
# that doxygen normally uses.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FOOTER =
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
# sheet that is used by each HTML page. It can be used to fine-tune the look of
# the HTML output. If left blank doxygen will generate a default style sheet.
# See also section "Doxygen usage" for information on how to generate the style
# sheet that doxygen normally uses.
# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
# it is more robust and this tag (HTML_STYLESHEET) will in the future become
# obsolete.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_STYLESHEET =
# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
# cascading style sheets that are included after the standard style sheets
# created by doxygen. Using this option one can overrule certain style aspects.
# This is preferred over using HTML_STYLESHEET since it does not replace the
# standard style sheet and is therefore more robust against future updates.
# Doxygen will copy the style sheet files to the output directory.
# Note: The order of the extra style sheet files is of importance (e.g. the last
# style sheet in the list overrules the setting of the previous ones in the
# list). For an example see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET =
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the HTML output directory. Note
# that these files will be copied to the base HTML output directory. Use the
# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
# files will be copied as-is; there are no commands or markers available.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_FILES =
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a colorwheel, see
# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
# purple, and 360 is red again.
# Minimum value: 0, maximum value: 359, default value: 220.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_HUE = 220
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
# in the HTML output. For a value of 0 the output will use grayscales only. A
# value of 255 will produce the most vivid colors.
# Minimum value: 0, maximum value: 255, default value: 100.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_SAT = 100
# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
# luminance component of the colors in the HTML output. Values below 100
# gradually make the output lighter, whereas values above 100 make the output
# darker. The value divided by 100 is the actual gamma applied, so 80 represents
# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
# change the gamma.
# Minimum value: 40, maximum value: 240, default value: 80.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting this
# to NO can help when comparing the output of multiple runs.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = YES
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_DYNAMIC_SECTIONS = NO
# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
# shown in the various tree structured indices initially; the user can expand
# and collapse entries dynamically later on. Doxygen will expand the tree to
# such a level that at most the specified number of entries are visible (unless
# a fully collapsed tree already exceeds this amount). So setting the number of
# entries 1 will produce a full collapsed tree by default. 0 is a special value
# representing an infinite number of entries and will result in a full expanded
# tree by default.
# Minimum value: 0, maximum value: 9999, default value: 100.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_INDEX_NUM_ENTRIES = 100
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
# generated that can be used as input for Apple's Xcode 3 integrated development
# environment (see: http://developer.apple.com/tools/xcode/), introduced with
# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
# Makefile in the HTML output directory. Running make will produce the docset in
# that directory and running make install will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
# for more information.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_DOCSET = NO
# This tag determines the name of the docset feed. A documentation feed provides
# an umbrella under which multiple documentation sets from a single provider
# (such as a company or product suite) can be grouped.
# The default value is: Doxygen generated docs.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_FEEDNAME = "Doxygen generated docs"
# This tag specifies a string that should uniquely identify the documentation
# set bundle. This should be a reverse domain-name style string, e.g.
# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_BUNDLE_ID = org.doxygen.Project
# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
# the documentation publisher. This should be a reverse domain-name style
# string, e.g. com.mycompany.MyDocSet.documentation.
# The default value is: org.doxygen.Publisher.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
# The default value is: Publisher.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_PUBLISHER_NAME = Publisher
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
# Windows.
#
# The HTML Help Workshop contains a compiler that can convert all HTML output
# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
# files are now used as the Windows 98 help format, and will replace the old
# Windows help format (.hlp) on all Windows platforms in the future. Compressed
# HTML files also contain an index, a table of contents, and you can search for
# words in the documentation. The HTML workshop also contains a viewer for
# compressed HTML files.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_HTMLHELP = NO
# The CHM_FILE tag can be used to specify the file name of the resulting .chm
# file. You can add a path in front of the file if the result should not be
# written to the html output directory.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_FILE =
# The HHC_LOCATION tag can be used to specify the location (absolute path
# including file name) of the HTML help compiler (hhc.exe). If non-empty,
# doxygen will try to run the HTML help compiler on the generated index.hhp.
# The file has to be specified with full path.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
HHC_LOCATION =
# The GENERATE_CHI flag controls if a separate .chi index file is generated
# (YES) or that it should be included in the master .chm file (NO).
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
GENERATE_CHI = NO
# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
# and project file content.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_INDEX_ENCODING =
# The BINARY_TOC flag controls whether a binary table of contents is generated
# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
# enables the Previous and Next buttons.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
BINARY_TOC = NO
# The TOC_EXPAND flag can be set to YES to add extra items for group members to
# the table of contents of the HTML help documentation and to the tree view.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
TOC_EXPAND = NO
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
# (.qch) of the generated HTML documentation.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_QHP = NO
# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
# the file name of the resulting .qch file. The path specified is relative to
# the HTML output folder.
# This tag requires that the tag GENERATE_QHP is set to YES.
QCH_FILE =
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
# Project output. For more information please see Qt Help Project / Namespace
# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_NAMESPACE = org.doxygen.Project
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
# Help Project output. For more information please see Qt Help Project / Virtual
# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
# folders).
# The default value is: doc.
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_VIRTUAL_FOLDER = doc
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
# filter to add. For more information please see Qt Help Project / Custom
# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
# filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see Qt Help Project / Custom
# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
# filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's filter section matches. Qt Help Project / Filter Attributes (see:
# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_SECT_FILTER_ATTRS =
# The QHG_LOCATION tag can be used to specify the location of Qt's
# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
# generated .qhp file.
# This tag requires that the tag GENERATE_QHP is set to YES.
QHG_LOCATION =
# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
# generated, together with the HTML files, they form an Eclipse help plugin. To
# install this plugin and make it available under the help contents menu in
# Eclipse, the contents of the directory containing the HTML and XML files needs
# to be copied into the plugins directory of eclipse. The name of the directory
# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
# After copying Eclipse needs to be restarted before the help appears.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_ECLIPSEHELP = NO
# A unique identifier for the Eclipse help plugin. When installing the plugin
# the directory name containing the HTML and XML files should also have this
# name. Each documentation set should have its own identifier.
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
ECLIPSE_DOC_ID = org.doxygen.Project
# If you want full control over the layout of the generated HTML pages it might
# be necessary to disable the index and replace it with your own. The
# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
# of each HTML page. A value of NO enables the index and the value YES disables
# it. Since the tabs in the index contain the same information as the navigation
# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
DISABLE_INDEX = NO
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
# structure should be generated to display hierarchical information. If the tag
# value is set to YES, a side panel will be generated containing a tree-like
# index structure (just like the one that is generated for HTML Help). For this
# to work a browser that supports JavaScript, DHTML, CSS and frames is required
# (i.e. any modern browser). Windows users are probably better off using the
# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
# further fine-tune the look of the index. As an example, the default style
# sheet generated by doxygen has an example that shows how to put an image at
# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
# the same information as the tab index, you could consider setting
# DISABLE_INDEX to YES when enabling this option.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = NO
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
# doxygen will group on one line in the generated HTML documentation.
#
# Note that a value of 0 will completely suppress the enum values from appearing
# in the overview section.
# Minimum value: 0, maximum value: 20, default value: 4.
# This tag requires that the tag GENERATE_HTML is set to YES.
ENUM_VALUES_PER_LINE = 4
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
# to set the initial width (in pixels) of the frame in which the tree is shown.
# Minimum value: 0, maximum value: 1500, default value: 250.
# This tag requires that the tag GENERATE_HTML is set to YES.
TREEVIEW_WIDTH = 250
# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
# external symbols imported via tag files in a separate window.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
EXT_LINKS_IN_WINDOW = NO
# Use this tag to change the font size of LaTeX formulas included as images in
# the HTML documentation. When you change the font size after a successful
# doxygen run you need to manually remove any form_*.png images from the HTML
# output directory to force them to be regenerated.
# Minimum value: 8, maximum value: 50, default value: 10.
# This tag requires that the tag GENERATE_HTML is set to YES.
FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are not
# supported properly for IE 6.0, but are supported on all modern browsers.
#
# Note that when changing this option you need to delete any form_*.png files in
# the HTML output directory before the changes have effect.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
FORMULA_TRANSPARENT = YES
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
# http://www.mathjax.org) which uses client side Javascript for the rendering
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path
# to it using the MATHJAX_RELPATH option.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
USE_MATHJAX = NO
# When MathJax is enabled you can set the default output format to be used for
# the MathJax output. See the MathJax site (see:
# http://docs.mathjax.org/en/latest/output.html) for more details.
# Possible values are: HTML-CSS (which is slower, but has the best
# compatibility), NativeMML (i.e. MathML) and SVG.
# The default value is: HTML-CSS.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_FORMAT = HTML-CSS
# When MathJax is enabled you need to specify the location relative to the HTML
# output directory using the MATHJAX_RELPATH option. The destination directory
# should contain the MathJax.js script. For instance, if the mathjax directory
# is located at the same level as the HTML output directory, then
# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
# Content Delivery Network so you can quickly see the result without installing
# MathJax. However, it is strongly recommended to install a local copy of
# MathJax from http://www.mathjax.org before deployment.
# The default value is: http://cdn.mathjax.org/mathjax/latest.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
# extension names that should be enabled during MathJax rendering. For example
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_EXTENSIONS =
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
# of code that will be used on startup of the MathJax code. See the MathJax site
# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
# example see the documentation.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_CODEFILE =
# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
# the HTML output. The underlying search engine uses javascript and DHTML and
# should work on any modern browser. Note that when using HTML help
# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
# there is already a search function so this one should typically be disabled.
# For large projects the javascript based search engine can be slow, then
# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
# search using the keyboard; to jump to the search box use + S
# (what the is depends on the OS and browser, but it is typically
# , /, or both). Inside the search box use the to jump into the search results window, the results can be navigated
# using the . Press to select an item or to cancel
# the search. The filter options can be selected when the cursor is inside the
# search box by pressing +. Also here use the
# to select a filter and or to activate or cancel the filter
# option.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a web server instead of a web client using Javascript. There
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
# setting. When disabled, doxygen will generate a PHP script for searching and
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
# and searching needs to be provided by external tools. See the section
# "External Indexing and Searching" for details.
# The default value is: NO.
# This tag requires that the tag SEARCHENGINE is set to YES.
SERVER_BASED_SEARCH = NO
# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
# script for searching. Instead the search results are written to an XML file
# which needs to be processed by an external indexer. Doxygen will invoke an
# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
# search results.
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: http://xapian.org/).
#
# See the section "External Indexing and Searching" for details.
# The default value is: NO.
# This tag requires that the tag SEARCHENGINE is set to YES.
EXTERNAL_SEARCH = NO
# The SEARCHENGINE_URL should point to a search engine hosted by a web server
# which will return the search results when EXTERNAL_SEARCH is enabled.
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: http://xapian.org/). See the section "External Indexing and
# Searching" for details.
# This tag requires that the tag SEARCHENGINE is set to YES.
SEARCHENGINE_URL =
# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
# search data is written to a file for indexing by an external tool. With the
# SEARCHDATA_FILE tag the name of this file can be specified.
# The default file is: searchdata.xml.
# This tag requires that the tag SEARCHENGINE is set to YES.
SEARCHDATA_FILE = searchdata.xml
# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
# projects and redirect the results back to the right project.
# This tag requires that the tag SEARCHENGINE is set to YES.
EXTERNAL_SEARCH_ID =
# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
# projects other than the one defined by this configuration file, but that are
# all added to the same external search index. Each project needs to have a
# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
# to a relative location where the documentation can be found. The format is:
# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
# This tag requires that the tag SEARCHENGINE is set to YES.
EXTRA_SEARCH_MAPPINGS =
#---------------------------------------------------------------------------
# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
# The default value is: YES.
GENERATE_LATEX = NO
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
# it.
# The default directory is: latex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked.
#
# Note that when enabling USE_PDFLATEX this option is only used for generating
# bitmaps for formulas in the HTML output, but not in the Makefile that is
# written to the output directory.
# The default file is: latex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_CMD_NAME = latex
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
# index for LaTeX.
# The default file is: makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
MAKEINDEX_CMD_NAME = makeindex
# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
# documents. This may be useful for small projects and may help to save some
# trees in general.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
COMPACT_LATEX = NO
# The PAPER_TYPE tag can be used to set the paper type that is used by the
# printer.
# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
# 14 inches) and executive (7.25 x 10.5 inches).
# The default value is: a4.
# This tag requires that the tag GENERATE_LATEX is set to YES.
PAPER_TYPE = a4wide
# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
# that should be included in the LaTeX output. To get the times font for
# instance you can specify
# EXTRA_PACKAGES=times
# If left blank no extra packages will be included.
# This tag requires that the tag GENERATE_LATEX is set to YES.
EXTRA_PACKAGES =
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
# generated LaTeX document. The header should contain everything until the first
# chapter. If it is left blank doxygen will generate a standard header. See
# section "Doxygen usage" for information on how to let doxygen write the
# default header to a separate file.
#
# Note: Only use a user-defined header if you know what you are doing! The
# following commands have a special meaning inside the header: $title,
# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
# string, for the replacement values of the other commands the user is referred
# to HTML_HEADER.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HEADER =
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
# generated LaTeX document. The footer should contain everything after the last
# chapter. If it is left blank doxygen will generate a standard footer. See
# LATEX_HEADER for more information on how to generate a default footer and what
# special commands can be used inside the footer.
#
# Note: Only use a user-defined footer if you know what you are doing!
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_FOOTER =
# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
# LaTeX style sheets that are included after the standard style sheets created
# by doxygen. Using this option one can overrule certain style aspects. Doxygen
# will copy the style sheet files to the output directory.
# Note: The order of the extra style sheet files is of importance (e.g. the last
# style sheet in the list overrules the setting of the previous ones in the
# list).
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_EXTRA_STYLESHEET =
# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the LATEX_OUTPUT output
# directory. Note that the files will be copied as-is; there are no commands or
# markers available.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_EXTRA_FILES =
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
# contain links (just like the HTML output) instead of page references. This
# makes the output suitable for online browsing using a PDF viewer.
# The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES.
PDF_HYPERLINKS = YES
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
# the PDF file directly from the LaTeX files. Set this option to YES, to get a
# higher quality PDF documentation.
# The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES.
USE_PDFLATEX = YES
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
# command to the generated LaTeX files. This will instruct LaTeX to keep running
# if errors occur, instead of asking the user for help. This option is also used
# when generating formulas in HTML.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_BATCHMODE = NO
# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
# index chapters (such as File Index, Compound Index, etc.) in the output.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HIDE_INDICES = NO
# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
# code with syntax highlighting in the LaTeX output.
#
# Note that which sources are shown also depends on other settings such as
# SOURCE_BROWSER.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_SOURCE_CODE = NO
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
# bibliography, e.g. plainnat, or ieeetr. See
# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
# The default value is: plain.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_BIB_STYLE = plain
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
# RTF output is optimized for Word 97 and may not look too pretty with other RTF
# readers/editors.
# The default value is: NO.
GENERATE_RTF = NO
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
# it.
# The default directory is: rtf.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_OUTPUT = rtf
# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
# documents. This may be useful for small projects and may help to save some
# trees in general.
# The default value is: NO.
# This tag requires that the tag GENERATE_RTF is set to YES.
COMPACT_RTF = NO
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
# contain hyperlink fields. The RTF file will contain links (just like the HTML
# output) instead of page references. This makes the output suitable for online
# browsing using Word or some other Word compatible readers that support those
# fields.
#
# Note: WordPad (write) and others do not support links.
# The default value is: NO.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_HYPERLINKS = NO
# Load stylesheet definitions from file. Syntax is similar to doxygen's config
# file, i.e. a series of assignments. You only have to provide replacements,
# missing definitions are set to their default value.
#
# See also section "Doxygen usage" for information on how to generate the
# default style sheet that doxygen normally uses.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_STYLESHEET_FILE =
# Set optional variables used in the generation of an RTF document. Syntax is
# similar to doxygen's config file. A template extensions file can be generated
# using doxygen -e rtf extensionFile.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_EXTENSIONS_FILE =
# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
# with syntax highlighting in the RTF output.
#
# Note that which sources are shown also depends on other settings such as
# SOURCE_BROWSER.
# The default value is: NO.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_SOURCE_CODE = NO
#---------------------------------------------------------------------------
# Configuration options related to the man page output
#---------------------------------------------------------------------------
# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
# classes and files.
# The default value is: NO.
GENERATE_MAN = NO
# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
# it. A directory man3 will be created inside the directory specified by
# MAN_OUTPUT.
# The default directory is: man.
# This tag requires that the tag GENERATE_MAN is set to YES.
MAN_OUTPUT = man
# The MAN_EXTENSION tag determines the extension that is added to the generated
# man pages. In case the manual section does not start with a number, the number
# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
# optional.
# The default value is: .3.
# This tag requires that the tag GENERATE_MAN is set to YES.
MAN_EXTENSION = .3
# The MAN_SUBDIR tag determines the name of the directory created within
# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
# MAN_EXTENSION with the initial . removed.
# This tag requires that the tag GENERATE_MAN is set to YES.
MAN_SUBDIR =
# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
# will generate one additional man file for each entity documented in the real
# man page(s). These additional files only source the real man page, but without
# them the man command would be unable to find the correct page.
# The default value is: NO.
# This tag requires that the tag GENERATE_MAN is set to YES.
MAN_LINKS = NO
#---------------------------------------------------------------------------
# Configuration options related to the XML output
#---------------------------------------------------------------------------
# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
# captures the structure of the code including all documentation.
# The default value is: NO.
GENERATE_XML = NO
# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
# it.
# The default directory is: xml.
# This tag requires that the tag GENERATE_XML is set to YES.
XML_OUTPUT = xml
# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
# listings (including syntax highlighting and cross-referencing information) to
# the XML output. Note that enabling this will significantly increase the size
# of the XML output.
# The default value is: YES.
# This tag requires that the tag GENERATE_XML is set to YES.
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
# that can be used to generate PDF.
# The default value is: NO.
GENERATE_DOCBOOK = NO
# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
# front of it.
# The default directory is: docbook.
# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
DOCBOOK_OUTPUT = docbook
# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
# program listings (including syntax highlighting and cross-referencing
# information) to the DOCBOOK output. Note that enabling this will significantly
# increase the size of the DOCBOOK output.
# The default value is: NO.
# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
DOCBOOK_PROGRAMLISTING = NO
#---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
# AutoGen Definitions (see http://autogen.sf.net) file that captures the
# structure of the code including all documentation. Note that this feature is
# still experimental and incomplete at the moment.
# The default value is: NO.
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
# file that captures the structure of the code including all documentation.
#
# Note that this feature is still experimental and incomplete at the moment.
# The default value is: NO.
GENERATE_PERLMOD = NO
# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
# output from the Perl module output.
# The default value is: NO.
# This tag requires that the tag GENERATE_PERLMOD is set to YES.
PERLMOD_LATEX = NO
# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
# formatted so it can be parsed by a human reader. This is useful if you want to
# understand what is going on. On the other hand, if this tag is set to NO, the
# size of the Perl module output will be much smaller and Perl will parse it
# just the same.
# The default value is: YES.
# This tag requires that the tag GENERATE_PERLMOD is set to YES.
PERLMOD_PRETTY = YES
# The names of the make variables in the generated doxyrules.make file are
# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
# so different doxyrules.make files included by the same Makefile don't
# overwrite each other's variables.
# This tag requires that the tag GENERATE_PERLMOD is set to YES.
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
# C-preprocessor directives found in the sources and include files.
# The default value is: YES.
ENABLE_PREPROCESSING = YES
# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
# in the source code. If set to NO, only conditional compilation will be
# performed. Macro expansion can be done in a controlled way by setting
# EXPAND_ONLY_PREDEF to YES.
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
MACRO_EXPANSION = YES
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
# the macro expansion is limited to the macros specified with the PREDEFINED and
# EXPAND_AS_DEFINED tags.
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
EXPAND_ONLY_PREDEF = YES
# If the SEARCH_INCLUDES tag is set to YES, the include files in the
# INCLUDE_PATH will be searched if a #include is found.
# The default value is: YES.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
SEARCH_INCLUDES = YES
# The INCLUDE_PATH tag can be used to specify one or more directories that
# contain include files that are not input files but should be processed by the
# preprocessor.
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
INCLUDE_PATH =
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the
# directories. If left blank, the patterns specified with FILE_PATTERNS will be
# used.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
INCLUDE_FILE_PATTERNS =
# The PREDEFINED tag can be used to specify one or more macro names that are
# defined before the preprocessor is started (similar to the -D option of e.g.
# gcc). The argument of the tag is a list of macros of the form: name or
# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
# is assumed. To prevent a macro definition from being undefined via #undef or
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
PREDEFINED = __attribute__(x)=
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The
# macro definition that is found in the sources will be used. Use the PREDEFINED
# tag if you want to use a different macro definition that overrules the
# definition found in the source code.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
EXPAND_AS_DEFINED =
# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
# remove all references to function-like macros that are alone on a line, have
# an all uppercase name, and do not end with a semicolon. Such function macros
# are typically used for boiler-plate code, and will confuse the parser if not
# removed.
# The default value is: YES.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration options related to external references
#---------------------------------------------------------------------------
# The TAGFILES tag can be used to specify one or more tag files. For each tag
# file the location of the external documentation should be added. The format of
# a tag file without this location is as follows:
# TAGFILES = file1 file2 ...
# Adding location for the tag files is done as follows:
# TAGFILES = file1=loc1 "file2 = loc2" ...
# where loc1 and loc2 can be relative or absolute paths or URLs. See the
# section "Linking to external documentation" for more information about the use
# of tag files.
# Note: Each tag file must have a unique name (where the name does NOT include
# the path). If a tag file is not located in the directory in which doxygen is
# run, you must also specify the path to the tagfile here.
TAGFILES =
# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
# tag file that is based on the input files it reads. See section "Linking to
# external documentation" for more information about the usage of tag files.
GENERATE_TAGFILE =
# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
# the class index. If set to NO, only the inherited external classes will be
# listed.
# The default value is: NO.
ALLEXTERNALS = NO
# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
# in the modules index. If set to NO, only the current project's groups will be
# listed.
# The default value is: YES.
EXTERNAL_GROUPS = YES
# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
# the related pages index. If set to NO, only the current project's pages will
# be listed.
# The default value is: YES.
EXTERNAL_PAGES = YES
# The PERL_PATH should be the absolute path and name of the perl script
# interpreter (i.e. the result of 'which perl').
# The default file (with absolute path) is: /usr/bin/perl.
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
# NO turns the diagrams off. Note that this option also works with HAVE_DOT
# disabled, but it is recommended to install and use dot, since it yields more
# powerful graphs.
# The default value is: YES.
CLASS_DIAGRAMS = YES
# You can define message sequence charts within doxygen comments using the \msc
# command. Doxygen will then run the mscgen tool (see:
# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
# the mscgen tool resides. If left empty the tool is assumed to be found in the
# default search path.
MSCGEN_PATH =
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
# If left empty dia is assumed to be found in the default search path.
DIA_PATH =
# If set to YES the inheritance and collaboration graphs will hide inheritance
# and usage relations if the target is undocumented or is not a class.
# The default value is: YES.
HIDE_UNDOC_RELATIONS = YES
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
# available from the path. This tool is part of Graphviz (see:
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
# Bell Labs. The other options in this section have no effect if this option is
# set to NO
# The default value is: YES.
HAVE_DOT = YES
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
# to run in parallel. When set to 0 doxygen will base this on the number of
# processors available in the system. You can set it explicitly to a value
# larger than 0 to get control over the balance between CPU load and processing
# speed.
# Minimum value: 0, maximum value: 32, default value: 0.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_NUM_THREADS = 0
# When you want a differently looking font in the dot files that doxygen
# generates you can specify the font name using DOT_FONTNAME. You need to make
# sure dot is able to find the font, which can be done by putting it in a
# standard location or by setting the DOTFONTPATH environment variable or by
# setting DOT_FONTPATH to the directory containing the font.
# The default value is: Helvetica.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTNAME =
# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
# dot graphs.
# Minimum value: 4, maximum value: 24, default value: 10.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTSIZE = 10
# By default doxygen will tell dot to use the default font as specified with
# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
# the path where dot can find it using this tag.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTPATH =
# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
# each documented class showing the direct and indirect inheritance relations.
# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
CLASS_GRAPH = YES
# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
# graph for each documented class showing the direct and indirect implementation
# dependencies (inheritance, containment, and class references variables) of the
# class with other documented classes.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
COLLABORATION_GRAPH = YES
# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
# groups, showing the direct groups dependencies.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
GROUP_GRAPHS = YES
# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
# collaboration diagrams in a style similar to the OMG's Unified Modeling
# Language.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
UML_LOOK = NO
# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
# class node. If there are many fields or methods and many nodes the graph may
# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
# number of items for each type to make the size more manageable. Set this to 0
# for no limit. Note that the threshold may be exceeded by 50% before the limit
# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
# but if the number exceeds 15, the total amount of fields shown is limited to
# 10.
# Minimum value: 0, maximum value: 100, default value: 10.
# This tag requires that the tag HAVE_DOT is set to YES.
UML_LIMIT_NUM_FIELDS = 10
# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
# collaboration graphs will show the relations between templates and their
# instances.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
TEMPLATE_RELATIONS = NO
# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
# YES then doxygen will generate a graph for each documented file showing the
# direct and indirect include dependencies of the file with other documented
# files.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
INCLUDE_GRAPH = YES
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
# set to YES then doxygen will generate a graph for each documented file showing
# the direct and indirect include dependencies of the file with other documented
# files.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
INCLUDED_BY_GRAPH = YES
# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
# dependency graph for every global function or class method.
#
# Note that enabling this option will significantly increase the time of a run.
# So in most cases it will be better to enable call graphs for selected
# functions only using the \callgraph command.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
CALL_GRAPH = YES
# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
# dependency graph for every global function or class method.
#
# Note that enabling this option will significantly increase the time of a run.
# So in most cases it will be better to enable caller graphs for selected
# functions only using the \callergraph command.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
CALLER_GRAPH = YES
# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
# hierarchy of all classes instead of a textual one.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
GRAPHICAL_HIERARCHY = YES
# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
# dependencies a directory has on other directories in a graphical way. The
# dependency relations are determined by the #include relations between the
# files in the directories.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
DIRECTORY_GRAPH = YES
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot.
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
# to make the SVG files visible in IE 9+ (other browsers do not have this
# requirement).
# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
# gif:cairo:gd, gif:gd, gif:gd:gd and svg.
# The default value is: png.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_IMAGE_FORMAT = png
# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
# enable generation of interactive SVG images that allow zooming and panning.
#
# Note that this requires a modern browser other than Internet Explorer. Tested
# and working are Firefox, Chrome, Safari, and Opera.
# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
# the SVG files visible. Older versions of IE do not have SVG support.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
INTERACTIVE_SVG = NO
# The DOT_PATH tag can be used to specify the path where the dot tool can be
# found. If left blank, it is assumed the dot tool can be found in the path.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_PATH =
# The DOTFILE_DIRS tag can be used to specify one or more directories that
# contain dot files that are included in the documentation (see the \dotfile
# command).
# This tag requires that the tag HAVE_DOT is set to YES.
DOTFILE_DIRS =
# The MSCFILE_DIRS tag can be used to specify one or more directories that
# contain msc files that are included in the documentation (see the \mscfile
# command).
MSCFILE_DIRS =
# The DIAFILE_DIRS tag can be used to specify one or more directories that
# contain dia files that are included in the documentation (see the \diafile
# command).
DIAFILE_DIRS =
# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
# path where java can find the plantuml.jar file. If left blank, it is assumed
# PlantUML is not used or called during a preprocessing step. Doxygen will
# generate a warning when it encounters a \startuml command in this case and
# will not generate output for the diagram.
PLANTUML_JAR_PATH =
# When using plantuml, the specified paths are searched for files specified by
# the !include statement in a plantuml block.
PLANTUML_INCLUDE_PATH =
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
# that will be shown in the graph. If the number of nodes in a graph becomes
# larger than this value, doxygen will truncate the graph, which is visualized
# by representing a node as a red box. Note that doxygen if the number of direct
# children of the root node in a graph is already larger than
# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
# Minimum value: 0, maximum value: 10000, default value: 50.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_GRAPH_MAX_NODES = 50
# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
# generated by dot. A depth value of 3 means that only nodes reachable from the
# root by following a path via at most 3 edges will be shown. Nodes that lay
# further from the root node will be omitted. Note that setting this option to 1
# or 2 may greatly reduce the computation time needed for large code bases. Also
# note that the size of a graph can be further restricted by
# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
# Minimum value: 0, maximum value: 1000, default value: 0.
# This tag requires that the tag HAVE_DOT is set to YES.
MAX_DOT_GRAPH_DEPTH = 0
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
# background. This is disabled by default, because dot on Windows does not seem
# to support this out of the box.
#
# Warning: Depending on the platform used, enabling this option may lead to
# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
# read).
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_TRANSPARENT = NO
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
# this, this feature is disabled by default.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_MULTI_TARGETS = YES
# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
# explaining the meaning of the various boxes and arrows in the dot generated
# graphs.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
GENERATE_LEGEND = YES
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
# files that are used to generate the various graphs.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_CLEANUP = YES
mxt-app-1.27/github-pandoc.css 0000664 0000000 0000000 00000034462 12706171405 0016303 0 ustar 00root root 0000000 0000000 /*! normalize.css v2.1.3 | MIT License | git.io/normalize */
/* ==========================================================================
HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined in IE 8/9.
*/
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section,
summary {
display: block;
}
/**
* Correct `inline-block` display not defined in IE 8/9.
*/
audio,
canvas,
video {
display: inline-block;
}
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Address `[hidden]` styling not present in IE 8/9.
* Hide the `template` element in IE, Safari, and Firefox < 22.
*/
[hidden],
template {
display: none;
}
/* ==========================================================================
Base
========================================================================== */
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS text size adjust after orientation change, without disabling
* user zoom.
*/
html {
font-family: sans-serif; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/**
* Remove default margin.
*/
body {
margin: 0;
}
/* ==========================================================================
Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
a {
background: transparent;
}
/**
* Address `outline` inconsistency between Chrome and other browsers.
*/
a:focus {
outline: thin dotted;
}
/**
* Improve readability when focused and also mouse hovered in all browsers.
*/
a:active,
a:hover {
outline: 0;
}
/* ==========================================================================
Typography
========================================================================== */
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari 5, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/**
* Address styling not present in IE 8/9, Safari 5, and Chrome.
*/
abbr[title] {
border-bottom: 1px dotted;
}
/**
* Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
*/
b,
strong {
font-weight: bold;
}
/**
* Address styling not present in Safari 5 and Chrome.
*/
dfn {
font-style: italic;
}
/**
* Address differences between Firefox and other browsers.
*/
hr {
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0;
}
/**
* Address styling not present in IE 8/9.
*/
mark {
background: #ff0;
color: #000;
}
/**
* Correct font family set oddly in Safari 5 and Chrome.
*/
code,
kbd,
pre,
samp {
font-family: monospace, serif;
font-size: 1em;
}
/**
* Improve readability of pre-formatted text in all browsers.
*/
pre {
white-space: pre-wrap;
}
/**
* Set consistent quote types.
*/
q {
quotes: "\201C" "\201D" "\2018" "\2019";
}
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
/* ==========================================================================
Embedded content
========================================================================== */
/**
* Remove border when inside `a` element in IE 8/9.
*/
img {
border: 0;
}
/**
* Correct overflow displayed oddly in IE 9.
*/
svg:not(:root) {
overflow: hidden;
}
/* ==========================================================================
Figures
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari 5.
*/
figure {
margin: 0;
}
/* ==========================================================================
Forms
========================================================================== */
/**
* Define consistent border, margin, and padding.
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/**
* 1. Correct `color` not being inherited in IE 8/9.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
border: 0; /* 1 */
padding: 0; /* 2 */
}
/**
* 1. Correct font family not being inherited in all browsers.
* 2. Correct font size not being inherited in all browsers.
* 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
*/
button,
input,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 2 */
margin: 0; /* 3 */
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
button,
input {
line-height: normal;
}
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+.
* Correct `select` style inheritance in Firefox 4+ and Opera.
*/
button,
select {
text-transform: none;
}
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
*/
button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button; /* 2 */
cursor: pointer; /* 3 */
}
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
html input[disabled] {
cursor: default;
}
/**
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
* (include `-moz` to future-proof).
*/
input[type="search"] {
-webkit-appearance: textfield; /* 1 */
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box; /* 2 */
box-sizing: content-box;
}
/**
* Remove inner padding and search cancel button in Safari 5 and Chrome
* on OS X.
*/
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/**
* 1. Remove default vertical scrollbar in IE 8/9.
* 2. Improve readability and alignment in all browsers.
*/
textarea {
overflow: auto; /* 1 */
vertical-align: top; /* 2 */
}
/* ==========================================================================
Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0;
}
.go-top {
position: fixed;
bottom: 2em;
right: 2em;
text-decoration: none;
background-color: #E0E0E0;
font-size: 12px;
padding: 1em;
display: inline;
}
/* Github css */
html,body{ margin: auto;
padding-right: 1em;
padding-left: 1em;
max-width: 44em; color:black;}*:not('#mkdbuttons'){margin:0;padding:0}body{font:13.34px helvetica,arial,freesans,clean,sans-serif;-webkit-font-smoothing:subpixel-antialiased;line-height:1.4;padding:3px;background:#fff;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px}p{margin:1em 0}a{color:#4183c4;text-decoration:none}body{background-color:#fff;padding:30px;margin:15px;font-size:14px;line-height:1.6}body>*:first-child{margin-top:0!important}body>*:last-child{margin-bottom:0!important}@media screen{body{box-shadow:0 0 0 1px #cacaca,0 0 0 4px #eee}}h1,h2,h3,h4,h5,h6{margin:20px 0 10px;padding:0;font-weight:bold;-webkit-font-smoothing:subpixel-antialiased;cursor:text}h1{font-size:28px;color:#000}h2{font-size:24px;border-bottom:1px solid #ccc;color:#000}h3{font-size:18px;color:#333}h4{font-size:16px;color:#333}h5{font-size:14px;color:#333}h6{color:#777;font-size:14px}p,blockquote,table,pre{margin:15px 0}ul{padding-left:30px}ol{padding-left:30px}ol li ul:first-of-type{margin-top:0}body>h2:first-child{margin-top:0;padding-top:0}body>h1:first-child{margin-top:0;padding-top:0}body>h1:first-child+h2{margin-top:0;padding-top:0}body>h3:first-child,body>h4:first-child,body>h5:first-child,body>h6:first-child{margin-top:0;padding-top:0}a:first-child h1,a:first-child h2,a:first-child h3,a:first-child h4,a:first-child h5,a:first-child h6{margin-top:0;padding-top:0}h1+p,h2+p,h3+p,h4+p,h5+p,h6+p,ul li>:first-child,ol li>:first-child{margin-top:0}dl{padding:0}dl dt{font-size:14px;font-weight:bold;font-style:italic;padding:0;margin:15px 0 5px}dl dt:first-child{padding:0}dl dt>:first-child{margin-top:0}dl dt>:last-child{margin-bottom:0}dl dd{margin:0 0 15px;padding:0 15px}dl dd>:first-child{margin-top:0}dl dd>:last-child{margin-bottom:0}blockquote{border-left:4px solid #DDD;padding:0 15px;color:#777}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}table{border-collapse:collapse;border-spacing:0;font-size:100%;font:inherit}table th{font-weight:bold;border:1px solid #ccc;padding:6px 13px}table td{border:1px solid #ccc;padding:6px 13px}table tr{border-top:1px solid #ccc;background-color:#fff}table tr:nth-child(2n){background-color:#f8f8f8}img{max-width:100%}code,tt{margin:0 2px;padding:0 5px;white-space:nowrap;border:1px solid #eaeaea;background-color:#f8f8f8;border-radius:3px;font-family:Consolas,'Liberation Mono',Courier,monospace;font-size:12px;color:#333}pre>code{margin:0;padding:0;white-space:pre;border:0;background:transparent}.highlight pre{background-color:#f8f8f8;border:1px solid #ccc;font-size:13px;line-height:19px;overflow:auto;padding:6px 10px;border-radius:3px}pre{background-color:#f8f8f8;border:1px solid #ccc;font-size:13px;line-height:19px;overflow:auto;padding:6px 10px;border-radius:3px}pre code,pre tt{background-color:transparent;border:0}.poetry pre{font-family:Georgia,Garamond,serif!important;font-style:italic;font-size:110%!important;line-height:1.6em;display:block;margin-left:1em}.poetry pre code{font-family:Georgia,Garamond,serif!important;word-break:break-all;word-break:break-word;-webkit-hyphens:auto;-moz-hyphens:auto;hyphens:auto;white-space:pre-wrap}sup,sub,a.footnote{font-size:1.4ex;height:0;line-height:1;vertical-align:super;position:relative}sub{vertical-align:sub;top:-1px}@media print{body{background:#fff}img,pre,blockquote,table,figure{page-break-inside:avoid}body{background:#fff;border:0}code{background-color:#fff;color:#333!important;padding:0 .2em;border:1px solid #dedede}pre{background:#fff}pre code{background-color:white!important;overflow:visible}}@media screen{body.inverted{color:#eee!important;border-color:#555;box-shadow:none}.inverted body,.inverted hr .inverted p,.inverted td,.inverted li,.inverted h1,.inverted h2,.inverted h3,.inverted h4,.inverted h5,.inverted h6,.inverted th,.inverted .math,.inverted caption,.inverted dd,.inverted dt,.inverted blockquote{color:#eee!important;border-color:#555;box-shadow:none}.inverted td,.inverted th{background:#333}.inverted h2{border-color:#555}.inverted hr{border-color:#777;border-width:1px!important}::selection{background:rgba(157,193,200,0.5)}h1::selection{background-color:rgba(45,156,208,0.3)}h2::selection{background-color:rgba(90,182,224,0.3)}h3::selection,h4::selection,h5::selection,h6::selection,li::selection,ol::selection{background-color:rgba(133,201,232,0.3)}code::selection{background-color:rgba(0,0,0,0.7);color:#eee}code span::selection{background-color:rgba(0,0,0,0.7)!important;color:#eee!important}a::selection{background-color:rgba(255,230,102,0.2)}.inverted a::selection{background-color:rgba(255,230,102,0.6)}td::selection,th::selection,caption::selection{background-color:rgba(180,237,95,0.5)}.inverted{background:#0b2531;background:#252a2a}.inverted body{background:#252a2a}.inverted a{color:#acd1d5}}.highlight .c{color:#998;font-style:italic}.highlight .err{color:#a61717;background-color:#e3d2d2}.highlight .k,.highlight .o{font-weight:bold}.highlight .cm{color:#998;font-style:italic}.highlight .cp{color:#999;font-weight:bold}.highlight .c1{color:#998;font-style:italic}.highlight .cs{color:#999;font-weight:bold;font-style:italic}.highlight .gd{color:#000;background-color:#fdd}.highlight .gd .x{color:#000;background-color:#faa}.highlight .ge{font-style:italic}.highlight .gr{color:#a00}.highlight .gh{color:#999}.highlight .gi{color:#000;background-color:#dfd}.highlight .gi .x{color:#000;background-color:#afa}.highlight .go{color:#888}.highlight .gp{color:#555}.highlight .gs{font-weight:bold}.highlight .gu{color:#800080;font-weight:bold}.highlight .gt{color:#a00}.highlight .kc,.highlight .kd,.highlight .kn,.highlight .kp,.highlight .kr{font-weight:bold}.highlight .kt{color:#458;font-weight:bold}.highlight .m{color:#099}.highlight .s{color:#d14}.highlight .na{color:#008080}.highlight .nb{color:#0086b3}.highlight .nc{color:#458;font-weight:bold}.highlight .no{color:#008080}.highlight .ni{color:#800080}.highlight .ne,.highlight .nf{color:#900;font-weight:bold}.highlight .nn{color:#555}.highlight .nt{color:#000080}.highlight .nv{color:#008080}.highlight .ow{font-weight:bold}.highlight .w{color:#bbb}.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:#099}.highlight .sb,.highlight .sc,.highlight .sd,.highlight .s2,.highlight .se,.highlight .sh,.highlight .si,.highlight .sx{color:#d14}.highlight .sr{color:#009926}.highlight .s1{color:#d14}.highlight .ss{color:#990073}.highlight .bp{color:#999}.highlight .vc,.highlight .vg,.highlight .vi{color:#008080}.highlight .il{color:#099}.highlight .gc{color:#999;background-color:#eaf2f5}.type-csharp .highlight .k,.type-csharp .highlight .kt{color:#00F}.type-csharp .highlight .nf{color:#000;font-weight:normal}.type-csharp .highlight .nc{color:#2b91af}.type-csharp .highlight .nn{color:#000}.type-csharp .highlight .s,.type-csharp .highlight .sc{color:#a31515}
mxt-app-1.27/jni/ 0000775 0000000 0000000 00000000000 12706171405 0013614 5 ustar 00root root 0000000 0000000 mxt-app-1.27/jni/Android.mk 0000664 0000000 0000000 00000000414 12706171405 0015524 0 ustar 00root root 0000000 0000000 LOCAL_PATH := $(call my-dir)
TOP_DIR := $(LOCAL_PATH)/..
GIT_VERSION = `sh -c 'build-aux/version.sh'`
subdirs := $(addprefix $(TOP_DIR)/,$(addsuffix /Android.mk, \
src/libmaxtouch \
src/jni \
src/mxt-app \
lib/libusbdroid \
))
include $(subdirs)
mxt-app-1.27/jni/Application.mk 0000664 0000000 0000000 00000000017 12706171405 0016406 0 ustar 00root root 0000000 0000000 APP_ABI := all
mxt-app-1.27/lib/ 0000775 0000000 0000000 00000000000 12706171405 0013602 5 ustar 00root root 0000000 0000000 mxt-app-1.27/lib/libusbdroid/ 0000775 0000000 0000000 00000000000 12706171405 0016104 5 ustar 00root root 0000000 0000000 mxt-app-1.27/lib/libusbdroid/Android.mk 0000664 0000000 0000000 00000000367 12706171405 0020023 0 ustar 00root root 0000000 0000000 LOCAL_PATH := $(call my-dir)/code/src/LibUSBDroid/jni
include $(CLEAR_VARS)
LOCAL_SRC_FILES := libusb_jni.c core.c descriptor.c io.c sync.c os/linux_usbfs.c
LOCAL_CFLAGS := -fPIC -DPIC
LOCAL_MODULE := libusbdroid
include $(BUILD_STATIC_LIBRARY)
mxt-app-1.27/lib/libusbdroid/code/ 0000775 0000000 0000000 00000000000 12706171405 0017016 5 ustar 00root root 0000000 0000000 mxt-app-1.27/man1/ 0000775 0000000 0000000 00000000000 12706171405 0013670 5 ustar 00root root 0000000 0000000 mxt-app-1.27/man1/README.txt 0000664 0000000 0000000 00000000065 12706171405 0015367 0 ustar 00root root 0000000 0000000 To view man page in build tree, run
man -M . mxt-app
mxt-app-1.27/src/ 0000775 0000000 0000000 00000000000 12706171405 0013623 5 ustar 00root root 0000000 0000000 mxt-app-1.27/src/jni/ 0000775 0000000 0000000 00000000000 12706171405 0014403 5 ustar 00root root 0000000 0000000 mxt-app-1.27/src/jni/Android.mk 0000664 0000000 0000000 00000000464 12706171405 0016320 0 ustar 00root root 0000000 0000000 LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CFLAGS += -DMXT_VERSION=\"$(GIT_VERSION)\"
LOCAL_C_INCLUDES += $(TOP_DIR)/src
LOCAL_SRC_FILES := jniinterface.c
LOCAL_LDLIBS := -llog
LOCAL_STATIC_LIBRARIES := maxtouch libusbdroid
LOCAL_MODULE := libmaxtouch-jni
include $(BUILD_SHARED_LIBRARY)
mxt-app-1.27/src/jni/com_atmel_Maxtouch_MaxtouchJni.h 0000664 0000000 0000000 00000005642 12706171405 0022704 0 ustar 00root root 0000000 0000000 /* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class com_atmel_Maxtouch_MaxtouchJni */
#ifndef _Included_com_atmel_Maxtouch_MaxtouchJni
#define _Included_com_atmel_Maxtouch_MaxtouchJni
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_atmel_Maxtouch_MaxtouchJni
* Method: Scan
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_Scan
(JNIEnv *, jobject);
/*
* Class: com_atmel_Maxtouch_MaxtouchJni
* Method: GetInfo
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_GetInfo
(JNIEnv *, jobject);
/*
* Class: com_atmel_Maxtouch_MaxtouchJni
* Method: GetSysfsDirectory
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_GetSysfsDirectory
(JNIEnv *, jobject);
/*
* Class: com_atmel_Maxtouch_MaxtouchJni
* Method: GetDebugMessages
* Signature: ()[Ljava/lang/String;
*/
JNIEXPORT jobjectArray JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_GetDebugMessages
(JNIEnv *, jobject);
/*
* Class: com_atmel_Maxtouch_MaxtouchJni
* Method: ReadRegister
* Signature: (II)[B
*/
JNIEXPORT jbyteArray JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_ReadRegister
(JNIEnv *, jobject, jint, jint);
/*
* Class: com_atmel_Maxtouch_MaxtouchJni
* Method: WriteRegister
* Signature: (I[B)I
*/
JNIEXPORT jint JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_WriteRegister
(JNIEnv *, jobject, jint, jbyteArray);
/*
* Class: com_atmel_Maxtouch_MaxtouchJni
* Method: SetDebugEnable
* Signature: (Z)I
*/
JNIEXPORT jint JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_SetDebugEnable
(JNIEnv *, jobject, jboolean);
/*
* Class: com_atmel_Maxtouch_MaxtouchJni
* Method: GetDebugEnable
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_GetDebugEnable
(JNIEnv *, jobject);
/*
* Class: com_atmel_Maxtouch_MaxtouchJni
* Method: LoadConfigFile
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_LoadConfigFile
(JNIEnv *, jobject, jstring);
/*
* Class: com_atmel_Maxtouch_MaxtouchJni
* Method: SaveConfigFile
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_SaveConfigFile
(JNIEnv *, jobject, jstring);
/*
* Class: com_atmel_Maxtouch_MaxtouchJni
* Method: BackupConfig
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_BackupConfig
(JNIEnv *, jobject);
/*
* Class: com_atmel_Maxtouch_MaxtouchJni
* Method: ResetChip
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_ResetChip
(JNIEnv *, jobject);
/*
* Class: com_atmel_Maxtouch_MaxtouchJni
* Method: CalibrateChip
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_CalibrateChip
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
mxt-app-1.27/src/jni/jniinterface.c 0000664 0000000 0000000 00000020500 12706171405 0017205 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file jniinterface.c
/// \brief JNI functions for libmaxtouch
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include "com_atmel_Maxtouch_MaxtouchJni.h"
#include "jni.h"
#include "libmaxtouch/libmaxtouch.h"
#include
struct libmaxtouch_ctx *ctx;
struct mxt_conn_info *conn;
struct mxt_device *mxt;
//******************************************************************************
/// \brief JNI initialisation function
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
JNIEnv *env;
if ( (*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_4) )
return JNI_ERR;
return JNI_VERSION_1_4;
}
//******************************************************************************
/// \brief Scan for device
/// \return device found true/false
JNIEXPORT jboolean JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_Scan
(JNIEnv *env, jobject this)
{
int ret;
ret = mxt_new(&ctx);
if (ret)
return JNI_FALSE;
// Enable logging
mxt_set_log_fn(ctx, mxt_log_android);
mxt_set_log_level(ctx, 4);
mxt_info(ctx, "libmaxtouch %s", MXT_VERSION);
ret = mxt_scan(ctx, &conn, false);
if (ret)
{
return JNI_FALSE;
}
ret = mxt_new_device(ctx, conn, &mxt);
if (ret)
return JNI_FALSE;
return JNI_TRUE;
}
//******************************************************************************
/// \brief Read info block
/// \return success true/false
JNIEXPORT jboolean JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_GetInfo
(JNIEnv *env, jobject this)
{
int ret;
ret = mxt_get_info(mxt);
return (ret == MXT_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
//******************************************************************************
/// \brief Read registers from MXT chip
JNIEXPORT jbyteArray JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_ReadRegister
( JNIEnv *env, jobject this, jint start_register, jint count)
{
int ret;
unsigned char* buf;
jbyteArray jb = 0;
buf = (unsigned char *)calloc(count, sizeof(unsigned char));
if (buf == NULL)
return NULL;
ret = mxt_read_register(mxt, buf, start_register, count);
if (ret == MXT_SUCCESS)
{
jb=(*env)->NewByteArray(env, count);
(*env)->SetByteArrayRegion(env, jb, 0, count, buf);
}
free(buf);
return jb;
}
//******************************************************************************
/// \brief Write registers to MXT chip
JNIEXPORT jint JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_WriteRegister
(JNIEnv *env, jobject this, jint start_register, jbyteArray data)
{
int ret;
int count;
unsigned char *buf;
/* transfer contents of byte array into buffer */
count=(*env)->GetArrayLength(env, data);
buf = (unsigned char *)calloc(count, sizeof(unsigned char));
if (buf == NULL)
return -1;
(*env)->GetByteArrayRegion(env, data, 0, count, buf);
ret = mxt_write_register(mxt, buf, start_register, count);
free(buf);
return ret;
}
//******************************************************************************
/// \brief Enable/disable debug output
JNIEXPORT jint JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_SetDebugEnable
(JNIEnv *env, jobject this, jboolean debugState)
{
bool bDebugState;
bDebugState = debugState == JNI_TRUE ? true : false;
return mxt_set_debug(mxt, bDebugState);
}
//******************************************************************************
/// \brief Get debug state
JNIEXPORT jboolean JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_GetDebugEnable
(JNIEnv *end, jobject this)
{
bool bDebugState;
int ret;
ret = mxt_get_debug(mxt, &bDebugState);
return (bDebugState == true) ? JNI_TRUE : JNI_FALSE;
}
//******************************************************************************
/// \brief Load config file
JNIEXPORT jint JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_LoadConfigFile
(JNIEnv *env, jobject this, jstring filename)
{
const char *szFilename = (*env)->GetStringUTFChars(env, filename, 0);
int ret;
ret = mxt_load_config_file(mxt, szFilename);
(*env)->ReleaseStringUTFChars(env, filename, szFilename);
return ret;
}
//******************************************************************************
/// \brief Save Config File
JNIEXPORT jint JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_SaveConfigFile
(JNIEnv *env, jobject this, jstring filename)
{
const char *szFilename = (*env)->GetStringUTFChars(env, filename, 0);
int ret;
ret = mxt_save_config_file(mxt, szFilename);
(*env)->ReleaseStringUTFChars(env, filename, szFilename);
return ret;
}
//******************************************************************************
/// \brief Get debug messages
/// \return Array of java string objects
JNIEXPORT jobjectArray JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_GetDebugMessages
(JNIEnv *env, jobject this)
{
int count, i, ret;
jobjectArray stringarray;
jclass stringClass;
char *szMessage;
ret = mxt_get_msg_count(mxt, &count);
/* suppress error and return empty array */
if (ret)
count = 0;
// Create JNI array of strings to return
stringClass = NULL;
stringClass = (*env)->FindClass(env, "java/lang/String");
stringarray= (*env)->NewObjectArray(env, count, stringClass, NULL);
if (count > 0)
{
for (i = 0; i < count; i++)
{
szMessage = mxt_get_msg_string(mxt);
(*env)->SetObjectArrayElement(env, stringarray, i,
(*env)->NewStringUTF(env, szMessage));
}
}
return stringarray;
}
//******************************************************************************
/// \brief Get location of interface in sysfs
/// \return directory path
JNIEXPORT jstring JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_GetSysfsDirectory
(JNIEnv *env, jobject this)
{
jclass stringClass;
jstring sysfsLocation;
char *szLocation;
szLocation = (char *)sysfs_get_directory(mxt);
stringClass = NULL;
stringClass = (*env)->FindClass(env, "java/lang/String");
sysfsLocation = (*env)->NewStringUTF(env, szLocation);
return sysfsLocation;
}
//******************************************************************************
/// \brief Backup configuration to non-volatile memory
/// \return Zero on success, or negative error
JNIEXPORT jint JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_BackupConfig
(JNIEnv *env, jobject this)
{
return mxt_backup_config(mxt, BACKUPNV_COMMAND);
}
//******************************************************************************
/// \brief Reset chip
/// \return Zero on success, or negative error
JNIEXPORT jint JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_ResetChip
(JNIEnv *env, jobject this)
{
return mxt_reset_chip(mxt, false);
}
//******************************************************************************
/// \brief Calibrate chip
/// \return Zero on success, or negative error
JNIEXPORT jint JNICALL Java_com_atmel_Maxtouch_MaxtouchJni_CalibrateChip
(JNIEnv *env, jobject this)
{
return mxt_calibrate_chip(mxt);
}
mxt-app-1.27/src/libmaxtouch/ 0000775 0000000 0000000 00000000000 12706171405 0016142 5 ustar 00root root 0000000 0000000 mxt-app-1.27/src/libmaxtouch/Android.mk 0000664 0000000 0000000 00000000771 12706171405 0020060 0 ustar 00root root 0000000 0000000 LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := $(TOP_DIR)/src $(TOP_DIR)/lib/libusbdroid/code/src
LOCAL_CFLAGS += -DHAVE_LIBUSB -DMXT_VERSION=\"$(GIT_VERSION)\"
LOCAL_SRC_FILES := \
libmaxtouch.c \
log.c \
msg.c \
config.c \
utilfuncs.c \
info_block.c \
sysfs/sysfs_device.c \
sysfs/dmesg.c \
i2c_dev/i2c_dev_device.c \
hidraw/hidraw_device.c \
usb/usb_device.c
LOCAL_MODULE := maxtouch
LOCAL_STATIC_LIBRARIES := libusbdroid
include $(BUILD_STATIC_LIBRARY)
mxt-app-1.27/src/libmaxtouch/config.c 0000664 0000000 0000000 00000066636 12706171405 0017574 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file config.c
/// \brief Configuration file handling
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2012 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include "libmaxtouch.h"
#include "info_block.h"
#include "utilfuncs.h"
#include "msg.h"
#define OBP_RAW_MAGIC "OBP_RAW V1"
//******************************************************************************
/// \brief Config file types
enum mxt_config_type {
CONFIG_RAW,
CONFIG_XCFG
};
//******************************************************************************
/// \brief Configuration data for a single object
struct mxt_object_config {
uint32_t type;
uint8_t instance;
uint32_t size;
uint16_t start_position;
uint8_t *data;
struct mxt_object_config *next;
};
//******************************************************************************
/// \brief Device configuration
struct mxt_config {
struct mxt_id_info id;
struct mxt_object_config *head;
uint32_t info_crc;
uint32_t config_crc;
enum mxt_config_type config_type;
};
//******************************************************************************
/// \brief Determines whether the object type is used for CRC checksum calculation
/// \return True if used, false if not
static bool is_type_used_for_crc(const uint32_t type)
{
switch (type) {
case GEN_MESSAGEPROCESSOR_T5:
case GEN_COMMANDPROCESSOR_T6:
case DEBUG_DIAGNOSTIC_T37:
case SPT_USERDATA_T38:
case SPT_MESSAGECOUNT_T44:
case SERIAL_DATA_COMMAND_T68:
return false;
default:
return true;
}
}
//******************************************************************************
/// \brief Some objects are volatile or read-only and should not be saved to config file
static bool mxt_object_is_volatile(uint16_t object_type)
{
switch (object_type) {
case DEBUG_DELTAS_T2:
case DEBUG_REFERENCES_T3:
case DEBUG_SIGNALS_T4:
case GEN_MESSAGEPROCESSOR_T5:
case GEN_COMMANDPROCESSOR_T6:
case SPT_MESSAGECOUNT_T44:
case GEN_DATASOURCE_T53:
return true;
default:
return false;
}
}
//******************************************************************************
/// \brief Free memory associated with configuration
static void mxt_free_config(struct mxt_config *cfg)
{
struct mxt_object_config **curr = &cfg->head;
struct mxt_object_config *next = cfg->head;
while (*curr) {
next = (*curr)->next;
free((*curr)->data);
(*curr)->data = NULL;
free(*curr);
*curr = NULL;
*curr = next;
}
}
//******************************************************************************
/// \brief Write configuration for a single object
static int mxt_write_object_config(struct mxt_device *mxt,
const struct mxt_object_config *objcfg)
{
uint8_t obj_buf[MXT_OBJECT_SIZE_MAX];
uint16_t obj_addr;
uint16_t device_size;
uint16_t num_bytes;
int ret;
if (mxt_object_is_volatile(objcfg->type))
return MXT_ERROR_OBJECT_IS_VOLATILE;
obj_addr = mxt_get_object_address(mxt, objcfg->type, objcfg->instance);
if (obj_addr == OBJECT_NOT_FOUND)
return MXT_ERROR_OBJECT_NOT_FOUND;
/* Read object config. This is done to retain any device configuration
* remaining in trailing bytes not specified in the file. */
memset(obj_buf, 0, sizeof(obj_buf));
ret = mxt_read_register(mxt, obj_buf, obj_addr,
mxt_get_object_size(mxt, objcfg->type));
if (ret)
return ret;
device_size = mxt_get_object_size(mxt, objcfg->type);
if (device_size > objcfg->size) {
mxt_warn(mxt->ctx, "Extending config by %d bytes in T%u",
device_size - objcfg->size, objcfg->type);
num_bytes = objcfg->size;
} else if (objcfg->size > device_size) {
/* Either we are in fallback mode due to wrong
* config or config from a later fw version,
* or the file is corrupt or hand-edited */
mxt_warn(mxt->ctx, "Discarding %u bytes in T%u",
objcfg->size - device_size, objcfg->type);
num_bytes = device_size;
} else {
num_bytes = device_size;
}
/* Update bytes from config */
memcpy(obj_buf, objcfg->data, num_bytes);
/* Write object */
ret = mxt_write_register(mxt, obj_buf, obj_addr, device_size);
if (ret) {
mxt_err(mxt->ctx, "Config write error, ret=%d", ret);
return ret;
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Write configuration to chip
static int mxt_write_device_config(struct mxt_device *mxt,
struct mxt_config *cfg)
{
struct mxt_object_config *objcfg = cfg->head;
int ret;
/* The Info Block CRC is calculated over mxt_id_info and the object table
* If it does not match then we are trying to load the configuration
* from a different chip or firmware version, so the configuration CRC
* is invalid anyway. */
if (cfg->info_crc && cfg->info_crc != mxt->info.crc)
mxt_warn(mxt->ctx, "Info Block CRC mismatch - device=0x%06X "
"file=0x%06X - attempting to apply config",
mxt->info.crc, cfg->info_crc);
mxt_info(mxt->ctx, "Writing config to chip");
while (objcfg) {
mxt_verb(mxt->ctx, "T%d instance %d size %d",
objcfg->type, objcfg->instance, objcfg->size);
ret = mxt_write_object_config(mxt, objcfg);
if (ret == MXT_ERROR_OBJECT_NOT_FOUND)
mxt_warn(mxt->ctx, "T%d not present", objcfg->type);
else if (ret == MXT_ERROR_OBJECT_IS_VOLATILE)
mxt_warn(mxt->ctx, "Skipping volatile T%d", objcfg->type);
else if (ret)
return ret;
objcfg = objcfg->next;
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Read configuration from chip
static int mxt_read_device_config(struct mxt_device *mxt,
struct mxt_config *cfg)
{
int obj_idx, instance;
int ret;
/* Copy ID information */
memcpy(&cfg->id, mxt->info.id, sizeof(struct mxt_id_info));
cfg->info_crc = mxt->info.crc;
cfg->config_crc = mxt_get_config_crc(mxt);
struct mxt_object_config **curr = &cfg->head;
for (obj_idx = 0; obj_idx < mxt->info.id->num_objects; obj_idx++) {
struct mxt_object object = mxt->info.objects[obj_idx];
if (mxt_object_is_volatile(object.type))
continue;
for (instance = 0; instance < MXT_INSTANCES(object); instance++) {
struct mxt_object_config *objcfg = calloc(1, sizeof(struct mxt_object_config));
if (!objcfg) {
ret = MXT_ERROR_NO_MEM;
goto free;
}
objcfg->type = object.type;
objcfg->size = MXT_SIZE(object);
objcfg->instance = instance;
objcfg->start_position = mxt_get_start_position(object, instance);
/* Malloc memory to store configuration */
objcfg->data = calloc(objcfg->size, sizeof(uint8_t));
if (!objcfg->data) {
free(objcfg);
mxt_err(mxt->ctx, "Failed to allocate memory");
ret = MXT_ERROR_NO_MEM;
goto free;
}
ret = mxt_read_register(mxt, objcfg->data,
objcfg->start_position, objcfg->size);
if (ret) {
free(objcfg->data);
free(objcfg);
goto free;
}
*curr = objcfg;
curr = &objcfg->next;
}
}
mxt_info(mxt->ctx, "Read config from device");
return MXT_SUCCESS;
free:
mxt_free_config(cfg);
return ret;
}
//******************************************************************************
/// \brief Save configuration to OBP_RAW file
/// \return #mxt_rc
static int mxt_save_raw_file(struct libmaxtouch_ctx *ctx,
const char *filename,
struct mxt_config *cfg)
{
struct mxt_id_info *id = &cfg->id;
struct mxt_object_config *objcfg = cfg->head;
FILE *fp;
int ret;
unsigned int i;
fp = fopen(filename, "w");
if (fp == NULL) {
mxt_err(ctx, "Error opening %s: %s", filename, strerror(errno));
return mxt_errno_to_rc(errno);
}
ret = fprintf(fp, "OBP_RAW V1\n");
if (ret < 0)
goto fprintf_error;
ret = fprintf(fp, "%02X %02X %02X %02X %02X %02X %02X\n"
"%06X\n"
"%06X\n",
id->family, id->variant,
id->version, id->build,
id->matrix_x_size, id->matrix_y_size,
id->num_objects,
cfg->info_crc, cfg->config_crc);
if (ret < 0)
goto fprintf_error;
while (objcfg) {
if (mxt_object_is_volatile(objcfg->type))
continue;
ret = fprintf(fp, "%04X %04X %04X", objcfg->type, objcfg->instance, objcfg->size);
if (ret < 0)
goto fprintf_error;
for (i = 0; i < objcfg->size; i++) {
ret = fprintf(fp, " %02X", objcfg->data[i]);
if (ret < 0)
goto fprintf_error;
}
ret = fprintf(fp, "\n");
if (ret < 0)
goto fprintf_error;
objcfg = objcfg->next;
}
fclose(fp);
mxt_info(ctx, "Saved config to %s in OBP_RAW format", filename);
return MXT_SUCCESS;
fprintf_error:
fclose(fp);
return mxt_errno_to_rc(errno);
}
//******************************************************************************
/// \brief Save configuration to .xcfg file
/// \return #mxt_rc
static int mxt_save_xcfg_file(struct libmaxtouch_ctx *ctx,
const char *filename,
struct mxt_config *cfg)
{
struct mxt_id_info *id = &cfg->id;
struct mxt_object_config *objcfg = cfg->head;
FILE *fp;
int ret;
unsigned int i;
fp = fopen(filename, "w");
if (fp == NULL) {
mxt_err(ctx, "Error opening %s: %s", filename, strerror(errno));
return mxt_errno_to_rc(errno);
}
ret = fprintf(fp, "[COMMENTS]\nDate and time: ");
if (ret < 0)
goto fprintf_error;
ret = mxt_print_timestamp(fp, true);
if (ret) {
fclose(fp);
return ret;
}
ret = fprintf(fp, "\n"
"[VERSION_INFO_HEADER]\n"
"FAMILY_ID=%d\n"
"VARIANT=%d\n"
"VERSION=%d\n"
"BUILD=%d\n"
"CHECKSUM=0x%06X\n"
"INFO_BLOCK_CHECKSUM=0x%02X\n"
"[APPLICATION_INFO_HEADER]\n"
"NAME=libmaxtouch\n"
"VERSION=%s\n",
id->family, id->variant,
id->version, id->build,
cfg->config_crc, cfg->info_crc,
MXT_VERSION);
if (ret < 0)
goto fprintf_error;
while (objcfg) {
if (mxt_object_is_volatile(objcfg->type))
continue;
const char *obj_name = mxt_get_object_name(objcfg->type);
if (obj_name) {
ret = fprintf(fp, "[%s INSTANCE %d]\n", obj_name, objcfg->instance);
if (ret < 0)
goto fprintf_error;
} else {
ret = fprintf(fp, "[UNKNOWN_T%d INSTANCE %d]\n", objcfg->type, objcfg->instance);
if (ret < 0)
goto fprintf_error;
}
ret = fprintf(fp, "OBJECT_ADDRESS=%d\n"
"OBJECT_SIZE=%d\n",
objcfg->start_position,
objcfg->size);
if (ret < 0)
goto fprintf_error;
for (i = 0; i < objcfg->size; i++) {
ret = fprintf(fp, "%d 1 UNKNOWN[%d]=%d\n", i, i, objcfg->data[i]);
if (ret < 0)
goto fprintf_error;
}
objcfg = objcfg->next;
}
fclose(fp);
ret = MXT_SUCCESS;
mxt_info(ctx, "Saved config to %s in .xcfg format", filename);
return MXT_SUCCESS;
fprintf_error:
fclose(fp);
return mxt_errno_to_rc(errno);
}
//******************************************************************************
/// \brief Load configuration from .xcfg file
/// \return #mxt_rc
static int mxt_load_xcfg_file(struct libmaxtouch_ctx *ctx, const char *filename,
struct mxt_config *cfg)
{
FILE *fp;
int c;
char object[255];
char tmp[255];
char *substr;
int object_id;
int instance;
int object_address;
int object_size;
int data;
int file_read = 0;
bool ignore_line = false;
int ret;
struct mxt_object_config **next = &cfg->head;
struct mxt_object_config *objcfg;
cfg->config_type = CONFIG_XCFG;
fp = fopen(filename, "r");
if (fp == NULL) {
mxt_err(ctx, "Error opening %s: %s", filename, strerror(errno));
return mxt_errno_to_rc(errno);
}
while (!file_read) {
/* First character is expected to be '[' - skip empty lines and spaces */
c = getc(fp);
while ((c == '\n') || (c == '\r') || (c == 0x20))
c = getc(fp);
if (c != '[') {
if (c == EOF)
break;
/* If we are ignoring the current section then look for the next section */
if (ignore_line) {
continue;
}
mxt_err(ctx, "Parse error: expected '[', read ascii char %c!", c);
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
if (fscanf(fp, "%[^] ]", object) != 1) {
mxt_err(ctx, "Object parse error");
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
/* Ignore the comments and file header sections */
if (!strcmp(object, "COMMENTS")
|| !strcmp(object, "APPLICATION_INFO_HEADER")) {
ignore_line = true;
mxt_dbg(ctx, "Skipping %s", object);
continue;
}
ignore_line = false;
/* Extract the checksum */
if (!strcmp(object, "VERSION_INFO_HEADER")) {
while (false == ignore_line) {
if (fscanf(fp, "%s", tmp) != 1) {
mxt_err(ctx, "Version info header parse error");
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
if (!strncmp(tmp, "CHECKSUM", 8)) {
sscanf(tmp, "%[^'=']=%x", object, &cfg->config_crc);
mxt_dbg(ctx, "Config CRC from file: %s", tmp);
ignore_line = true;
}
}
continue;
}
if (fscanf(fp, "%s", tmp) != 1) {
mxt_err(ctx, "Instance parse error");
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
if (strcmp(tmp, "INSTANCE")) {
mxt_err(ctx, "Parse error, expected INSTANCE, got %s", tmp);
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
if (fscanf(fp, "%d", &instance) != 1) {
mxt_err(ctx, "Instance number parse error");
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
/* Read rest of header section */
while(c != ']') {
c = getc(fp);
if (c == '\n') {
mxt_err(ctx, "Parse error, expected ] before end of line");
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
}
while(c != '\n')
c = getc(fp);
while ((c != '=') && (c != EOF))
c = getc(fp);
if (fscanf(fp, "%d", &object_address) != 1) {
mxt_err(ctx, "Object address parse error");
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
c = getc(fp);
while((c != '=') && (c != EOF))
c = getc(fp);
if (fscanf(fp, "%d", &object_size) != 1) {
mxt_err(ctx, "Object size parse error");
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
c = getc(fp);
/* Find object type ID number at end of object string */
substr = strrchr(object, '_');
if (substr == NULL || (*(substr + 1) != 'T')) {
mxt_err(ctx, "Parse error, could not find T number in %s", object);
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
if (sscanf(substr + 2, "%d", &object_id) != 1) {
mxt_err(ctx, "Unable to get object type ID for %s", object);
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
mxt_dbg(ctx, "%s T%u OBJECT_ADDRESS=%d OBJECT_SIZE=%d",
object, object_id, object_address, object_size);
objcfg = calloc(1, sizeof(struct mxt_object_config));
if (!objcfg) {
ret = MXT_ERROR_NO_MEM;
goto close;
}
objcfg->type = object_id;
objcfg->size = object_size;
objcfg->instance = instance;
objcfg->start_position = object_address;
*next = objcfg;
next = &objcfg->next;
/* Allocate memory to store configuration */
objcfg->data = calloc(object_size, sizeof(uint8_t));
if (!objcfg->data) {
mxt_err(ctx, "Failed to allocate memory");
ret = MXT_ERROR_NO_MEM;
goto close;
}
while (true) {
int offset;
int width;
/* Find next line, check first character valid and rewind */
c = getc(fp);
while((c == '\n') || (c == '\r') || (c == 0x20))
c = getc(fp);
fseek(fp, -1, SEEK_CUR);
/* End of object */
if (c == '[')
break;
/* End of file */
if (c == EOF)
break;
/* Read address */
if (fscanf(fp, "%d", &offset) != 1) {
mxt_err(ctx, "Address parse error");
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
/* Read byte count of this register (max 2) */
if (fscanf(fp, "%d", &width) != 1) {
mxt_err(ctx, "Byte count parse error");
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
while((c != '=') && (c != EOF)) {
c = getc(fp);
}
if (fscanf(fp, "%d", &data) != 1) {
mxt_err(ctx, "Data parse error");
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
c = getc(fp);
switch (width) {
case 1:
objcfg->data[offset] = (char) data;
break;
case 2:
objcfg->data[offset] = (char) data & 0xFF;
objcfg->data[offset + 1] = (char) ((data >> 8) & 0xFF);
break;
case 4:
objcfg->data[offset] = (char) data & 0xFF;
objcfg->data[offset + 1] = (char) ((data >> 8) & 0xFF);
objcfg->data[offset + 2] = (char) ((data >> 16) & 0xFF);
objcfg->data[offset + 3] = (char) ((data >> 24) & 0xFF);
break;
default:
mxt_err(ctx, "Only 1, 2 and 4 byte config values are supported");
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
}
}
ret = MXT_SUCCESS;
mxt_info(ctx, "Configuration read from %s in XCFG format", filename);
close:
fclose(fp);
return ret;
}
//******************************************************************************
/// \brief Load configuration from RAW file
// \return #mxt_rc
static int mxt_load_raw_file(struct libmaxtouch_ctx *ctx, const char *filename,
struct mxt_config *cfg)
{
FILE *fp;
int ret;
size_t i;
char line[2048];
struct mxt_object_config **next;
struct mxt_object_config *objcfg;
cfg->config_type = CONFIG_RAW;
fp = fopen(filename, "r");
if (fp == NULL) {
mxt_err(ctx, "Error opening %s: %s", filename, strerror(errno));
return mxt_errno_to_rc(errno);
}
if (fgets(line, sizeof(line), fp) == NULL) {
mxt_err(ctx, "Unexpected EOF");
}
if (strncmp(line, OBP_RAW_MAGIC, strlen(OBP_RAW_MAGIC))) {
mxt_warn(ctx, "Not in OBP_RAW format");
ret = MXT_ERROR_FILE_FORMAT;
goto close;
} else {
mxt_dbg(ctx, "Loading OBP_RAW file");
}
/* Load information block and check */
for (i = 0; i < sizeof(struct mxt_id_info); i++) {
ret = fscanf(fp, "%hhx", (unsigned char *)&cfg->id + i);
if (ret != 1) {
mxt_err(ctx, "Bad format");
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
}
/* Read CRCs */
ret = fscanf(fp, "%x", &cfg->info_crc);
if (ret != 1) {
mxt_err(ctx, "Bad format: failed to parse Info CRC");
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
ret = fscanf(fp, "%x", &cfg->config_crc);
if (ret != 1) {
mxt_err(ctx, "Bad format: failed to parse Config CRC");
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
next = &cfg->head;
while (true) {
objcfg = calloc(1, sizeof(struct mxt_object_config));
if (!objcfg) {
ret = MXT_ERROR_NO_MEM;
goto close;
}
/* Read type, instance, length */
ret = fscanf(fp, "%x %" SCNx8 " %x",
&objcfg->type, &objcfg->instance, &objcfg->size);
if (ret == EOF) {
free(objcfg);
break;
} else if (ret != 3) {
mxt_err(ctx, "Bad format: failed to parse object");
free(objcfg);
ret = MXT_ERROR_FILE_FORMAT;
goto close;
}
mxt_dbg(ctx, "OBP_RAW T%u instance %u", objcfg->type, objcfg->instance);
*next = objcfg;
next = &objcfg->next;
/* Malloc memory to store configuration */
objcfg->data = calloc(objcfg->size, sizeof(uint8_t));
if (!objcfg->data) {
mxt_err(ctx, "Failed to allocate memory");
ret = MXT_ERROR_NO_MEM;
goto close;
}
/* Read bytes from file */
for (i = 0; i < objcfg->size; i++) {
uint8_t val;
ret = fscanf(fp, "%hhx", &val);
if (ret != 1) {
mxt_err(ctx, "Parse error in T%d", objcfg->type);
ret = MXT_ERROR_FILE_FORMAT;
free(objcfg->data);
goto close;
}
*(objcfg->data + i) = val;
}
mxt_log_buffer(ctx, LOG_DEBUG, "CFG:", objcfg->data, objcfg->size);
}
ret = MXT_SUCCESS;
mxt_info(ctx, "Configuration read from %s in OBP_RAW format", filename);
close:
fclose(fp);
return ret;
}
//******************************************************************************
/// \brief Get the configuration from file
/// \return #mxt_rc
static int mxt_get_config_from_file(struct libmaxtouch_ctx *ctx,
const char *filename, struct mxt_config *cfg)
{
int ret;
char *extension = strrchr(filename, '.');
if (cfg) {
if (extension && !strcmp(extension, ".xcfg")) {
ret = mxt_load_xcfg_file(ctx, filename, cfg);
if (ret)
return ret;
} else {
ret = mxt_load_raw_file(ctx, filename, cfg);
if (ret)
return ret;
}
} else {
ret = MXT_INTERNAL_ERROR;
mxt_err(ctx, "Config is null");
}
return ret;
}
//******************************************************************************
/// \brief Load configuration from .xcfg or RAW file, automatically detect
// format and write to device
/// \return #mxt_rc
int mxt_load_config_file(struct mxt_device *mxt, const char *filename)
{
struct mxt_config cfg = {{0}};
int ret = mxt_get_config_from_file(mxt->ctx, filename, &cfg);
if (ret == MXT_SUCCESS) {
ret = mxt_write_device_config(mxt, &cfg);
mxt_free_config(&cfg);
}
return ret;
}
//******************************************************************************
/// \brief Save configuration to file
/// \return #mxt_rc
int mxt_save_config_file(struct mxt_device *mxt, const char *filename)
{
int ret;
char *extension = strrchr(filename, '.');
struct mxt_config cfg = {{0}};
ret = mxt_read_device_config(mxt, &cfg);
if (ret)
return ret;
if (extension && !strcmp(extension, ".xcfg"))
ret = mxt_save_xcfg_file(mxt->ctx, filename, &cfg);
else
ret = mxt_save_raw_file(mxt->ctx, filename, &cfg);
mxt_free_config(&cfg);
return ret;
}
//******************************************************************************
/// \brief Zero all configuration settings
/// \return #mxt_rc
int mxt_zero_config(struct mxt_device *mxt)
{
int obj_idx, instance, num_bytes;
uint8_t *buf;
struct mxt_object object;
struct mxt_id_info *id = mxt->info.id;
int ret;
mxt_info(mxt->ctx, "Zeroing all configuration settings...");
/* Single buffer to match MAX object size*/
buf = (uint8_t *)calloc(1, MXT_OBJECT_SIZE_MAX);
if (buf == NULL) {
mxt_err(mxt->ctx, "Failed to allocate memory");
return MXT_ERROR_NO_MEM;
}
for (obj_idx = 0; obj_idx < id->num_objects; obj_idx++) {
object = mxt->info.objects[obj_idx];
num_bytes = MXT_SIZE(object);
for (instance = 0; instance < MXT_INSTANCES(object); instance++) {
int address = mxt_get_start_position(object, instance);
ret = mxt_write_register(mxt, buf, address, num_bytes);
if (ret)
goto free;
}
}
ret = MXT_SUCCESS;
free:
free(buf);
return ret;
}
//******************************************************************************
/// \brief Check the checksum for a given file
/// \return #mxt_rc
int mxt_checkcrc(struct libmaxtouch_ctx *ctx, struct mxt_device *mxt, char *filename)
{
int ret;
struct mxt_config cfg = {{0}};
uint16_t obj_idx = 0;
int start_pos = INT_MAX;
uint16_t end_pos = 0;
/* Get the mxt_config and object configurations */
ret = mxt_get_config_from_file(ctx, filename, &cfg);
if (ret)
goto free;
/* Find limits of CRC region */
struct mxt_object_config *objcfg = cfg.head;
if (mxt == NULL) {
if (cfg.config_type == CONFIG_RAW) {
mxt_err(ctx, "RAW config format only supported with chip present");
ret = MXT_ERROR_NO_DEVICE;
goto free;
} else {
while (objcfg) {
if (is_type_used_for_crc(objcfg->type)) {
if (start_pos > objcfg->start_position)
start_pos = objcfg->start_position;
if (end_pos < (objcfg->start_position + objcfg->size))
end_pos = objcfg->start_position + objcfg->size;
}
objcfg = objcfg->next;
}
}
} else {
for (obj_idx = 0; obj_idx < mxt->info.id->num_objects; obj_idx++) {
struct mxt_object *object = &mxt->info.objects[obj_idx];
if (is_type_used_for_crc(object->type)) {
int sp = mxt_get_object_address(mxt, object->type, 0);
if (start_pos > sp)
start_pos = sp;
int obj_size = mxt_get_object_size(mxt, object->type);
if (end_pos < (sp + obj_size))
end_pos = sp + obj_size;
}
}
}
mxt_verb(ctx, "CRC start_pos:%d end_pos:%d", start_pos, end_pos);
/* Allocate buffer for CRC calculation */
uint8_t *buffer = (uint8_t *)calloc(end_pos, sizeof(uint8_t));
if (!buffer) {
ret = MXT_ERROR_NO_MEM;
mxt_err(ctx, "Could not allocate memory for buffer");
goto free;
}
/* Loop through until all buffers have been read in order */
objcfg = cfg.head;
while (objcfg) {
if (is_type_used_for_crc(objcfg->type)) {
uint16_t off = objcfg->start_position;
if (cfg.config_type != CONFIG_XCFG)
off = mxt_get_object_address(mxt, objcfg->type, objcfg->instance);
memcpy(buffer + off, objcfg->data, objcfg->size);
}
objcfg = objcfg->next;
}
uint32_t calc_crc;
ret = mxt_calculate_crc(ctx, &calc_crc, buffer + start_pos, end_pos - start_pos);
if (calc_crc == cfg.config_crc) {
mxt_info(ctx, "File checksum verified: %d", cfg.config_crc);
ret = MXT_SUCCESS;
} else {
mxt_err(ctx, "Checksum error: calc=%06X file=%06X", calc_crc, cfg.config_crc);
ret = MXT_ERROR_CHECKSUM_MISMATCH;
}
free(buffer);
free:
mxt_free_config(&cfg);
return ret;
}
mxt-app-1.27/src/libmaxtouch/hidraw/ 0000775 0000000 0000000 00000000000 12706171405 0017420 5 ustar 00root root 0000000 0000000 mxt-app-1.27/src/libmaxtouch/hidraw/hidraw_device.c 0000664 0000000 0000000 00000023373 12706171405 0022371 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file hidraw_device.c
/// \brief HIDRAW device support
/// \author Steven Swann
//------------------------------------------------------------------------------
// Copyright 2014 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct mxt_device;
struct mxt_conn_info;
#include "hidraw_device.h"
#include "libmaxtouch/libmaxtouch.h"
#define HIDRAW_CMD_ID 0x51
#define MXT_HID_READ_SUCCESS 0x04
#define MXT_HID_READ_DATA_SIZE 15
#define MXT_HID_WRITE_DATA_SIZE 12
#define MXT_HID_ADDR_SIZE 0x02
#define HIDRAW_WRITE_RETRY_DELAY_US 25000
#define HIDRAW_READ_RETRY_DELAY_US 250
#define HIDRAW_TIMEOUT_DELAY_US 500
struct hid_packet {
uint8_t report_id;
union {
struct {
uint8_t cmd;
uint8_t rx_bytes;
uint8_t tx_bytes;
uint16_t address __attribute__((packed));
uint8_t write_data[MXT_HID_WRITE_DATA_SIZE];
} __attribute__((packed));
struct {
uint8_t result;
uint8_t bytes_read;
uint8_t read_data[MXT_HID_READ_DATA_SIZE];
} __attribute__((packed));
struct {
uint8_t raw_data[18];
} __attribute__((packed));
};
} __attribute__((packed));
//******************************************************************************
/// \brief Register hidraw device
/// \return #mxt_rc
int hidraw_register(struct mxt_device *mxt)
{
mxt_info(mxt->ctx, "Registered hidraw adapter:%s", mxt->conn->hidraw.node );
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Open the hidraw dev interface and set the slave address
/// \return #mxt_rc
static int hidraw_open(struct mxt_device *mxt)
{
char filename[20];
snprintf(filename, sizeof(filename), "%s", mxt->conn->hidraw.node);
mxt->conn->hidraw.fd = open(filename, O_RDWR|O_NONBLOCK);
if (mxt->conn->hidraw.fd < 0) {
mxt_err(mxt->ctx, "Could not open %s, error %s (%d)",
filename, strerror(errno), errno);
return mxt_errno_to_rc(errno);
}
mxt_dbg(mxt->ctx, "Opened %s, fd: %d", filename, mxt->conn->hidraw.fd);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Release device
void hidraw_release(struct mxt_device *mxt)
{
return;
}
//******************************************************************************
/// \brief Write packet to MXT chip
/// \return Number of databytes sent
static int hidraw_write_packet(struct mxt_device *mxt, struct hid_packet *write_pkt, uint8_t *byte_count)
{
int ret;
uint8_t pkt_size = write_pkt->rx_bytes + 4; /* allowing for header */
if ((ret = write(mxt->conn->hidraw.fd, write_pkt, pkt_size)) != pkt_size) {
mxt_verb(mxt->ctx, "HIDRAW retry");
usleep(HIDRAW_WRITE_RETRY_DELAY_US);
if ((ret = write(mxt->conn->hidraw.fd, &write_pkt, pkt_size)) != pkt_size) {
mxt_err(mxt->ctx, "Error %s (%d) writing to hidraw",
strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
}
}
mxt_log_buffer(mxt->ctx, LOG_VERBOSE, "PKT TX:",
(const unsigned char *) write_pkt, pkt_size);
*byte_count = ret - 6;
mxt_dbg(mxt->ctx, "Sending packet: size: %d No. data bytes TX: %d",
pkt_size, *byte_count);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Write read command packet to MXT chip
/// \return #mxt_rc
static int hidraw_write_read_cmd(struct mxt_device *mxt, uint16_t start_register, uint8_t count, uint8_t *byte_count)
{
struct hid_packet cmd_pkt = { 0 };
cmd_pkt.report_id = mxt->conn->hidraw.report_id;
cmd_pkt.cmd = 0x51;
cmd_pkt.rx_bytes = 2; /* includes start address word */
cmd_pkt.tx_bytes = count;
cmd_pkt.address = htole16(start_register);
mxt_dbg(mxt->ctx, "Sending read command");
return hidraw_write_packet(mxt, &cmd_pkt, byte_count);
}
//******************************************************************************
/// \brief Read packet from MXT chip
/// \return #mxt_rc
static int hidraw_read_response(struct mxt_device *mxt, struct hid_packet *read_pkt,
size_t count)
{
ssize_t ret = 0;
size_t t_count = 0;
int timeout = 0;
do {
ret = read(mxt->conn->hidraw.fd, read_pkt + t_count, count);
if ((size_t)ret != count) {
mxt_dbg(mxt->ctx, "Error %s (%d) reading from hidraw",
strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
} else {
t_count += (size_t)ret;
}
usleep(HIDRAW_READ_RETRY_DELAY_US);
} while (timeout++ <= HIDRAW_TIMEOUT_DELAY_US && t_count != count);
mxt_dbg(mxt->ctx, "No. bytes requested: %zu, No. of bytes read: %zu",
count, t_count);
mxt_log_buffer(mxt->ctx, LOG_VERBOSE, "RD PKT RX:",
(const unsigned char *) read_pkt, count);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Read packet from MXT chip
/// \return #mxt_rc
static int hidraw_read_packet(struct mxt_device *mxt, struct hid_packet *read_pkt,
uint16_t start_register, size_t count)
{
int pkt_count = count + 3;
int ret = 0;
uint8_t byte_count = 0;
ret = hidraw_write_read_cmd(mxt, start_register, count, &byte_count);
if (ret)
return ret;
ret = hidraw_read_response(mxt, read_pkt, pkt_count);
if (ret < 0)
return ret;
return ret - 3;
}
//******************************************************************************
/// \brief Read register from MXT chip
/// \return #mxt_rc
int hidraw_read_register(struct mxt_device *mxt, unsigned char *buf,
uint16_t start_register, size_t count,
size_t *bytes_transferred)
{
int ret;
struct hid_packet read_pkt = { 0 };
mxt_dbg(mxt->ctx, "%s - start_register:%d No. bytes requested:%zu",
__func__, start_register, count);
ret = hidraw_open(mxt);
if (ret)
return ret;
size_t bytes_read = 0;
while (bytes_read < count) {
ret = hidraw_read_packet(mxt, &read_pkt,
start_register + bytes_read,
(count - bytes_read <= MXT_HID_READ_DATA_SIZE ? count - bytes_read : MXT_HID_READ_DATA_SIZE));
if (ret < 0) {
mxt_dbg(mxt->ctx, "read error %s (%d)", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
}
memcpy(buf + bytes_read, read_pkt.read_data, ret);
bytes_read += ret;
}
*bytes_transferred = bytes_read;
close(mxt->conn->hidraw.fd);
mxt->conn->hidraw.fd = 0;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Write register from MXT chip
/// \return #mxt_rc
int hidraw_write_register(struct mxt_device *mxt, unsigned char const *val, uint16_t start_register, int datalength)
{
int ret;
uint8_t byte_count;
struct hid_packet write_pkt;
memset(&write_pkt, 0x00, sizeof(struct hid_packet));
write_pkt.report_id = mxt->conn->hidraw.report_id;
write_pkt.cmd = 0x51;
write_pkt.tx_bytes = 0;
mxt_dbg(mxt->ctx, "%s - start_register:%d No. bytes to write:%d",
__func__, start_register, datalength);
ret = hidraw_open(mxt);
if (ret)
return ret;
int bytes_written = 0;
while (bytes_written < datalength) {
write_pkt.rx_bytes = MXT_HID_ADDR_SIZE +
(datalength - bytes_written <= MXT_HID_WRITE_DATA_SIZE ? datalength - bytes_written : MXT_HID_WRITE_DATA_SIZE);
write_pkt.address = htole16(start_register + bytes_written);
memcpy(write_pkt.write_data, val + bytes_written, write_pkt.rx_bytes);
ret = hidraw_write_packet(mxt, &write_pkt, &byte_count);
if (ret) {
mxt_err(mxt->ctx, "read error %s (%d)", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
goto close;
}
bytes_written += byte_count;
mxt_dbg(mxt->ctx, "Bytes Written:%d", bytes_written);
struct hid_packet response_pkt;
memset(&response_pkt, 0x00, sizeof(struct hid_packet));
ret = hidraw_read_response(mxt, &response_pkt, 2);
if (response_pkt.result != MXT_HID_READ_SUCCESS)
mxt_err(mxt->ctx, "HIDRAW write failed: 0x%x",
response_pkt.result);
}
close:
close(mxt->conn->hidraw.fd);
mxt->conn->hidraw.fd = 0;
return MXT_SUCCESS;
}
mxt-app-1.27/src/libmaxtouch/hidraw/hidraw_device.h 0000664 0000000 0000000 00000004371 12706171405 0022373 0 ustar 00root root 0000000 0000000 #pragma once
//------------------------------------------------------------------------------
/// \file hidraw_device.h
/// \brief HIDRAW device support
/// \author Steven Swann
//------------------------------------------------------------------------------
// Copyright 2014 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#define HIDRAW_REPORT_ID 0x06
//******************************************************************************
/// \brief Device information for hidraw-dev backend
struct hidraw_conn_info {
char node[20];
uint8_t report_id;
int fd;
};
int hidraw_register(struct mxt_device *mxt);
int hidraw_read(struct mxt_device *mxt);
int hidraw_read_register(struct mxt_device *mxt, unsigned char *buf, uint16_t start_register, size_t count, size_t *bytes_transferred);
int hidraw_write_register(struct mxt_device *mxt, unsigned char const *val, uint16_t start_register, int datalength);
void hidraw_release(struct mxt_device *mxt);
mxt-app-1.27/src/libmaxtouch/i2c_dev/ 0000775 0000000 0000000 00000000000 12706171405 0017455 5 ustar 00root root 0000000 0000000 mxt-app-1.27/src/libmaxtouch/i2c_dev/i2c_dev_device.c 0000664 0000000 0000000 00000015550 12706171405 0022461 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file i2c_dev_device.c
/// \brief MXT device low level access via i2c-dev interface
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include
struct mxt_device;
struct mxt_conn_info;
#include "i2c_dev_device.h"
#include "libmaxtouch/libmaxtouch.h"
#define I2C_SLAVE_FORCE 0x0706
/* Deep sleep retry delay 25 ms */
#define I2C_RETRY_DELAY 25000
//******************************************************************************
/// \brief Register i2c-dev device
/// \return #mxt_rc
int i2c_dev_open(struct mxt_device *mxt)
{
mxt_info
(
mxt->ctx, "Registered i2c-dev adapter:%d address:0x%x",
mxt->conn->i2c_dev.adapter, mxt->conn->i2c_dev.address
);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Release device
void i2c_dev_release(struct mxt_device *mxt)
{
}
//******************************************************************************
/// \brief Open the i2c dev interface and set the slave address
/// \return #mxt_rc
static int open_and_set_slave_address(struct mxt_device *mxt, int *fd_out)
{
int fd;
int ret;
char filename[20];
snprintf(filename, 19, "/dev/i2c-%d", mxt->conn->i2c_dev.adapter);
fd = open(filename, O_RDWR);
if (fd < 0) {
mxt_err(mxt->ctx, "Could not open %s, error %s (%d)", filename, strerror(errno), errno);
return mxt_errno_to_rc(errno);
}
ret = ioctl(fd, I2C_SLAVE_FORCE, mxt->conn->i2c_dev.address);
if (ret < 0) {
mxt_err(mxt->ctx, "Error setting slave address, error %s (%d)", strerror(errno), errno);
close(fd);
return mxt_errno_to_rc(errno);
}
*fd_out = fd;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Read register from MXT chip
/// \return #mxt_rc
int i2c_dev_read_register(struct mxt_device *mxt, unsigned char *buf,
int start_register, int count, size_t *bytes_read)
{
int fd = -ENODEV;
int ret;
char register_buf[2];
if (count > mxt->ctx->i2c_block_size)
count = mxt->ctx->i2c_block_size;
ret = open_and_set_slave_address(mxt, &fd);
if (ret)
return ret;
register_buf[0] = start_register & 0xff;
register_buf[1] = (start_register >> 8) & 0xff;
if (write(fd, ®ister_buf, 2) != 2) {
mxt_verb(mxt->ctx, "I2C retry");
usleep(I2C_RETRY_DELAY);
if (write(fd, ®ister_buf, 2) != 2) {
mxt_err(mxt->ctx, "Error %s (%d) writing to i2c", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
goto close;
}
}
ssize_t read_rc;
read_rc = read(fd, buf, count);
if (read_rc < 0) {
mxt_err(mxt->ctx, "Error %s (%d) reading from i2c", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
goto close;
} else if (read_rc == 0) {
/* end of file */
ret = MXT_ERROR_IO;
goto close;
} else {
*bytes_read = (size_t)read_rc;
ret = MXT_SUCCESS;
}
close:
close(fd);
return ret;
}
//******************************************************************************
/// \brief Write register to MXT chip
/// \return #mxt_rc
int i2c_dev_write_register(struct mxt_device *mxt, unsigned char const *val,
int start_register, size_t datalength)
{
int fd = -ENODEV;
int count;
int ret;
unsigned char *buf;
ret = open_and_set_slave_address(mxt, &fd);
if (ret)
return ret;
count = datalength + 2;
buf = (unsigned char *)calloc(count, sizeof(unsigned char));
buf[0] = start_register & 0xff;
buf[1] = (start_register >> 8) & 0xff;
memcpy(buf + 2, val, datalength);
if (write(fd, buf, count) != count) {
mxt_verb(mxt->ctx, "I2C retry");
usleep(I2C_RETRY_DELAY);
if (write(fd, buf, count) != count) {
mxt_err(mxt->ctx, "Error %s (%d) writing to i2c", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
} else {
ret = MXT_SUCCESS;
}
} else {
ret = MXT_SUCCESS;
}
free(buf);
close(fd);
return ret;
}
//******************************************************************************
/// \brief Bootloader read
/// \return #mxt_rc
int i2c_dev_bootloader_read(struct mxt_device *mxt, unsigned char *buf, int count)
{
int fd = -ENODEV;
int ret;
ret = open_and_set_slave_address(mxt, &fd);
if (ret)
return ret;
mxt_dbg(mxt->ctx, "Reading %d bytes", count);
if (read(fd, buf, count) != count) {
mxt_err(mxt->ctx, "Error %s (%d) reading from i2c", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
} else {
ret = MXT_SUCCESS;
}
close(fd);
return ret;
}
//******************************************************************************
/// \brief Bootloader write
/// \return #mxt_rc
int i2c_dev_bootloader_write(struct mxt_device *mxt, unsigned char const *buf,
int count, size_t *bytes_read)
{
int fd = -ENODEV;
int ret;
if (count > mxt->ctx->i2c_block_size)
count = mxt->ctx->i2c_block_size;
ret = open_and_set_slave_address(mxt, &fd);
if (ret)
return ret;
mxt_dbg(mxt->ctx, "Writing %d bytes", count);
if (write(fd, buf, count) != count) {
mxt_err(mxt->ctx, "Error %s (%d) writing to i2c", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
} else {
ret = MXT_SUCCESS;
}
*bytes_read = count;
close(fd);
return ret;
}
mxt-app-1.27/src/libmaxtouch/i2c_dev/i2c_dev_device.h 0000664 0000000 0000000 00000005072 12706171405 0022464 0 ustar 00root root 0000000 0000000 #pragma once
//------------------------------------------------------------------------------
/// \file i2c_dev_device.h
/// \brief headers for MXT device low level access via i2c-dev interface
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#define I2C_DEV_MAX_BLOCK 255
//******************************************************************************
/// \brief Device information for i2c-dev backend
struct i2c_dev_conn_info {
int adapter;
int address;
};
//******************************************************************************
/// \brief Device information for i2c-dev backend
struct i2c_dev_device {
};
int i2c_dev_open(struct mxt_device *mxt);
void i2c_dev_release(struct mxt_device *mxt);
int i2c_dev_read_register(struct mxt_device *mxt, unsigned char *buf, int start_register, int count, size_t *bytes_transferred);
int i2c_dev_write_register(struct mxt_device *mxt, unsigned char const *buf, int start_register, size_t count);
int i2c_dev_bootloader_read(struct mxt_device *mxt, unsigned char *buf, int count);
int i2c_dev_bootloader_write(struct mxt_device *mxt, unsigned char const *buf, int count, size_t *bytes_transferred);
mxt-app-1.27/src/libmaxtouch/info_block.c 0000664 0000000 0000000 00000027564 12706171405 0020431 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file info_block.c
/// \brief Functions for accessing the mXT chip's information block.
/// \author Iiro Valkonen
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include "libmaxtouch.h"
/*!
* @brief Information block checksum return function.
* @return 24-bit checksum value in 32-bit integer.
*/
static uint32_t convert_crc(struct mxt_raw_crc *crc)
{
return ((crc->CRC_hi<<16u) | (crc->CRC));
}
/*!
* @brief Checksum algorithm.
* @return Calculated checksum.
*/
static uint32_t crc24(uint32_t crc, uint8_t firstbyte, uint8_t secondbyte)
{
static const uint32_t CRCPOLY = 0x0080001B;
uint32_t result;
uint16_t data_word;
data_word = (uint16_t) ((uint16_t)(secondbyte << 8u) | firstbyte);
result = ((crc << 1u) ^ (uint32_t)data_word);
/* Check if 25th bit is set, and XOR the result to create 24-bit checksum */
if (result & 0x1000000) {
result ^= CRCPOLY;
}
return result;
}
/*!
* @brief Calculate and verify checksum over a region of memory
* @return #mxt_rc
*/
int mxt_calculate_crc(struct libmaxtouch_ctx *ctx, uint32_t *crc_result,
uint8_t *base_addr, size_t size)
{
static const uint32_t MASK_24_BITS = 0x00FFFFFF;
uint32_t calc_crc = 0; /* Calculated checksum */
uint16_t crc_byte_index = 0;
mxt_dbg(ctx, "Calculating CRC over %zd bytes", size);
/* Call the CRC function crc24() iteratively to calculate the CRC,
* passing it two bytes at a time. */
while (crc_byte_index < ((size % 2) ? (size - 1) : size)) {
calc_crc = crc24(calc_crc, *(base_addr + crc_byte_index),
*(base_addr + crc_byte_index + 1));
crc_byte_index += 2;
}
/* Call crc24() for the final byte, plus an extra
* 0 value byte to make the sequence even if it's odd */
if (size % 2) {
calc_crc = crc24(calc_crc, *(base_addr + crc_byte_index), 0);
}
/* Mask 32-bit calculated checksum to 24-bit */
calc_crc &= calc_crc & MASK_24_BITS;
*crc_result = calc_crc;
return MXT_SUCCESS;
}
/*!
* @brief Reads the information block from the chip.
* @return #mxt_rc
*/
int mxt_read_info_block(struct mxt_device *mxt)
{
int ret;
/* Read the ID Information from the chip */
uint8_t *info_blk = (uint8_t *)calloc(1, sizeof(struct mxt_id_info));
if (info_blk == NULL) {
mxt_err(mxt->ctx, "Memory allocation failure");
return MXT_ERROR_NO_MEM;
}
ret = mxt_read_register(mxt, info_blk, 0, sizeof(struct mxt_id_info));
if (ret) {
mxt_err(mxt->ctx, "Failed to read ID information");
return ret;
}
/* Determine the number of bytes for checksum calculation */
int num_objects = ((struct mxt_id_info*) info_blk)->num_objects;
size_t crc_area_size = sizeof(struct mxt_id_info)
+ num_objects * sizeof(struct mxt_object);
/* Allocate space to read Information Block AND Checksum from the chip */
size_t info_block_size = crc_area_size + sizeof(struct mxt_raw_crc);
info_blk = (uint8_t *)realloc(info_blk, info_block_size);
if (info_blk == NULL) {
mxt_err(mxt->ctx, "Memory allocation failure");
return MXT_ERROR_NO_MEM;
}
/* Read the entire Information Block from the chip */
ret = mxt_read_register(mxt, info_blk, 0, info_block_size);
if (ret) {
mxt_err(mxt->ctx, "Failed to read Information Block");
return ret;
}
/* Update pointers in device structure */
mxt->info.raw_info = info_blk;
mxt->info.id = (struct mxt_id_info*) info_blk;
mxt->info.objects = (struct mxt_object*)(info_blk + sizeof(struct mxt_id_info));
mxt->info.crc = convert_crc((struct mxt_raw_crc*) (info_blk + crc_area_size));
/* Calculate and compare Information Block Checksum */
uint32_t calc_crc;
ret = mxt_calculate_crc(mxt->ctx, &calc_crc, info_blk, crc_area_size);
if (ret)
return ret;
/* A zero CRC indicates a communications error */
if (calc_crc == 0) {
mxt_err(mxt->ctx, "Info checksum zero - possible comms error or zero input");
return MXT_ERROR_IO;
}
/* Compare the read checksum with calculated checksum */
if (mxt->info.crc != calc_crc) {
mxt_err(mxt->ctx, "Info checksum error calc=%06X read=%06X",
calc_crc, mxt->info.crc);
return MXT_ERROR_CHECKSUM_MISMATCH;
}
mxt_dbg(mxt->ctx, "Info checksum verified %06X", calc_crc);
return MXT_SUCCESS;
}
/*!
* @brief Populates a look-up table for the report IDs.
* @return #mxt_rc
*/
int mxt_calc_report_ids(struct mxt_device *mxt)
{
/* Report ID zero is reserved - start from one */
mxt->info.max_report_id = 1;
int report_id_count = 1;
int i;
int instance;
int report_index;
struct mxt_object obj;
/* Calculate the number of report IDs */
for (i = 0; i < mxt->info.id->num_objects; i++) {
obj = mxt->info.objects[i];
mxt->info.max_report_id += MXT_INSTANCES(obj) * obj.num_report_ids;
}
/* Allocate memory for report ID look-up table */
mxt->report_id_map = calloc(mxt->info.max_report_id,
sizeof(struct mxt_report_id_map));
if (mxt->report_id_map == NULL) {
mxt_err(mxt->ctx, "calloc failure");
return MXT_ERROR_NO_MEM;
}
/* Store the object and instance for each report ID */
for (i = 0; i < mxt->info.id->num_objects; i++) {
obj = mxt->info.objects[i];
for (instance = 0; instance < MXT_INSTANCES(obj); instance++) {
for (report_index = 0; report_index < obj.num_report_ids; report_index++) {
mxt->report_id_map[report_id_count].object_type = obj.type;
mxt->report_id_map[report_id_count].instance = instance;
report_id_count++;
}
}
}
mxt_verb(mxt->ctx, "Created a look-up table of %d Report IDs", report_id_count);
return MXT_SUCCESS;
}
/*!
* @brief Outputs firmware version as formatted string
* @return #mxt_rc
*/
int mxt_get_firmware_version(struct mxt_device *mxt, char *version_str)
{
if (mxt->info.id == NULL)
return MXT_ERROR_NO_DEVICE;
snprintf(version_str, MXT_FW_VER_LEN, "%u.%u.%02X",
(mxt->info.id->version & 0xF0) >> 4,
(mxt->info.id->version & 0x0F),
mxt->info.id->build);
return MXT_SUCCESS;
}
/*!
* @brief Logs information about the chip.
*/
void mxt_display_chip_info(struct mxt_device *mxt)
{
struct mxt_object obj;
char firmware_version[MXT_FW_VER_LEN];
struct mxt_id_info *id = mxt->info.id;
int i;
mxt_get_firmware_version(mxt, (char *)&firmware_version);
/* Display ID information */
mxt_dbg(mxt->ctx, "Family ID = %u (0x%02X)",
id->family, id->family);
mxt_dbg(mxt->ctx, "Variant ID = %u (0x%02X)",
id->variant, id->variant);
mxt_dbg(mxt->ctx, "Firmware Version = %s", firmware_version);
mxt_dbg(mxt->ctx, "Matrix X Size = %d", id->matrix_x_size);
mxt_dbg(mxt->ctx, "Matrix Y Size = %d", id->matrix_y_size);
mxt_dbg(mxt->ctx, "Number of elements in the Object Table = %d",
id->num_objects);
/* Display information about specific objects */
for (i = 0; i < id->num_objects; i++) {
obj = mxt->info.objects[i];
mxt_dbg(mxt->ctx, "T%u size:%u instances:%u address:%u",
obj.type, MXT_SIZE(obj),
MXT_INSTANCES(obj), mxt_get_start_position(obj, 0));
}
}
/*!
* @param mxt Maxtouch Device
* @param object_type Object ID number.
* @param instance Instance number of the object.
*
* @brief Returns the start address of the selected object and instance number
* in the chip's memory map.
* @return Object address, or OBJECT_NOT_FOUND if object/instance not found.
*/
uint16_t mxt_get_object_address(struct mxt_device *mxt, uint16_t object_type, uint8_t instance)
{
struct mxt_id_info *id = mxt->info.id;
int i = 0;
struct mxt_object obj;
for (i = 0; i < id->num_objects; i++) {
obj = mxt->info.objects[i];
/* Does object type match? */
if (obj.type == object_type) {
/* Are there enough instances defined in the firmware? */
if (obj.instances_minus_one >= instance) {
return mxt_get_start_position(obj, instance);
} else {
mxt_warn(mxt->ctx, "T%u instance %u not present on device",
object_type, instance);
return OBJECT_NOT_FOUND;
}
}
}
mxt_verb(mxt->ctx, "T%u not present on device", object_type);
return OBJECT_NOT_FOUND;
}
/*!
* @param mxt Maxtouch Device
* @param object_type Object ID number.
*
* @brief Returns the size of the specified type in the object table.
* @return Object size, or OBJECT_NOT_FOUND if object not found.
*/
uint8_t mxt_get_object_size(struct mxt_device *mxt, uint16_t object_type)
{
int i = mxt_get_object_table_num(mxt, object_type);
if (i == 255) {
return OBJECT_NOT_FOUND;
}
return MXT_SIZE(mxt->info.objects[i]);
}
/*!
* @param mxt Maxtouch Device
* @param object_type Object ID number.
*
* @brief Returns the number of instances of the specific object type
* @return number of instances, zero if not found
*/
uint8_t mxt_get_object_instances(struct mxt_device *mxt, uint16_t object_type)
{
struct mxt_id_info *id = mxt->info.id;
int i;
for (i = 0; i < id->num_objects; i++) {
if (mxt->info.objects[i].type == object_type) {
return MXT_INSTANCES(mxt->info.objects[i]);
}
}
return 0;
}
/*!
* @param mxt Maxtouch Device
* @param object_type Object ID number.
*
* @brief Returns the index of the specified type in the object table.
* @return Element index, or 255 if object type not found.
*/
uint8_t mxt_get_object_table_num(struct mxt_device *mxt, uint16_t object_type)
{
struct mxt_id_info *id = mxt->info.id;
int i;
for (i = 0; i < id->num_objects; i++) {
if (mxt->info.objects[i].type == object_type) {
return i;
}
}
mxt_warn(mxt->ctx, "Could not find object type T%u in object table", object_type);
return 255;
}
/*!
* @param obj Object table element.
* @param instance Object instance index.
*
* @brief Returns the start position for the specified object element by
* combining the least significant and most significant bytes.
* @return Start position as a single value.
*/
uint16_t mxt_get_start_position(struct mxt_object obj, uint8_t instance)
{
return (obj.start_pos_msb * 256) + obj.start_pos_lsb
+ (MXT_SIZE(obj) * instance);
}
/*!
* @brief Look up object type from report ID
* @param mxt Maxtouch Device
* @param report_id Report ID
* @return Object type number, or OBJECT_NOT_FOUND
*/
uint16_t mxt_report_id_to_type(struct mxt_device *mxt, int report_id)
{
if (report_id > mxt->info.max_report_id)
return OBJECT_NOT_FOUND;
return (mxt->report_id_map[report_id].object_type);
}
mxt-app-1.27/src/libmaxtouch/info_block.h 0000664 0000000 0000000 00000024461 12706171405 0020427 0 ustar 00root root 0000000 0000000 #pragma once
//------------------------------------------------------------------------------
/// \file info_block.h
/// \brief Functions for accessing the mXT chip's information block.
/// \author Iiro Valkonen
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
struct mxt_device;
struct libmaxtouch_ctx;
#define MXT_INSTANCES(o) ((uint16_t)((o).instances_minus_one) + 1)
#define MXT_SIZE(o) ((uint16_t)((o).size_minus_one) + 1)
#define MXT_OBJECT_SIZE_MAX 256
/*! \brief Checksum element struct */
struct mxt_raw_crc {
/*! CRC field */
uint16_t CRC;
/*! CRC field: higher byte */
uint8_t CRC_hi;
} __attribute__((packed));
/*! \brief Object table element struct */
struct mxt_object {
uint8_t type; /*!< Object type ID */
uint8_t start_pos_lsb; /*!< LSByte of the start address of the obj config structure */
uint8_t start_pos_msb; /*!< MSByte of the start address of the obj config structure */
uint8_t size_minus_one; /*!< Byte length of the obj config structure - 1 */
uint8_t instances_minus_one; /*!< Number of objects of this obj. type - 1 */
uint8_t num_report_ids; /*!< The max number of touches in a screen,
* max number of sliders in a slider array, etc.*/
} __attribute__((packed));
/*! \brief ID Information fields in the Information Block*/
struct mxt_id_info {
uint8_t family; /*!< Device family */
uint8_t variant; /*!< Device variant */
uint8_t version; /*!< Firmware version (Major/minor nibbles) */
uint8_t build; /*!< Firmware build number */
uint8_t matrix_x_size; /*!< Matrix X Size */
uint8_t matrix_y_size; /*!< Matrix Y Size */
/*! Number of elements in the object table. The actual number of objects
* can be different if any object has more than one instance. */
uint8_t num_objects;
} __attribute__((packed));
/*! \brief Info block struct holding ID and object table data and their CRC sum.
*
* Info block struct. Similar to one in info_block.h, but since
* the size of object table is not known beforehand, it's pointer to an
* array instead of an array. This is not defined in info_block.h unless
* we are compiling with IAR AVR or AVR32 compiler (__ICCAVR__ or __ICCAVR32__
* is defined). If this driver is compiled with those compilers, the
* info_block.h needs to be edited to not include that struct definition.
*
* CRC is 24 bits, consisting of CRC and CRC_hi; CRC is the lower 16 bits and
* CRC_hi the upper 8.
*
*/
struct mxt_info {
/*! Pointer to the struct containing ID Information. */
struct mxt_id_info *id;
/*! Pointer to an array of objects */
struct mxt_object *objects;
/*! Information block checksum */
uint32_t crc;
/*! Raw info block data */
uint8_t *raw_info;
/*! Number of valid report IDs */
uint8_t max_report_id;
};
/*!
* @brief Struct holding the object type / instance info.
*
* Struct holding the object type / instance info. An array of these maps
* report id's to object type / instance (array index = report id). Note
* that the report ID number 0 is reserved.
*/
struct mxt_report_id_map {
uint16_t object_type; /*!< Object type */
uint8_t instance; /*!< Instance number */
};
/*! Object types */
#define F_ENUM(x, y) x = y,
#define F_SWITCH(x, y) case x: return ( #x );
#define OBJECT_LIST(f) \
f(RESERVED_T0, 0) \
f(RESERVED_T1, 1) \
f(DEBUG_DELTAS_T2, 2) \
f(DEBUG_REFERENCES_T3, 3) \
f(DEBUG_SIGNALS_T4, 4) \
f(GEN_MESSAGEPROCESSOR_T5, 5) \
f(GEN_COMMANDPROCESSOR_T6, 6) \
f(GEN_POWERCONFIG_T7, 7) \
f(GEN_ACQUISITIONCONFIG_T8, 8) \
f(TOUCH_MULTITOUCHSCREEN_T9, 9) \
f(TOUCH_SINGLETOUCHSCREEN_T10, 10) \
f(TOUCH_XSLIDER_T11, 11) \
f(TOUCH_YSLIDER_T12, 12) \
f(TOUCH_XWHEEL_T13, 13) \
f(TOUCH_YWHEEL_T14, 14) \
f(TOUCH_KEYARRAY_T15, 15) \
f(PROCG_SIGNALFILTER_T16, 16) \
f(PROCI_LINEARIZATIONTABLE_T17, 17) \
f(SPT_COMMSCONFIG_T18, 18) \
f(SPT_GPIOPWM_T19, 19) \
f(PROCI_GRIPFACESUPPRESSION_T20, 20) \
f(RESERVED_T21, 21) \
f(PROCG_NOISESUPPRESSION_T22, 22) \
f(TOUCH_PROXIMITY_T23, 23) \
f(PROCI_ONETOUCHGESTUREPROCESSOR_T24, 24) \
f(SPT_SELFTEST_T25, 25) \
f(DEBUG_CTERANGE_T26, 26) \
f(PROCI_TWOTOUCHGESTUREPROCESSOR_T27, 27) \
f(SPT_CTECONFIG_T28, 28) \
f(SPT_GPI_T29, 29) \
f(SPT_GATE_T30, 30) \
f(TOUCH_KEYSET_T31, 31) \
f(TOUCH_XSLIDERSET_T32, 32) \
f(RESERVED_T33, 33) \
f(GEN_MESSAGEBLOCK_T34, 34) \
f(SPT_PROTOTYPE_T35, 35) \
f(RESERVED_T36, 36) \
f(DEBUG_DIAGNOSTIC_T37, 37) \
f(SPT_USERDATA_T38, 38) \
f(SPARE_T39, 39) \
f(PROCI_GRIPSUPPRESSION_T40, 40) \
f(PROCI_PALMSUPPRESSION_T41, 41) \
f(PROCI_TOUCHSUPPRESSION_T42, 42) \
f(SPT_DIGITIZER_T43, 43) \
f(SPT_MESSAGECOUNT_T44, 44) \
f(PROCI_VIRTUALKEY_T45, 45) \
f(SPT_CTECONFIG_T46, 46) \
f(PROCI_STYLUS_T47, 47) \
f(PROCG_NOISESUPPRESSION_T48, 48) \
f(GEN_DUALPULSE_T49, 49) \
f(SPARE_T50, 50) \
f(SPT_SONY_CUSTOM_T51, 51) \
f(TOUCH_PROXKEY_T52, 52) \
f(GEN_DATASOURCE_T53, 53) \
f(PROCG_NOISESUPPRESSION_T54, 54) \
f(PROCI_ADAPTIVETHRESHOLD_T55, 55) \
f(PROCI_SHIELDLESS_T56, 56) \
f(PROCI_EXTRATOUCHSCREENDATA_T57, 57) \
f(SPT_EXTRANOISESUPCTRLS_T58, 58) \
f(SPT_FASTDRIFT_T59, 59) \
f(SPT_TIMER_T61, 61) \
f(PROCG_NOISESUPPRESSION_T62, 62) \
f(PROCI_ACTIVESTYLUS_T63, 63) \
f(SPT_REFERENCERELOAD_T64, 64) \
f(PROCI_LENSBENDING_T65, 65) \
f(SPT_GOLDENREFERENCES_T66, 66) \
f(PROCI_CUSTOMGESTUREPROCESSOR_T67, 67) \
f(SERIAL_DATA_COMMAND_T68, 68) \
f(PROCI_PALMGESTUREPROCESSOR_T69, 69) \
f(SPT_DYNAMICCONFIGURATIONCONTROLLER_T70, 70) \
f(SPT_DYNAMICCONFIGURATIONCONTAINER_T71, 71) \
f(PROCG_NOISESUPPRESSION_T72, 72) \
f(PROCI_ZONEINDICATION_T73, 73) \
f(PROCG_SIMPLEGESTUREPROCESSOR_T74, 74) \
f(MOTION_SENSING_OBJECT_T75, 75) \
f(PROCI_MOTION_GESTURES_T76, 76) \
f(SPT_CTESCANCONFIG_T77, 77) \
f(PROCI_GLOVEDETECTION_T78, 78) \
f(SPT_TOUCHEVENTTRIGGER_T79, 79) \
f(PROCI_RETRANSMISSIONCOMPENSATION_T80, 80) \
f(PROCI_UNLOCKGESTURE_T81, 81) \
f(SPT_NOISESUPEXTENSION_T82, 82) \
f(ENVIRO_LIGHTSENSING_T83, 83) \
f(PROCI_GESTUREPROCESSOR_T84, 84) \
f(PEN_ACTIVESTYLUSPOWER_T85, 85) \
f(PROCG_NOISESUPACTIVESTYLUS_T86, 86) \
f(PEN_ACTIVESTYLUSDATA_T87, 87) \
f(PEN_ACTIVESTYLUSRECEIVE_T88, 88) \
f(PEN_ACTIVESTYLUSTRANSMIT_T89, 89) \
f(PEN_ACTIVESTYLUSWINDOW_T90, 90) \
f(DEBUG_CUSTOMDATACONFIG_T91, 91) \
f(PROCI_SYMBOLGESTUREPROCESSOR_T92, 92) \
f(PROCI_TOUCHSEQUENCELOGGER_T93, 93) \
f(SPT_PTCCONFIG_T95, 95) \
f(SPT_PTCTUNINGPARAMS_T96, 96) \
f(TOUCH_PTCKEYS_T97, 97) \
f(PROCG_PTCNOISESUPPRESSION_T98, 98) \
f(PROCI_KEYGESTUREPROCESSOR_T99, 99) \
f(TOUCH_MULTITOUCHSCREEN_T100, 100) \
f(SPT_TOUCHSCREENHOVER_T101, 101) \
f(SPT_SELFCAPHOVERCTECONFIG_T102, 102) \
f(PROCI_SCHNOISESUPPRESSION_T103, 103) \
f(SPT_AUXTOUCHCONFIG_T104, 104) \
f(SPT_DRIVENPLATEHOVERCONFIG_T105, 105) \
f(SPT_ACTIVESTYLUSMMBCONFIG_T106, 106) \
f(PROCI_ACTIVESTYLUS_T107, 107) \
f(PROCG_NOISESUPSELFCAP_T108, 108) \
f(SPT_SELFCAPGLOBALCONFIG_T109, 109) \
f(SPT_SELFCAPTUNINGPARAMS_T110, 110) \
f(SPT_SELFCAPCONFIG_T111, 111) \
f(PROCI_SELFCAPGRIPSUPPRESSION_T112, 112) \
f(SPT_PROXMEASURECONFIG_T113, 113) \
f(SPT_ACTIVESTYLUSMEASCONFIG_T114, 114) \
f(PROCI_SYMBOLGESTURE_T115, 115) \
f(SPT_SYMBOLGESTURECONFIG_T116, 116) \
f(GEN_INFOBLOCK16BIT_T254, 254) \
f(SPT_PROTOTYPE_T220, 220) \
f(SPT_PROTOTYPE_T221, 221) \
f(SPT_PROTOTYPE_T222, 222) \
f(SPT_PROTOTYPE_T223, 223) \
f(SPT_PROTOTYPE_T224, 224) \
f(SPT_PROTOTYPE_T225, 225) \
f(SPT_PROTOTYPE_T226, 226) \
f(SPT_PROTOTYPE_T227, 227) \
f(SPT_PROTOTYPE_T228, 228) \
f(SPT_PROTOTYPE_T229, 229) \
f(SPT_PROTOTYPE_T230, 230) \
f(SPT_PROTOTYPE_T231, 231) \
f(SPT_PROTOTYPE_T232, 232) \
f(SPT_PROTOTYPE_T233, 233) \
f(SPT_PROTOTYPE_T234, 234) \
f(SPT_PROTOTYPE_T235, 235) \
f(SPT_PROTOTYPE_T236, 236) \
f(SPT_PROTOTYPE_T237, 237) \
f(SPT_PROTOTYPE_T238, 238) \
f(SPT_PROTOTYPE_T239, 239) \
f(RESERVED_T255, 255)
enum mxt_object_type {
OBJECT_LIST(F_ENUM)
};
/*! Returned by get_object_address() if object is not found */
#define OBJECT_NOT_FOUND 0u
#define MXT_FW_VER_LEN 10u
/* Function prototypes */
int mxt_read_info_block(struct mxt_device *dev);
int mxt_calc_report_ids(struct mxt_device *dev);
void mxt_display_chip_info(struct mxt_device *dev);
uint16_t mxt_get_object_address(struct mxt_device *dev, uint16_t object_type, uint8_t instance);
uint8_t mxt_get_object_size(struct mxt_device *dev, uint16_t object_type);
uint8_t mxt_get_object_table_num(struct mxt_device *dev, uint16_t object_type);
uint16_t mxt_get_start_position(struct mxt_object obj, uint8_t instance);
int mxt_get_firmware_version(struct mxt_device *dev, char *version_str);
uint16_t mxt_report_id_to_type(struct mxt_device *dev, int report_id);
uint8_t mxt_get_object_instances(struct mxt_device *mxt, uint16_t object_type);
int mxt_calculate_crc(struct libmaxtouch_ctx *ctx, uint32_t *crc_result, uint8_t *base_addr, size_t size);
mxt-app-1.27/src/libmaxtouch/libmaxtouch.c 0000664 0000000 0000000 00000053515 12706171405 0020636 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file libmaxtouch.c
/// \brief MXT device low level access
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include "libmaxtouch.h"
#include "libmaxtouch/sysfs/dmesg.h"
#include "msg.h"
//******************************************************************************
/// \brief Initialise libmaxtouch library
/// \return #mxt_rc
int mxt_new(struct libmaxtouch_ctx **ctx)
{
struct libmaxtouch_ctx *new_ctx;
new_ctx = calloc(1, sizeof(struct libmaxtouch_ctx));
if (!new_ctx)
return MXT_ERROR_NO_MEM;
new_ctx->log_level = LOG_ERROR;
new_ctx->query = false;
new_ctx->log_fn = mxt_log_stderr;
new_ctx->i2c_block_size = I2C_DEV_MAX_BLOCK;
*ctx = new_ctx;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Close libmaxtouch library
/// \return #mxt_rc
int mxt_free(struct libmaxtouch_ctx *ctx)
{
#ifdef HAVE_LIBUSB
usb_close(ctx);
#endif
free(ctx);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Set function for logging output
/// \return #mxt_rc
void mxt_set_log_fn(struct libmaxtouch_ctx *ctx,
void (*log_fn)(struct libmaxtouch_ctx *ctx,
enum mxt_log_level level, const char *format, va_list args))
{
ctx->log_fn = log_fn;
}
//******************************************************************************
/// \brief Scan for devices on the I2C bus and USB
/// \note Checks for I2C devices first
/// \return #mxt_rc
int mxt_scan(struct libmaxtouch_ctx *ctx, struct mxt_conn_info **conn,
bool query)
{
int ret;
ctx->query = query;
ctx->scan_count = 0;
/* Scan the I2C bus first because it will return quicker */
ret = sysfs_scan(ctx, conn);
#ifdef HAVE_LIBUSB
if (query || ret) {
/* If no I2C devices are found then scan the USB */
ret = usb_scan(ctx, conn);
}
#endif /* HAVE_LIBUSB */
if (query) {
/* Clear query flag in case of context re-use */
ctx->query = false;
if (ctx->scan_count) {
return MXT_SUCCESS;
}
}
return ret;
}
//******************************************************************************
/// \brief Create connection object
/// \return #mxt_rc
int mxt_new_conn(struct mxt_conn_info **conn, enum mxt_device_type type)
{
struct mxt_conn_info *c = calloc(1, sizeof(struct mxt_conn_info));
if (!c)
return MXT_ERROR_NO_MEM;
c->type = type;
c->refcount = 1;
*conn = c;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Take a reference to the connection object
struct mxt_conn_info *mxt_ref_conn(struct mxt_conn_info *conn)
{
if (conn == NULL)
return NULL;
conn->refcount++;
return conn;
}
//******************************************************************************
/// \brief Free connection object
struct mxt_conn_info *mxt_unref_conn(struct mxt_conn_info *conn)
{
if (conn == NULL)
return NULL;
conn->refcount--;
if (conn->refcount > 0)
return conn;
switch (conn->type) {
case E_SYSFS:
free(conn->sysfs.path);
break;
default:
break;
}
free(conn);
return NULL;
}
//******************************************************************************
/// \brief Open device
/// \return #mxt_rc
int mxt_new_device(struct libmaxtouch_ctx *ctx, struct mxt_conn_info *conn,
struct mxt_device **mxt)
{
int ret;
struct mxt_device *new_dev;
new_dev = calloc(1, sizeof(struct mxt_device));
if (!new_dev)
return MXT_ERROR_NO_MEM;
new_dev->ctx = ctx;
new_dev->conn = mxt_ref_conn(conn);
if (conn == NULL) {
mxt_err(ctx, "New device connection parameters not valid");
return MXT_ERROR_NO_DEVICE;
}
switch (conn->type) {
case E_SYSFS:
ret = sysfs_open(new_dev);
break;
case E_I2C_DEV:
ret = i2c_dev_open(new_dev);
break;
#ifdef HAVE_LIBUSB
case E_USB:
ret = usb_open(new_dev);
break;
#endif /* HAVE_LIBUSB */
case E_HIDRAW:
ret = hidraw_register(new_dev);
break;
default:
mxt_err(ctx, "Device type not supported");
ret = MXT_ERROR_NOT_SUPPORTED;
goto failure;
}
if (ret != 0)
goto failure;
*mxt = new_dev;
return MXT_SUCCESS;
failure:
mxt_unref_conn(conn);
free(new_dev);
return ret;
}
//******************************************************************************
/// \brief Read information block
/// \return #mxt_rc
int mxt_get_info(struct mxt_device *mxt)
{
int ret;
ret = mxt_read_info_block(mxt);
if (ret)
return ret;
ret = mxt_calc_report_ids(mxt);
if (ret) {
mxt_err(mxt->ctx, "Failed to generate report ID look-up table");
return ret;
}
mxt_display_chip_info(mxt);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Close device
void mxt_free_device(struct mxt_device *mxt)
{
switch (mxt->conn->type) {
case E_SYSFS:
sysfs_release(mxt);
break;
case E_I2C_DEV:
i2c_dev_release(mxt);
break;
#ifdef HAVE_LIBUSB
case E_USB:
usb_release(mxt);
break;
#endif /* HAVE_LIBUSB */
case E_HIDRAW:
hidraw_release(mxt);
break;
default:
mxt_err(mxt->ctx, "Device type not supported");
}
mxt->conn = mxt_unref_conn(mxt->conn);
free(mxt->info.raw_info);
free(mxt->report_id_map);
free(mxt);
}
//******************************************************************************
/// \brief Read register from MXT chip
/// \return #mxt_rc
static int mxt_read_register_block(struct mxt_device *mxt, uint8_t *buf,
int start_register, int count,
size_t *bytes)
{
int ret;
switch (mxt->conn->type) {
case E_SYSFS:
ret = sysfs_read_register(mxt, buf, start_register, count, bytes);
break;
case E_I2C_DEV:
ret = i2c_dev_read_register(mxt, buf, start_register, count, bytes);
break;
#ifdef HAVE_LIBUSB
case E_USB:
ret = usb_read_register(mxt, buf, start_register, count, bytes);
break;
#endif /* HAVE_LIBUSB */
case E_HIDRAW:
ret = hidraw_read_register(mxt, buf, start_register, count, bytes);
break;
default:
mxt_err(mxt->ctx, "Device type not supported");
ret = MXT_ERROR_NOT_SUPPORTED;
}
return ret;
}
//******************************************************************************
/// \brief Read registers from MXT chip, in blocks
/// \return #mxt_rc
int mxt_read_register(struct mxt_device *mxt, uint8_t *buf,
int start_register, size_t count)
{
int ret;
size_t received;
size_t off = 0;
mxt_verb(mxt->ctx, "%s start_register:%d count:%zu", __func__,
start_register, count);
while (off < count) {
ret = mxt_read_register_block(mxt, buf + off, start_register + off,
count - off, &received);
if (ret)
return ret;
off += received;
}
mxt_log_buffer(mxt->ctx, LOG_VERBOSE, "RX:", buf, count);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Write register to MXT chip
/// \return #mxt_rc
int mxt_write_register(struct mxt_device *mxt, uint8_t const *buf,
int start_register, size_t count)
{
int ret;
mxt_verb(mxt->ctx, "%s start_register:%d count:%zu", __func__,
start_register, count);
switch (mxt->conn->type) {
case E_SYSFS:
ret = sysfs_write_register(mxt, buf, start_register, count);
break;
case E_I2C_DEV:
ret = i2c_dev_write_register(mxt, buf, start_register, count);
break;
#ifdef HAVE_LIBUSB
case E_USB:
ret = usb_write_register(mxt, buf, start_register, count);
break;
#endif /* HAVE_LIBUSB */
case E_HIDRAW:
ret = hidraw_write_register(mxt, buf, start_register, count);
break;
default:
mxt_err(mxt->ctx, "Device type not supported");
ret = MXT_ERROR_NOT_SUPPORTED;
}
if (ret == MXT_SUCCESS)
mxt_log_buffer(mxt->ctx, LOG_VERBOSE, "TX:", buf, count);
return ret;
}
//******************************************************************************
/// \brief Enable/disable MSG retrieval
/// \return #mxt_rc
int mxt_set_debug(struct mxt_device *mxt, bool debug_state)
{
int ret;
switch (mxt->conn->type) {
case E_SYSFS:
ret = sysfs_set_debug(mxt, debug_state);
break;
#ifdef HAVE_LIBUSB
case E_USB:
#endif
case E_I2C_DEV:
case E_HIDRAW:
/* No need to enable MSG output */
ret = MXT_SUCCESS;
break;
default:
mxt_err(mxt->ctx, "Device type not supported");
ret = MXT_ERROR_NOT_SUPPORTED;
}
return ret;
}
//******************************************************************************
/// \brief Get debug state
/// \param mxt device context
/// \param value true (debug enabled) or false (debug disabled)
/// \return #mxt_rc
int mxt_get_debug(struct mxt_device *mxt, bool *value)
{
int ret;
switch (mxt->conn->type) {
case E_SYSFS:
ret = sysfs_get_debug(mxt, value);
break;
#ifdef HAVE_LIBUSB
case E_USB:
mxt_warn(mxt->ctx, "Kernel debug not supported for USB devices");
ret = MXT_ERROR_NOT_SUPPORTED;
break;
#endif /* HAVE_LIBUSB */
case E_I2C_DEV:
case E_HIDRAW:
default:
ret = MXT_ERROR_NOT_SUPPORTED;
mxt_err(mxt->ctx, "Device type not supported");
}
return ret;
}
//******************************************************************************
/// \brief Perform fallback reset
/// \return #mxt_rc
static int mxt_send_reset_command(struct mxt_device *mxt, bool bootloader_mode)
{
int ret;
uint16_t t6_addr;
unsigned char write_value = RESET_COMMAND;
/* Obtain command processor's address */
t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0);
if (t6_addr == OBJECT_NOT_FOUND)
return MXT_ERROR_OBJECT_NOT_FOUND;
/* The value written determines which mode the chip will boot into */
if (bootloader_mode) {
mxt_info(mxt->ctx, "Resetting in bootloader mode");
write_value = BOOTLOADER_COMMAND;
} else {
mxt_info(mxt->ctx, "Sending reset command");
}
/* Write to command processor register to perform command */
ret = mxt_write_register
(
mxt, &write_value, t6_addr + MXT_T6_RESET_OFFSET, 1
);
return ret;
}
//******************************************************************************
/// \brief Restart the maxtouch chip, in normal or bootloader mode
/// \return 0 = success, negative = fail
int mxt_reset_chip(struct mxt_device *mxt, bool bootloader_mode)
{
int ret;
switch (mxt->conn->type) {
case E_SYSFS:
case E_I2C_DEV:
case E_HIDRAW:
ret = mxt_send_reset_command(mxt, bootloader_mode);
break;
#ifdef HAVE_LIBUSB
case E_USB:
ret = usb_reset_chip(mxt, bootloader_mode);
break;
#endif /* HAVE_LIBUSB */
default:
mxt_err(mxt->ctx, "Device type not supported");
ret = MXT_ERROR_NOT_SUPPORTED;
}
return ret;
}
//******************************************************************************
/// \brief Handle calibration messages
/// \return #mxt_rc
static int handle_calibrate_msg(struct mxt_device *mxt, uint8_t *msg,
void *context, uint8_t size)
{
int *last_status = context;
int status = msg[1];
if (mxt_report_id_to_type(mxt, msg[0]) == GEN_COMMANDPROCESSOR_T6) {
if (status & 0x10) {
mxt_dbg(mxt->ctx, "Device calibrating");
} else if (!(status & 0x10) && (*last_status & 0x10)) {
mxt_info(mxt->ctx, "Device calibrated");
return MXT_SUCCESS;
}
*last_status = status;
}
return MXT_MSG_CONTINUE;
}
//******************************************************************************
/// \brief Calibrate maxtouch chip
/// \return 0 = success, negative = fail
int mxt_calibrate_chip(struct mxt_device *mxt)
{
int ret;
uint16_t t6_addr;
unsigned char write_value = CALIBRATE_COMMAND;
/* Obtain command processor's address */
t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0);
if (t6_addr == OBJECT_NOT_FOUND)
return MXT_ERROR_OBJECT_NOT_FOUND;
mxt_flush_msgs(mxt);
/* Write to command processor register to perform command */
ret = mxt_write_register(mxt, &write_value, t6_addr + MXT_T6_CALIBRATE_OFFSET, 1);
if (ret == 0) {
mxt_info(mxt->ctx, "Sent calibration command");
} else {
mxt_err(mxt->ctx, "Failed to send calibration command");
}
int state = 0;
int flag = false;
ret = mxt_read_messages(mxt, MXT_CALIBRATE_TIMEOUT, &state,
handle_calibrate_msg, &flag);
if (ret == MXT_ERROR_TIMEOUT) {
mxt_warn(mxt->ctx, "WARN: timed out waiting for calibrate status");
return MXT_SUCCESS;
} else if (ret) {
mxt_err(mxt->ctx, "FAIL: device calibration failed");
return ret;
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Backup configuration settings to non-volatile memory
/// \return #mxt_rc
int mxt_backup_config(struct mxt_device *mxt, uint8_t backup_command)
{
int ret;
uint16_t t6_addr;
/* Obtain command processor's address */
t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0);
if (t6_addr == OBJECT_NOT_FOUND)
return MXT_ERROR_OBJECT_NOT_FOUND;
/* Write to command processor register to perform command */
ret = mxt_write_register
(
mxt, &backup_command, t6_addr + MXT_T6_BACKUPNV_OFFSET, 1
);
if (ret == MXT_SUCCESS)
mxt_info(mxt->ctx, "Backed up settings to the non-volatile memory");
else
mxt_err(mxt->ctx, "Failed to back up settings");
return ret;
}
//******************************************************************************
/// \brief Issue REPORTALL command to device
/// \return #mxt_rc
int mxt_report_all(struct mxt_device *mxt)
{
int ret;
uint16_t t6_addr;
const uint8_t report_all_cmd = 0xff;
/* Obtain command processor's address */
t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0);
if (t6_addr == OBJECT_NOT_FOUND)
return MXT_ERROR_OBJECT_NOT_FOUND;
/* Write to command processor register to perform command */
ret = mxt_write_register
(
mxt, &report_all_cmd, t6_addr + MXT_T6_REPORTALL_OFFSET, 1
);
if (ret == MXT_SUCCESS)
mxt_info(mxt->ctx, "REPORTALL command issued");
else
mxt_err(mxt->ctx, "Failed to issue REPORTALL command");
return ret;
}
//******************************************************************************
/// \brief Get number of debug messages available
/// \note This may retrieve and buffer messages
/// \return #mxt_rc
int mxt_get_msg_count(struct mxt_device *mxt, int *count)
{
int ret;
switch (mxt->conn->type) {
case E_SYSFS:
if (sysfs_has_debug_v2(mxt))
ret = sysfs_get_msgs_v2(mxt, count);
else
ret = dmesg_get_msgs(mxt, count, false);
break;
#ifdef HAVE_LIBUSB
case E_USB:
#endif /* HAVE_LIBUSB */
case E_I2C_DEV:
case E_HIDRAW:
ret = t44_get_msg_count(mxt, count);
break;
default:
mxt_err(mxt->ctx, "Device type not supported");
ret = MXT_ERROR_NOT_SUPPORTED;
break;
}
return ret;
}
//******************************************************************************
/// \brief Get T5 message as string
/// \return Message string (null for no message)
char *mxt_get_msg_string(struct mxt_device *mxt)
{
char *msg_string = NULL;
switch (mxt->conn->type) {
case E_SYSFS:
if (sysfs_has_debug_v2(mxt))
msg_string = sysfs_get_msg_string_v2(mxt);
else
msg_string = dmesg_get_msg_string(mxt);
break;
#ifdef HAVE_LIBUSB
case E_USB:
#endif /* HAVE_LIBUSB */
case E_I2C_DEV:
case E_HIDRAW:
msg_string = t44_get_msg_string(mxt);
break;
default:
mxt_err(mxt->ctx, "Device type not supported");
break;
}
if (msg_string)
mxt_dbg(mxt->ctx, "%s", msg_string);
return msg_string;
}
//******************************************************************************
/// \brief Get T5 message as byte array
/// \param mxt Maxtouch Device
/// \param buf Pointer to buffer
/// \param buflen Length of buffer
/// \param count length of message in bytes
/// \return #mxt_rc
int mxt_get_msg_bytes(struct mxt_device *mxt, unsigned char *buf,
size_t buflen, int *count)
{
int ret;
switch (mxt->conn->type) {
case E_SYSFS:
if (sysfs_has_debug_v2(mxt))
ret = sysfs_get_msg_bytes_v2(mxt, buf, buflen, count);
else
ret = dmesg_get_msg_bytes(mxt, buf, buflen, count);
break;
#ifdef HAVE_LIBUSB
case E_USB:
#endif /* HAVE_LIBUSB */
case E_I2C_DEV:
case E_HIDRAW:
ret = t44_get_msg_bytes(mxt, buf, buflen, count);
break;
default:
mxt_err(mxt->ctx, "Device type not supported");
ret = MXT_ERROR_NOT_SUPPORTED;
break;
}
if (ret == MXT_SUCCESS)
mxt_log_buffer(mxt->ctx, LOG_DEBUG, MSG_PREFIX, buf, *count);
return ret;
}
//******************************************************************************
/// \brief Discard all previous messages
/// \return #mxt_rc
int mxt_msg_reset(struct mxt_device *mxt)
{
int ret;
switch (mxt->conn->type) {
case E_SYSFS:
if (sysfs_has_debug_v2(mxt))
ret = sysfs_msg_reset_v2(mxt);
else
ret = dmesg_reset(mxt);
break;
#ifdef HAVE_LIBUSB
case E_USB:
#endif /* HAVE_LIBUSB */
case E_I2C_DEV:
case E_HIDRAW:
ret = t44_msg_reset(mxt);
break;
default:
mxt_err(mxt->ctx, "Device type not supported");
ret = MXT_ERROR_NOT_SUPPORTED;
break;
}
return ret;
}
//******************************************************************************
/// \brief Get fd for message polling
int mxt_get_msg_poll_fd(struct mxt_device *mxt)
{
if (sysfs_has_debug_v2(mxt))
return sysfs_get_debug_v2_fd(mxt);
else
return 0;
}
//******************************************************************************
/// \brief Wait for messages
int mxt_msg_wait(struct mxt_device *mxt, int timeout_ms)
{
int ret;
int fd = 0;
int numfds = 0;
struct pollfd fds[1];
fd = mxt_get_msg_poll_fd(mxt);
if (fd) {
fds[0].fd = fd;
fds[0].events = POLLPRI;
numfds = 1;
}
ret = poll(fds, numfds, timeout_ms);
if (ret == -1 && errno == EINTR) {
mxt_dbg(mxt->ctx, "Interrupted");
return MXT_ERROR_INTERRUPTED;
} else if (ret < 0) {
mxt_err(mxt->ctx, "poll returned %d (%s)", errno, strerror(errno));
return MXT_ERROR_IO;
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Read from bootloader
/// \return #mxt_rc
int mxt_bootloader_read(struct mxt_device *mxt, unsigned char *buf, int count)
{
int ret;
switch (mxt->conn->type) {
#ifdef HAVE_LIBUSB
case E_USB:
ret = usb_bootloader_read(mxt, buf, count);
break;
#endif /* HAVE_LIBUSB */
case E_I2C_DEV:
ret = i2c_dev_bootloader_read(mxt, buf, count);
break;
case E_HIDRAW:
default:
mxt_err(mxt->ctx, "Device type not supported");
ret = MXT_ERROR_NOT_SUPPORTED;
break;
}
return ret;
}
//******************************************************************************
/// \brief Write to bootloader
/// \return #mxt_rc
static int i2c_dev_bootloader_write_blks(struct mxt_device *mxt, unsigned char const *buf, int count)
{
int ret;
size_t received;
int off = 0;
while (off < count) {
ret = i2c_dev_bootloader_write(mxt, buf + off, count - off, &received);
if (ret)
return ret;
off += received;
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Write to bootloader
/// \return #mxt_rc
int mxt_bootloader_write(struct mxt_device *mxt, unsigned char const *buf, int count)
{
int ret;
switch (mxt->conn->type) {
#ifdef HAVE_LIBUSB
case E_USB:
ret = usb_bootloader_write(mxt, buf, count);
break;
#endif /* HAVE_LIBUSB */
case E_I2C_DEV:
ret = i2c_dev_bootloader_write_blks(mxt, buf, count);
break;
case E_HIDRAW:
default:
mxt_err(mxt->ctx, "Device type not supported");
ret = MXT_ERROR_NOT_SUPPORTED;
break;
}
return ret;
}
//******************************************************************************
/// \brief Convert errno codes from the Linux API to #mxt_rc values
/// \return #mxt_rc
int mxt_errno_to_rc(int errno_in)
{
switch (errno_in) {
case EACCES:
return MXT_ERROR_ACCESS;
case ENOMEM:
return MXT_ERROR_NO_MEM;
case ETIMEDOUT:
return MXT_ERROR_TIMEOUT;
case ENOENT:
return MXT_ERROR_NOENT;
default:
return MXT_ERROR_IO;
}
}
mxt-app-1.27/src/libmaxtouch/libmaxtouch.h 0000664 0000000 0000000 00000022407 12706171405 0020637 0 ustar 00root root 0000000 0000000 #pragma once
//------------------------------------------------------------------------------
/// \file libmaxtouch.h
/// \brief headers for MXT device low level access
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#ifdef __cplusplus
extern "C" {
#endif
#include
#include
#include
struct libmaxtouch_ctx;
struct mxt_device;
struct mxt_conn_info;
#include "log.h"
#include "sysfs/sysfs_device.h"
#include "i2c_dev/i2c_dev_device.h"
#ifdef HAVE_LIBUSB
#include "usb/usb_device.h"
#endif
#include "hidraw/hidraw_device.h"
#include "info_block.h"
/* GEN_COMMANDPROCESSOR_T6 Register offsets from T6 base address */
#define MXT_T6_RESET_OFFSET 0x00
#define MXT_T6_BACKUPNV_OFFSET 0x01
#define MXT_T6_CALIBRATE_OFFSET 0x02
#define MXT_T6_REPORTALL_OFFSET 0x03
#define MXT_T6_RESERVED_OFFSET 0x04
#define MXT_T6_DIAGNOSTIC_OFFSET 0x05
/* Values to write to the command processor fields */
#define RESET_COMMAND 0x01
#define BOOTLOADER_COMMAND 0xA5
#define BACKUPNV_COMMAND 0x55
#define CALIBRATE_COMMAND 0x01
/* Prefix for T5 messages */
#define MSG_PREFIX "MXT MSG:"
/* Polling delay for continually polling messages */
#define MXT_MSG_POLL_DELAY_MS 10
/* Calibrate timeout */
#define MXT_CALIBRATE_TIMEOUT 10
//******************************************************************************
/// \brief Return codes
enum mxt_rc {
MXT_SUCCESS = 0, /*!< Success */
MXT_INTERNAL_ERROR = 1, /*!< Internal error/assert */
MXT_ERROR_IO = 2, /*!< Input/output error */
MXT_ERROR_NO_MEM = 3, /*!< Memory allocation failure */
MXT_ERROR_TIMEOUT = 4, /*!< Timeout */
MXT_ERROR_NO_DEVICE = 5, /*!< Could not find a device or device went away */
MXT_ERROR_ACCESS = 6, /*!< Permission denied */
MXT_ERROR_NOT_SUPPORTED = 7, /*!< Operation not allowed for this device type */
MXT_ERROR_INTERRUPTED = 8, /*!< Interrupt function call */
MXT_ERROR_OBJECT_NOT_FOUND = 9, /*!< Object not available on device */
MXT_ERROR_NO_MESSAGE = 10, /*!< Received unexpected invalid message from message processor */
MXT_ERROR_SELF_TEST_INVALID = 11, /*!< Self test invalid test command */
MXT_ERROR_SELF_TEST_ANALOG = 12, /*!< Self test AVdd Analog power is not present */
MXT_ERROR_SELF_TEST_PIN_FAULT = 13, /*!< Self test Pin fault */
MXT_ERROR_SELF_TEST_AND_GATE = 14, /*!< Self test AND Gate Fault */
MXT_ERROR_SELF_TEST_SIGNAL_LIMIT = 15, /*!< Self test Signal limit fault */
MXT_ERROR_SELF_TEST_GAIN = 16, /*!< Self test Gain error */
MXT_ERROR_CHECKSUM_MISMATCH = 17, /*!< Information block or config checksum error */
MXT_ERROR_BOOTLOADER_UNLOCKED = 18, /*!< Bootloader already unlocked */
MXT_ERROR_BOOTLOADER_FRAME_CRC_FAIL = 19, /*!< Bootloader CRC failure (transmission failure) */
MXT_ERROR_FILE_FORMAT = 20, /*!< File format error */
MXT_FIRMWARE_UPDATE_NOT_REQUIRED = 21, /*!< Device firmware already required version */
MXT_ERROR_BOOTLOADER_NO_ADDRESS = 22, /*!< Could not identify bootloader address */
MXT_ERROR_FIRMWARE_UPDATE_FAILED = 23, /*!< Version on device did not match version given after bootloading operation */
MXT_ERROR_RESET_FAILURE = 24, /*!< Device did not reset */
MXT_ERROR_UNEXPECTED_DEVICE_STATE = 25, /*!< Device in unexpected state */
MXT_ERROR_BAD_INPUT = 26, /*!< Incorrect command line parameters or menu input given */
MXT_ERROR_PROTOCOL_FAULT = 27, /*!< Bridge TCP protocol parse error */
MXT_ERROR_CONNECTION_FAILURE = 28, /*!< Bridge connection error */
MXT_ERROR_SERIAL_DATA_FAILURE = 29, /*!< Serial data download failed */
MXT_ERROR_NOENT = 30, /*!< No such file or directory */
MXT_ERROR_SELFCAP_TUNE = 31, /*!< Error processing self cap command */
MXT_MSG_CONTINUE = 32, /*!< Continue processing messages */
MXT_ERROR_RESERVED = 33, /*!< Reserved value */
MXT_DEVICE_IN_BOOTLOADER = 34, /*!< Device is in bootloader mode */
MXT_ERROR_OBJECT_IS_VOLATILE = 35, /*!< Object is volatile */
MXT_ERROR_RESERVED2 = 36, /*!< Reserved value */
};
//******************************************************************************
/// \brief Device connection type
enum mxt_device_type {
E_SYSFS,
#ifdef HAVE_LIBUSB
E_USB,
#endif
E_I2C_DEV,
E_HIDRAW,
};
//******************************************************************************
/// \brief Libmaxtouch context
struct libmaxtouch_ctx {
bool query;
int scan_count;
enum mxt_log_level log_level;
int i2c_block_size;
void (*log_fn)(struct libmaxtouch_ctx *ctx, enum mxt_log_level level,
const char *format, va_list args);
union {
#ifdef HAVE_LIBUSB
struct usb_context usb;
#endif
};
};
//******************************************************************************
/// \brief Device connection parameters
struct mxt_conn_info {
enum mxt_device_type type;
int refcount;
union {
struct i2c_dev_conn_info i2c_dev;
struct hidraw_conn_info hidraw;
struct sysfs_conn_info sysfs;
#ifdef HAVE_LIBUSB
struct usb_conn_info usb;
#endif
};
};
//******************************************************************************
/// \brief Device context
struct mxt_device {
struct mxt_conn_info *conn;
struct libmaxtouch_ctx *ctx;
struct mxt_info info;
struct mxt_report_id_map *report_id_map;
char msg_string[255];
union {
struct sysfs_device sysfs;
#ifdef HAVE_LIBUSB
struct usb_device usb;
#endif
struct i2c_dev_device i2c_dev;
};
};
int mxt_new(struct libmaxtouch_ctx **ctx);
int mxt_free(struct libmaxtouch_ctx *ctx);
int mxt_scan(struct libmaxtouch_ctx *ctx, struct mxt_conn_info **conn, bool query);
int mxt_new_conn(struct mxt_conn_info **conn, enum mxt_device_type type);
struct mxt_conn_info *mxt_ref_conn(struct mxt_conn_info *conn);
struct mxt_conn_info *mxt_unref_conn(struct mxt_conn_info *conn);
int mxt_new_device(struct libmaxtouch_ctx *ctx, struct mxt_conn_info *conn, struct mxt_device **mxt);
void mxt_set_log_fn(struct libmaxtouch_ctx *ctx, void (*log_fn)(struct libmaxtouch_ctx *ctx, enum mxt_log_level level, const char *format, va_list args));
void mxt_free_device(struct mxt_device *mxt);
int mxt_get_info(struct mxt_device *mxt);
int mxt_read_register(struct mxt_device *mxt, uint8_t *buf, int start_register, size_t count);
int mxt_write_register(struct mxt_device *mxt, uint8_t const *buf, int start_register, size_t count);
int mxt_set_debug(struct mxt_device *mxt, bool debug_state);
int mxt_get_debug(struct mxt_device *mxt, bool *value);
int mxt_reset_chip(struct mxt_device *mxt, bool bootloader_mode);
int mxt_calibrate_chip(struct mxt_device *mxt);
int mxt_backup_config(struct mxt_device *mxt, uint8_t backup_command);
int mxt_load_config_file(struct mxt_device *mxt, const char *cfg_file);
int mxt_save_config_file(struct mxt_device *mxt, const char *filename);
int mxt_zero_config(struct mxt_device *mxt);
int mxt_get_msg_count(struct mxt_device *mxt, int *count);
char *mxt_get_msg_string(struct mxt_device *mxt);
int mxt_get_msg_bytes(struct mxt_device *mxt, unsigned char *buf, size_t buflen, int *count);
int mxt_msg_reset(struct mxt_device *mxt);
int mxt_get_msg_poll_fd(struct mxt_device *mxt);
int mxt_bootloader_read(struct mxt_device *mxt, unsigned char *buf, int count);
int mxt_bootloader_write(struct mxt_device *mxt, unsigned char const *buf, int count);
int mxt_msg_wait(struct mxt_device *mxt, int timeout_ms);
int mxt_errno_to_rc(int errno_in);
int mxt_report_all(struct mxt_device *mxt);
int mxt_checkcrc(struct libmaxtouch_ctx *ctx, struct mxt_device *mxt, char *filename);
#ifdef __cplusplus
}
#endif
mxt-app-1.27/src/libmaxtouch/log.c 0000664 0000000 0000000 00000012255 12706171405 0017074 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file log.c
/// \brief Provides a macro for logging messages.
/// \author Tim Culmer
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include "stdio.h"
#include "stdint.h"
#include "malloc.h"
#include "libmaxtouch.h"
#include "libmaxtouch/utilfuncs.h"
#if ANDROID
#include
#ifndef LOG_TAG
#define LOG_TAG "libmaxtouch"
#endif
#endif
//******************************************************************************
/// \brief Returns the input log level as a human-readable string.
/// \return Log level string
static const char get_log_level_string(enum mxt_log_level level)
{
switch (level) {
case LOG_SILENT:
return 'S';
case LOG_FATAL:
return 'F';
case LOG_ERROR:
return 'E';
case LOG_WARN:
return 'W';
case LOG_INFO:
return 'I';
case LOG_DEBUG:
return 'D';
case LOG_VERBOSE:
case LOG_DEFAULT:
case LOG_UNKNOWN:
default:
return 'V';
}
}
//******************************************************************************
/// \brief Get log verbosity level
enum mxt_log_level mxt_get_log_level(struct libmaxtouch_ctx *ctx)
{
return ctx->log_level;
}
//******************************************************************************
/// \brief Set log verbosity level
void mxt_set_log_level(struct libmaxtouch_ctx *ctx, uint8_t verbose)
{
switch (verbose) {
case 0:
ctx->log_level = LOG_SILENT;
break;
case 1:
ctx->log_level = LOG_WARN;
break;
case 2:
ctx->log_level = LOG_INFO;
break;
case 3:
ctx->log_level = LOG_DEBUG;
break;
default:
ctx->log_level = LOG_VERBOSE;
break;
}
}
//*****************************************************************************
/// \brief Output buffer to debug as hex
void mxt_log_buffer(struct libmaxtouch_ctx *ctx, enum mxt_log_level level,
const char *prefix,
const unsigned char *data, size_t count)
{
#if ENABLE_DEBUG
unsigned int i;
char *hexbuf;
size_t strsize = count*3 + 1;
if (mxt_get_log_level(ctx) > level)
return;
hexbuf = (char *)calloc(strsize, sizeof(char));
if (hexbuf == NULL) {
mxt_err(ctx, "%s: calloc failure", __func__);
return;
}
for (i = 0; i < count; i++)
sprintf(&hexbuf[3 * i], "%02X ", data[i]);
mxt_log(ctx, LOG_VERBOSE, "%s %s", prefix, hexbuf);
free(hexbuf);
#endif
}
//******************************************************************************
/// \brief Log function
void mxt_log(struct libmaxtouch_ctx *ctx, enum mxt_log_level level, const char *format, ...)
{
va_list args;
va_start(args, format);
ctx->log_fn(ctx, level, format, args);
va_end(args);
}
//******************************************************************************
/// \brief Output log message to stdout
void mxt_log_stdout(struct libmaxtouch_ctx *ctx, enum mxt_log_level level,
const char *format, va_list va_args)
{
vprintf(format, va_args);
printf("\n");
}
//******************************************************************************
/// \brief Output log message to stderr, with optional timestamp
void mxt_log_stderr(struct libmaxtouch_ctx *ctx, enum mxt_log_level level,
const char *format, va_list va_args)
{
if (mxt_get_log_level(ctx) < LOG_INFO) {
mxt_print_timestamp(stderr, false);
fprintf(stderr, " %c: ", get_log_level_string(level));
}
vfprintf(stderr, format, va_args);
fprintf(stderr, "\n");
}
#if ANDROID
//******************************************************************************
/// \brief Log using the Android API
void mxt_log_android(struct libmaxtouch_ctx *ctx, enum mxt_log_level level,
const char *format, va_list args)
{
__android_log_vprint(level, LOG_TAG, format, args);
}
#endif
mxt-app-1.27/src/libmaxtouch/log.h 0000664 0000000 0000000 00000007476 12706171405 0017112 0 ustar 00root root 0000000 0000000 #pragma once
//------------------------------------------------------------------------------
/// \file log.h
/// \brief Provides a macro for logging messages.
/// \author Tim Culmer
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#define ENABLE_LOGGING 1
#ifndef NDEBUG
#define ENABLE_DEBUG 1
#else
#define ENABLE_DEBUG 0
#endif
/* Log levels - designed to match Android's log levels */
enum mxt_log_level {
LOG_UNKNOWN = 0,
LOG_DEFAULT = 1,
LOG_VERBOSE = 2,
LOG_DEBUG = 3,
LOG_INFO = 4,
LOG_WARN = 5,
LOG_ERROR = 6,
LOG_FATAL = 7,
LOG_SILENT = 8
};
struct libmaxtouch_ctx;
enum mxt_log_level mxt_get_log_level(struct libmaxtouch_ctx *ctx);
void mxt_set_log_level(struct libmaxtouch_ctx *ctx, uint8_t verbose);
void mxt_log_stdout(struct libmaxtouch_ctx *ctx, enum mxt_log_level level, const char *format, va_list va_args);
void mxt_log_stderr(struct libmaxtouch_ctx *ctx, enum mxt_log_level level, const char *format, va_list args);
void mxt_log_android(struct libmaxtouch_ctx *ctx, enum mxt_log_level level, const char *format, va_list args);
void mxt_log_buffer(struct libmaxtouch_ctx *ctx, enum mxt_log_level level, const char *prefix, const unsigned char *data, size_t count);
static inline void __attribute__((always_inline, format(printf, 2, 3)))
mxt_log_null(struct libmaxtouch_ctx *ctx, const char *format, ...) {}
void mxt_log(struct libmaxtouch_ctx *ctx, enum mxt_log_level level, const char *format, ...);
#define mxt_log_cond(ctx, level, arg...) \
do { \
if (level >= mxt_get_log_level(ctx)) \
mxt_log(ctx, level, ## arg); \
} while (0)
#if ENABLE_LOGGING
#if ENABLE_DEBUG
#define mxt_verb(ctx, arg...) mxt_log_cond(ctx, LOG_VERBOSE, ## arg)
#define mxt_dbg(ctx, arg...) mxt_log_cond(ctx, LOG_DEBUG, ## arg)
#else
#define mxt_verb(ctx, arg...) mxt_log_null(ctx, ## arg)
#define mxt_dbg(ctx, arg...) mxt_log_null(ctx, ## arg)
#endif
#define mxt_info(ctx, arg...) mxt_log_cond(ctx, LOG_INFO, ## arg)
#define mxt_warn(ctx, arg...) mxt_log_cond(ctx, LOG_WARN, ## arg)
#define mxt_err(ctx, arg...) mxt_log_cond(ctx, LOG_ERROR, ## arg)
#else
/* Disable logging */
#define mxt_verb(ctx, arg...) mxt_log_null(ctx, ## arg)
#define mxt_dbg(ctx, arg...) mxt_log_null(ctx, ## arg)
#define mxt_info(ctx, arg...) mxt_log_null(ctx, ## arg)
#define mxt_warn(ctx, arg...) mxt_log_null(ctx, ## arg)
#define mxt_err(ctx, arg...) mxt_log_null(ctx, ## arg)
#endif
mxt-app-1.27/src/libmaxtouch/msg.c 0000664 0000000 0000000 00000016277 12706171405 0017111 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file msg.c
/// \brief Message handling functions
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2012 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include "libmaxtouch.h"
#include "msg.h"
//******************************************************************************
/// \brief Get number of messages
/// \return #mxt_rc
int t44_get_msg_count(struct mxt_device *mxt, int *count_out)
{
uint16_t addr;
int ret;
uint8_t count;
addr = mxt_get_object_address(mxt, SPT_MESSAGECOUNT_T44, 0);
if (addr == OBJECT_NOT_FOUND)
return MXT_ERROR_OBJECT_NOT_FOUND;
/* Get T44 count */
ret = mxt_read_register(mxt, &count, addr, 1);
if (ret)
return ret;
*count_out = count;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Get next MSG as a string
/// \return String or NULL for error
char *t44_get_msg_string(struct mxt_device *mxt)
{
int ret, i;
int size;
size_t length;
unsigned char databuf[20];
ret = t44_get_msg_bytes(mxt, databuf, sizeof(databuf), &size);
if (ret)
return NULL;
length = snprintf(mxt->msg_string, sizeof(mxt->msg_string), MSG_PREFIX);
for (i = 0; i < size; i++) {
length += snprintf(mxt->msg_string + length, sizeof(mxt->msg_string) - length,
"%02X ", databuf[i]);
}
return &mxt->msg_string[0];
}
//******************************************************************************
/// \brief Get next MSG into byte buffer
/// \return #mxt_rc
int t44_get_msg_bytes(struct mxt_device *mxt, unsigned char *buf,
size_t buflen, int *count)
{
int ret;
uint16_t addr;
uint16_t size;
addr = mxt_get_object_address(mxt, GEN_MESSAGEPROCESSOR_T5, 0);
if (addr == OBJECT_NOT_FOUND)
return MXT_ERROR_OBJECT_NOT_FOUND;
/* Do not read CRC byte */
size = mxt_get_object_size(mxt, GEN_MESSAGEPROCESSOR_T5) - 1;
if (size > buflen) {
mxt_err(mxt->ctx, "Buffer too small!");
return MXT_ERROR_NO_MEM;
}
ret = mxt_read_register(mxt, buf, addr, size);
if (ret)
return ret;
/* Check for invalid message */
if (buf[0] == 255u) {
mxt_verb(mxt->ctx, "Invalid message");
return MXT_ERROR_NO_MESSAGE;
}
*count = size;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Discard all messages
/// \return #mxt_rc
int t44_msg_reset(struct mxt_device *mxt)
{
int count, i, ret, size;
unsigned char databuf[20];
ret = t44_get_msg_count(mxt, &count);
if (ret) {
mxt_verb(mxt->ctx, "rc = %d", ret);
return ret;
}
for (i = 0; i < count; i++) {
ret = t44_get_msg_bytes(mxt, &databuf[0], sizeof(databuf), &size);
if (ret) {
mxt_verb(mxt->ctx, "rc = %d", ret);
return ret;
}
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Get messages from device and display to user
/// \param timeout_seconds Represent the time in seconds to continuously
/// display messages to the user. By setting timeout_seconds to 0, or
/// MSG_NO_WAIT the T5 object is read only once. By setting timeout_seconds to
/// -1, or MSG_CONTINUOUS the T5 object is repeatedly read until the user
/// presses Ctrl-C.
/// \param mxt Maxtouch Device
/// \param context Additional context required by msg_func
/// \param msg_func Pointer to function to read object status
/// \param flag Pointer to control flag
/// \return #mxt_rc
int mxt_read_messages(struct mxt_device *mxt, int timeout_seconds, void *context,
int (*msg_func)(struct mxt_device *mxt, uint8_t *msg,
void *context, uint8_t size), int *flag)
{
int count, len;
time_t now;
time_t start_time = time(NULL);
uint8_t buf[10];
int ret;
while (!*flag) {
mxt_msg_wait(mxt, MXT_MSG_POLL_DELAY_MS);
ret = mxt_get_msg_count(mxt, &count);
if (ret)
return ret;
while (count--) {
len = 0;
ret = mxt_get_msg_bytes(mxt, buf, sizeof(buf), &len);
if (ret && ret != MXT_ERROR_NO_MESSAGE)
return ret;
if (len > 0) {
ret = ((*msg_func)(mxt, buf, context, len));
if (ret != MXT_MSG_CONTINUE)
return ret;
}
}
if (timeout_seconds == 0) {
return MXT_SUCCESS;
} else if (timeout_seconds > 0) {
now = time(NULL);
if ((now - start_time) > timeout_seconds) {
mxt_err(mxt->ctx, "Timeout");
return MXT_ERROR_TIMEOUT;
}
}
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Flush messages in buffer
/// \return #mxt_rc
int mxt_flush_msgs(struct mxt_device *mxt)
{
int dummy;
mxt_dbg(mxt->ctx, "Flushing messages");
return mxt_get_msg_count(mxt, &dummy);
}
//******************************************************************************
/// \brief Gets checksum from T6 message
/// \return #mxt_rc
static int get_checksum_message(struct mxt_device *mxt, uint8_t *msg,
void *context, uint8_t size)
{
if (mxt_report_id_to_type(mxt, msg[0]) == GEN_COMMANDPROCESSOR_T6) {
uint32_t *checksum = context;
*checksum = msg[2] | (msg[3] << 8) | (msg[4] << 16);
return MXT_SUCCESS;
}
return MXT_MSG_CONTINUE;
}
//******************************************************************************
/// \brief Reads checksum from T6 messages
/// \return #mxt_rc
uint32_t mxt_get_config_crc(struct mxt_device *mxt)
{
int ret;
int flag = false;
uint32_t checksum;
ret = mxt_report_all(mxt);
if (ret)
return 0;
ret = mxt_read_messages(mxt, 2, &checksum, get_checksum_message, &flag);
if (ret)
return 0;
return checksum;
}
mxt-app-1.27/src/libmaxtouch/msg.h 0000664 0000000 0000000 00000004330 12706171405 0017101 0 ustar 00root root 0000000 0000000 #pragma once
//------------------------------------------------------------------------------
/// \file msg.h
/// \brief Message handling function headers
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2012 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
int t44_get_msg_count(struct mxt_device *mxt, int *count);
char *t44_get_msg_string(struct mxt_device *mxt);
int t44_get_msg_bytes(struct mxt_device *mxt, unsigned char *buf, size_t buflen, int *count);
int t44_msg_reset(struct mxt_device *mxt);
int mxt_read_messages(struct mxt_device *mxt, int timeout_seconds, void *context, int (*msg_func)(struct mxt_device *mxt, uint8_t *msg, void *context, uint8_t size), int *flag);
int mxt_get_calibrate_msgs(struct mxt_device *mxt, int timeout, int *state);
int mxt_flush_msgs(struct mxt_device *mxt);
uint32_t mxt_get_config_crc(struct mxt_device *mxt);
mxt-app-1.27/src/libmaxtouch/sysfs/ 0000775 0000000 0000000 00000000000 12706171405 0017311 5 ustar 00root root 0000000 0000000 mxt-app-1.27/src/libmaxtouch/sysfs/dmesg.c 0000664 0000000 0000000 00000022420 12706171405 0020554 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file dmesg.c
/// \brief Functions to read kernel message buffer
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#ifndef SYSLOG_ACTION_READ_ALL
#define SYSLOG_ACTION_READ_ALL (3)
#endif
#ifndef SYSLOG_ACTION_SIZE_BUFFER
#define SYSLOG_ACTION_SIZE_BUFFER (10)
#endif
#define MAX_DMESG_COUNT (500)
#define MAX_DMESG_BUFSIZE (10E6)
#include "libmaxtouch/log.h"
#include "libmaxtouch/libmaxtouch.h"
#include "sysfs_device.h"
#include "dmesg.h"
//******************************************************************************
/// Define for size of message buffer
#define BUFFERSIZE 256
//******************************************************************************
/// \brief Linked list item structure
struct dmesg_item {
unsigned long sec;
unsigned long msec;
char msg[BUFFERSIZE];
struct dmesg_item *next;
};
//******************************************************************************
/// \brief Add new node to linked list of dmesg items
/// \param mxt Maxtouch Device
/// \param sec Seconds value of item
/// \param msec Milliseconds value of item
/// \param msg Message string data
static void dmesg_list_add(struct mxt_device *mxt, unsigned long sec,
unsigned long msec, char *msg)
{
// create new node
struct dmesg_item* new_node = (struct dmesg_item *)calloc(1, sizeof(struct dmesg_item));
if (!new_node) return;
strncpy(new_node->msg, msg, sizeof(new_node->msg));
new_node->msg[sizeof(new_node->msg) - 1] = '\0';
new_node->sec = sec;
new_node->msec = msec;
new_node->next = mxt->sysfs.dmesg_head;
mxt->sysfs.dmesg_head = new_node;
mxt->sysfs.dmesg_count++;
}
//******************************************************************************
/// \brief Remove all items from the linked list
/// \param mxt Maxtouch Device
static void dmesg_list_empty(struct mxt_device *mxt)
{
if (mxt->sysfs.dmesg_head == NULL)
return;
// reset
struct dmesg_item *old_node = mxt->sysfs.dmesg_head;
mxt->sysfs.dmesg_head = NULL;
mxt->sysfs.dmesg_count = 0;
// release memory
struct dmesg_item *next_node = NULL;
while (old_node->next != NULL) {
next_node = old_node->next;
free(old_node);
old_node = next_node;
}
free(old_node);
return;
}
//******************************************************************************
/// \brief Get messages
/// \param mxt Maxtouch Device
/// \param count Number of messages available
/// \param init_timestamp Read newest dmesg line and initialise timestamp
/// \return #mxt_rc
int dmesg_get_msgs(struct mxt_device *mxt, int *count, bool init_timestamp)
{
char msg[BUFFERSIZE];
int ep, sp;
int ret = MXT_SUCCESS;
unsigned long sec, msec, lastsec = 0, lastmsec = 0;
// Read entire kernel log buffer
ep = klogctl(SYSLOG_ACTION_READ_ALL, mxt->sysfs.debug_msg_buf,
mxt->sysfs.debug_msg_buf_size);
// Return if no bytes read
if (ep < 0) {
mxt_warn(mxt->ctx, "klogctl error %d (%s)", errno, strerror(errno));
ret = mxt_errno_to_rc(errno);
} else {
// null terminate
mxt->sysfs.debug_msg_buf[ep] = 0;
sp = ep;
if (!init_timestamp)
dmesg_list_empty(mxt);
// Search for next new line character
while (true) {
sp--;
while (sp >= 0 && *(mxt->sysfs.debug_msg_buf + sp) != '\n')
sp--;
if (sp <= 0)
break;
// Try to parse dmesg line
if (sscanf(mxt->sysfs.debug_msg_buf+sp+1, "< %*c>[ %lu.%06lu] %255[^\n]",
&sec, &msec, msg) == 3) {
if (init_timestamp) {
mxt->sysfs.timestamp = sec;
mxt->sysfs.mtimestamp = msec;
mxt_verb(mxt->ctx, "%s - init [%5lu.%06lu]", __func__, sec, msec);
break;
}
// Store time of last message in buffer
if (lastsec == 0) {
lastsec = sec;
lastmsec = msec;
}
// Only 500 at a time, otherwise we overrun JNI reference limit.
// Timestamp must be greater than previous messages, slightly
// complicated by seconds and microseconds
if ((mxt->sysfs.dmesg_count > MAX_DMESG_COUNT) ||
(sec == mxt->sysfs.timestamp && msec <= mxt->sysfs.mtimestamp) ||
(sec < mxt->sysfs.timestamp)) {
mxt->sysfs.timestamp = lastsec;
mxt->sysfs.mtimestamp = lastmsec;
break;
}
char* msgptr;
msg[sizeof(msg) - 1] = '\0';
msgptr = strstr(msg, "MXT MSG");
if (msgptr)
dmesg_list_add(mxt, sec, msec, msgptr);
}
}
if (!init_timestamp) {
*count = mxt->sysfs.dmesg_count;
mxt->sysfs.dmesg_ptr = mxt->sysfs.dmesg_head;
}
}
return ret;
}
//******************************************************************************
/// \brief Update the timestamp from the klog messages
/// \param mxt Maxtouch Device
/// \return #mxt_rc
static int dmesg_update_timestamp(struct mxt_device *mxt)
{
return dmesg_get_msgs(mxt, NULL, true);
}
//******************************************************************************
/// \brief Get the next debug message
/// \param mxt Maxtouch Device
/// \return Message string
char *dmesg_get_msg_string(struct mxt_device *mxt)
{
char *msg_string;
msg_string = mxt->sysfs.dmesg_ptr->msg;
if (mxt->sysfs.dmesg_ptr != NULL) {
// Get next record in linked list
mxt->sysfs.dmesg_ptr = mxt->sysfs.dmesg_ptr->next;
}
if (!strncasecmp("MXT MSG:FF", msg_string, 10))
return NULL;
return msg_string;
}
//******************************************************************************
/// \brief Get debug message as byte array
/// \param mxt Maxtouch Device
/// \param buf Pointer to buffer
/// \param buflen Length of buffer
/// \param count number of bytes read
/// \return #mxt_rc
int dmesg_get_msg_bytes(struct mxt_device *mxt, unsigned char *buf,
size_t buflen, int *count)
{
unsigned int bufidx = 0;
int offset;
char *message;
message = dmesg_get_msg_string(mxt);
if (!message)
return MXT_ERROR_NO_MESSAGE;
/* Check message begins with prefix */
if (strncmp(MSG_PREFIX, message, strlen(MSG_PREFIX))) {
*count = 0;
return MXT_SUCCESS;
}
message += strlen(MSG_PREFIX);
while (1 == sscanf(message, "%hhx%n", buf + bufidx, &offset)) {
message += offset;
bufidx++;
if (bufidx >= buflen)
break;
}
*count = bufidx;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Reset the timestamp counter
int dmesg_reset(struct mxt_device *mxt)
{
int ret;
mxt->sysfs.dmesg_head = NULL;
mxt->sysfs.mtimestamp = 0;
mxt->sysfs.timestamp = 0;
ret = dmesg_update_timestamp(mxt);
return ret;
}
//******************************************************************************
/// \brief Allocate kernel log buffer
int dmesg_alloc_buffer(struct mxt_device *mxt)
{
int size;
size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, NULL, 0);
if (size == -1) {
mxt_err(mxt->ctx, "klogctl error %d (%s)", errno, strerror(errno));
return mxt_errno_to_rc(errno);
}
if (size > MAX_DMESG_BUFSIZE)
size = MAX_DMESG_BUFSIZE;
mxt_dbg(mxt->ctx, "sysfs.debug_msg_buf_size: %d bytes", size);
// Allocate buffer space
mxt->sysfs.debug_msg_buf = (char *)calloc(size, sizeof(char));
if (mxt->sysfs.debug_msg_buf == NULL) {
mxt_err(mxt->ctx, "Error allocating debug_msg_buf %d bytes", size);
return mxt_errno_to_rc(errno);
}
mxt->sysfs.debug_msg_buf_size = size;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Allocate kernel log buffer
void dmesg_free_buffer(struct mxt_device *mxt)
{
free(mxt->sysfs.debug_msg_buf);
mxt->sysfs.debug_msg_buf = NULL;
}
mxt-app-1.27/src/libmaxtouch/sysfs/dmesg.h 0000664 0000000 0000000 00000003720 12706171405 0020563 0 ustar 00root root 0000000 0000000 #pragma once
//------------------------------------------------------------------------------
/// \file dmesg.h
/// \brief Header for dmesg handling
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
char *dmesg_get_msg_string(struct mxt_device *mxt);
int dmesg_get_msgs(struct mxt_device *mxt, int *count, bool init_timestamp);
int dmesg_get_msg_bytes(struct mxt_device *mxt, unsigned char *buf, size_t buflen, int *count);
int dmesg_reset(struct mxt_device *mxt);
int dmesg_alloc_buffer(struct mxt_device *mxt);
void dmesg_free_buffer(struct mxt_device *mxt);
mxt-app-1.27/src/libmaxtouch/sysfs/sysfs_device.c 0000664 0000000 0000000 00000050203 12706171405 0022143 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file sysfs_device.c
/// \brief MXT device low level access via I2C
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "libmaxtouch/log.h"
#include "libmaxtouch/libmaxtouch.h"
#include "sysfs_device.h"
#include "dmesg.h"
#define SYSFS_I2C_ROOT "/sys/bus/i2c/drivers/"
//******************************************************************************
/// \brief Construct filename of path
static char *make_path(struct mxt_device *mxt, const char *filename)
{
snprintf(mxt->sysfs.temp_path, mxt->sysfs.path_max,
"%s/%s", mxt->conn->sysfs.path, filename);
return mxt->sysfs.temp_path;
}
//******************************************************************************
/// \brief Open sysfs MSG notify attribute
/// \return #mxt_rc
static int sysfs_open_notify_fd(struct mxt_device *mxt)
{
char *filename = make_path(mxt, "debug_notify");
mxt->sysfs.debug_notify_fd = open(filename, O_RDONLY);
if (mxt->sysfs.debug_notify_fd < 0) {
mxt_err(mxt->ctx, "Could not open %s, error %s (%d)", filename, strerror(errno), errno);
return mxt_errno_to_rc(errno);
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Reopen sysfs MSG notify attribute
static void sysfs_reopen_notify_fd(struct mxt_device *mxt)
{
uint16_t val;
close(mxt->sysfs.debug_notify_fd);
sysfs_open_notify_fd(mxt);
read(mxt->sysfs.debug_notify_fd, &val, 2);
}
//******************************************************************************
/// \brief Create sysfs connection info
/// \return #mxt_rc
static int sysfs_new_connection(struct libmaxtouch_ctx *ctx,
struct mxt_conn_info **conn,
const char *dir, bool acpi)
{
int ret;
struct mxt_conn_info *c;
ret = mxt_new_conn(&c, E_SYSFS);
if (ret)
return ret;
c->sysfs.path = (char *)calloc(strlen(dir) + 1, sizeof(char));
memcpy(c->sysfs.path, dir, strlen(dir) + 1);
c->sysfs.acpi = acpi;
*conn = c;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Get fd for select
int sysfs_get_debug_v2_fd(struct mxt_device *mxt)
{
return mxt->sysfs.debug_notify_fd;
}
//******************************************************************************
/// \brief Check sysfs device directory for correct attributes
/// \return #mxt_rc
static int scan_sysfs_directory(struct libmaxtouch_ctx *ctx,
struct mxt_conn_info **conn,
struct dirent *i2c_dir,
const char *dir,
bool acpi)
{
char *pszDirname;
size_t length;
DIR *pDirectory;
struct dirent *pEntry;
bool mem_access_found = false;
bool debug_found = false;
bool debug_v2_found = false;
int ret;
length = strlen(dir) + strlen(i2c_dir->d_name) + 2;
if ((pszDirname = (char *)calloc(length, sizeof(char))) == NULL) {
ret = MXT_ERROR_NO_MEM;
goto free;
}
snprintf(pszDirname, length, "%s/%s", dir, i2c_dir->d_name);
pDirectory = opendir(pszDirname);
if (!pDirectory) {
ret = MXT_ERROR_NO_MEM;
goto free;
}
while ((pEntry = readdir(pDirectory)) != NULL) {
if (!strcmp(pEntry->d_name, "mem_access")) {
mxt_dbg(ctx, "Found mem_access interface at %s/mem_access", pszDirname);
mem_access_found = true;
} else if (!strcmp(pEntry->d_name, "debug_enable")) {
mxt_dbg(ctx, "Found debug_enable interface at %s/debug_enable", pszDirname);
debug_found = true;
} else if (!strcmp(pEntry->d_name, "debug_msg")) {
mxt_dbg(ctx, "Found Debug V2 at %s/debug_msg", pszDirname);
debug_v2_found = true;
}
}
/* If device found, store it and return success */
if (mem_access_found && (debug_found || debug_v2_found)) {
ctx->scan_count++;
if (ctx->query) {
printf("sysfs:%s Atmel %s interface\n", pszDirname,
debug_v2_found ? "Debug V2" : "Debug");
} else {
ret = sysfs_new_connection(ctx, conn, pszDirname, acpi);
mxt_dbg(ctx, "Found %s", pszDirname);
goto close;
}
} else {
mxt_verb(ctx, "Ignoring %s", pszDirname);
}
ret = MXT_ERROR_NO_DEVICE;
close:
(void)closedir(pDirectory);
free:
free(pszDirname);
return ret;
}
//******************************************************************************
/// \brief Process a driver directory in sysfs looking for MXT devices
/// \return #mxt_rc
static int scan_driver_directory(struct libmaxtouch_ctx *ctx,
struct mxt_conn_info **conn,
const char *path, struct dirent *dir)
{
char *pszDirname;
size_t length;
DIR *pDirectory;
struct dirent *pEntry;
int adapter;
unsigned int address;
unsigned char acpi[PATH_MAX];
int ret;
length = strlen(path) + strlen(dir->d_name) + 1;
if ((pszDirname = (char *)calloc(length, sizeof(char))) == NULL) {
mxt_err(ctx, "calloc failure");
return MXT_ERROR_NO_MEM;
}
snprintf(pszDirname, length, "%s%s", path, dir->d_name);
pDirectory = opendir(pszDirname);
if (pDirectory == NULL) {
ret = MXT_ERROR_NO_MEM;
goto free;
}
while ((pEntry = readdir(pDirectory)) != NULL) {
if (!strcmp(pEntry->d_name, ".") || !strcmp(pEntry->d_name, ".."))
continue;
if (sscanf(pEntry->d_name, "%d-%x", &adapter, &address) == 2) {
ret = scan_sysfs_directory(ctx, conn, pEntry, pszDirname, false);
if (ret != MXT_ERROR_NO_DEVICE) goto close;
} else if (sscanf(pEntry->d_name, "i2c-%s", acpi) == 1) {
ret = scan_sysfs_directory(ctx, conn, pEntry, pszDirname, true);
if (ret != MXT_ERROR_NO_DEVICE) goto close;
}
}
ret = MXT_ERROR_NO_DEVICE;
close:
(void)closedir(pDirectory);
free:
free(pszDirname);
return ret;
}
//******************************************************************************
/// \brief Scan for devices
/// \return #mxt_rc
int sysfs_scan(struct libmaxtouch_ctx *ctx, struct mxt_conn_info **conn)
{
struct dirent *pEntry;
DIR *pDirectory;
int ret;
// Look in sysfs for driver entries
pDirectory = opendir(SYSFS_I2C_ROOT);
if (!pDirectory)
return MXT_ERROR_NO_DEVICE;
while ((pEntry = readdir(pDirectory)) != NULL) {
if (!strcmp(pEntry->d_name, ".") || !strcmp(pEntry->d_name, ".."))
continue;
ret = scan_driver_directory(ctx, conn, SYSFS_I2C_ROOT, pEntry);
// If found or error finish
if (ret != MXT_ERROR_NO_DEVICE) goto close;
}
ret = MXT_ERROR_NO_DEVICE;
close:
(void)closedir(pDirectory);
return ret;
}
//******************************************************************************
/// \brief Open device
/// \return #mxt_rc
int sysfs_open(struct mxt_device *mxt)
{
struct sysfs_conn_info *conn = &mxt->conn->sysfs;
char *filename;
struct stat filestat;
int ret;
mxt->sysfs.path_max = strlen(conn->path) + 20;
// Allocate temporary path space
mxt->sysfs.temp_path = calloc(mxt->sysfs.path_max + 1, sizeof(char));
if (!mxt->sysfs.temp_path)
return MXT_ERROR_NO_MEM;
// Cache memory access path for fast access
mxt->sysfs.mem_access_path = calloc(mxt->sysfs.path_max + 1, sizeof(char));
if (!mxt->sysfs.mem_access_path)
return MXT_ERROR_NO_MEM;
snprintf(mxt->sysfs.mem_access_path, mxt->sysfs.path_max,
"%s/mem_access", conn->path);
// Check whether debug v2 or not
filename = make_path(mxt, "debug_msg");
ret = stat(filename, &filestat);
if (ret < 0) {
if (errno == ENOENT) {
mxt->sysfs.debug_v2 = false;
} else {
mxt_err(mxt->ctx, "Could not stat %s, error %s (%d)",
filename, strerror(errno), errno);
return mxt_errno_to_rc(errno);
}
} else {
mxt->sysfs.debug_v2 = true;
}
mxt_info(mxt->ctx, "Registered sysfs path:%s", conn->path);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Release device
void sysfs_release(struct mxt_device *mxt)
{
if (mxt) {
free(mxt->sysfs.temp_path);
mxt->sysfs.temp_path = NULL;
free(mxt->sysfs.debug_v2_msg_buf);
mxt->sysfs.debug_v2_msg_buf = NULL;
}
}
//******************************************************************************
/// \brief Open memory access file
/// \return #mxt_rc
static int open_device_file(struct mxt_device *mxt, int *fd_out)
{
int fd;
// Check device is initialised
if (!mxt || !mxt->sysfs.mem_access_path) {
mxt_err(mxt->ctx, "Device uninitialised");
return MXT_ERROR_NO_DEVICE;
}
fd = open(mxt->sysfs.mem_access_path, O_RDWR);
if (fd < 0) {
mxt_err(mxt->ctx, "Could not open %s, error %s (%d)",
mxt->sysfs.mem_access_path, strerror(errno), errno);
return mxt_errno_to_rc(errno);
}
*fd_out = fd;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Read register from MXT chip
/// \return #mxt_rc
int sysfs_read_register(struct mxt_device *mxt, unsigned char *buf,
int start_register, size_t count, size_t *bytes_read)
{
int fd = -ENODEV;
int ret;
ret = open_device_file(mxt, &fd);
if (ret)
return ret;
if (lseek(fd, start_register, 0) < 0) {
mxt_err(mxt->ctx, "lseek error %s (%d)", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
goto close;
}
*bytes_read = 0;
while (*bytes_read < count) {
ret = read(fd, buf + *bytes_read, count - *bytes_read);
if (ret == 0) {
ret = MXT_ERROR_IO;
goto close;
} else if (ret < 0) {
mxt_err(mxt->ctx, "read error %s (%d)", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
goto close;
}
*bytes_read += ret;
}
ret = MXT_SUCCESS;
close:
close(fd);
return ret;
}
//******************************************************************************
/// \brief Write register to MXT chip
/// \return #mxt_rc
int sysfs_write_register(struct mxt_device *mxt, unsigned char const *buf,
int start_register, size_t count)
{
int fd = -ENODEV;
int ret;
size_t bytes_written;
ret = open_device_file(mxt, &fd);
if (ret)
return ret;
if (lseek(fd, start_register, 0) < 0) {
mxt_err(mxt->ctx, "lseek error %s (%d)", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
goto close;
}
bytes_written = 0;
while (bytes_written < count) {
ret = write(fd, buf+bytes_written, count - bytes_written);
if (ret == 0) {
ret = MXT_ERROR_IO;
goto close;
} else if (ret < 0) {
mxt_err(mxt->ctx, "Error %s (%d) writing to register", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
goto close;
}
bytes_written += ret;
}
ret = MXT_SUCCESS;
close:
close(fd);
return ret;
}
//******************************************************************************
/// \brief Write boolean to file as ASCII 0/1
/// \param mxt Device context
/// \param filename Name of file to write
/// \param value Value to write
/// \return #mxt_rc
static int write_boolean_file(struct mxt_device *mxt, const char *filename,
bool value)
{
FILE *file;
file = fopen(filename, "w+");
if (!file) {
mxt_err(mxt->ctx, "Could not open %s, error %s (%d)", filename, strerror(errno), errno);
return mxt_errno_to_rc(errno);
}
if (value == true) {
fputs("1", file);
} else {
fputs("0", file);
}
fclose(file);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Read boolean from file as ASCII 0/1
/// \param mxt Device context
/// \param filename Name of file to read
/// \param value Value read from file
/// \return #mxt_rc
static int read_boolean_file(struct mxt_device *mxt, char *filename,
bool *value)
{
FILE *file;
char val;
bool ret;
file = fopen(filename, "r");
if (!file) {
mxt_err(mxt->ctx, "Could not open %s, error %s (%d)", filename, strerror(errno), errno);
return mxt_errno_to_rc(errno);
}
ret = fread(&val, sizeof(char), 1, file);
if (ret < 0) {
mxt_err(mxt->ctx, "Error reading files");
return MXT_ERROR_IO;
}
if (val == 49) { // ASCII '0'
*value = true;
} else {
*value = false;
}
fclose(file);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Set debug state
/// \param mxt Device context
/// \param debug_state true = debug enabled, false = debug disabled
/// \return #mxt_rc
int sysfs_set_debug(struct mxt_device *mxt, bool debug_state)
{
int ret;
// Check device is initialised
if (!mxt) {
mxt_err(mxt->ctx, "Device uninitialised");
return MXT_ERROR_NO_DEVICE;
}
if (mxt->sysfs.debug_v2 == true) {
ret = write_boolean_file(mxt, make_path(mxt, "debug_v2_enable"), debug_state);
if (ret)
ret = write_boolean_file(mxt, make_path(mxt, "debug_enable"), debug_state);
if (debug_state) {
ret = sysfs_open_notify_fd(mxt);
if (ret)
return ret;
} else {
close(mxt->sysfs.debug_notify_fd);
}
} else {
if (debug_state) {
ret = dmesg_alloc_buffer(mxt);
if (ret)
return ret;
} else {
dmesg_free_buffer(mxt);
}
ret = write_boolean_file(mxt, make_path(mxt, "debug_enable"), debug_state);
}
return ret;
}
//******************************************************************************
/// \brief Get debug message string
/// \param mxt Device context
/// \return C string or NULL
char *sysfs_get_msg_string_v2(struct mxt_device *mxt)
{
int ret, i;
int size;
size_t length;
unsigned char databuf[20];
static char msg_string[255];
ret = sysfs_get_msg_bytes_v2(mxt, &databuf[0], sizeof(databuf), &size);
if (ret)
return NULL;
length = snprintf(msg_string, sizeof(msg_string), "MXT MSG:");
for (i = 0; i < size; i++) {
length += snprintf(msg_string + length, sizeof(msg_string) - length,
"%02X ", databuf[i]);
}
return &msg_string[0];
}
//******************************************************************************
/// \brief Get debug message bytes
/// \param mxt Device context
/// \param buf Pointer to buffer
/// \param buflen Length of buffer
/// \param count length of message in bytes
/// \return #mxt_rc
int sysfs_get_msg_bytes_v2(struct mxt_device *mxt, unsigned char *buf,
size_t buflen, int *count)
{
uint16_t t5_size;
if (!mxt->sysfs.debug_v2_msg_buf)
return MXT_INTERNAL_ERROR;
t5_size = mxt_get_object_size(mxt, GEN_MESSAGEPROCESSOR_T5) - 1;
if (buflen < t5_size)
return MXT_ERROR_NO_MEM;
if (mxt->sysfs.debug_v2_msg_ptr > mxt->sysfs.debug_v2_msg_count)
return MXT_INTERNAL_ERROR;
memcpy(buf,
mxt->sysfs.debug_v2_msg_buf + mxt->sysfs.debug_v2_msg_ptr * t5_size,
t5_size);
mxt->sysfs.debug_v2_msg_ptr++;
*count = t5_size;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Reset debug messages
/// \param mxt Device context
int sysfs_msg_reset_v2(struct mxt_device *mxt)
{
free(mxt->sysfs.debug_v2_msg_buf);
mxt->sysfs.debug_v2_msg_buf = NULL;
return 0;
}
//******************************************************************************
/// \brief Return whether device has debug V2 support
/// \param mxt Device context
bool sysfs_has_debug_v2(struct mxt_device *mxt)
{
return mxt->sysfs.debug_v2;
}
//******************************************************************************
/// \brief Get messages (V2 interface)
/// \param mxt Device context
/// \param count Number of messages retrieved
/// \return #mxt_rc
int sysfs_get_msgs_v2(struct mxt_device *mxt, int *count)
{
int num_bytes;
uint16_t t5_size;
char *filename;
struct stat filestat;
int ret;
int fd;
sysfs_reopen_notify_fd(mxt);
filename = make_path(mxt, "debug_msg");
ret = stat(filename, &filestat);
if (ret < 0) {
mxt_err(mxt->ctx, "Could not stat %s, error %s (%d)",
filename, strerror(errno), errno);
return mxt_errno_to_rc(errno);
}
mxt->sysfs.debug_v2_size = filestat.st_size;
if (mxt->sysfs.debug_v2_msg_buf) {
free(mxt->sysfs.debug_v2_msg_buf);
mxt->sysfs.debug_v2_msg_buf = NULL;
}
mxt->sysfs.debug_v2_msg_buf = calloc(mxt->sysfs.debug_v2_size, sizeof(uint8_t));
fd = open(filename, O_RDWR);
if (fd < 0) {
mxt_err(mxt->ctx, "Could not open %s, error %s (%d)", filename, strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
goto close;
}
t5_size = mxt_get_object_size(mxt, GEN_MESSAGEPROCESSOR_T5) - 1;
num_bytes = read(fd, mxt->sysfs.debug_v2_msg_buf, mxt->sysfs.debug_v2_size);
if (num_bytes < 0) {
mxt_err(mxt->ctx, "read error %s (%d)", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
goto close;
}
mxt->sysfs.debug_v2_msg_count = num_bytes / t5_size;
mxt->sysfs.debug_v2_msg_ptr = 0;
ret = MXT_SUCCESS;
*count = mxt->sysfs.debug_v2_msg_count;
mxt_verb(mxt->ctx, "count = %d", mxt->sysfs.debug_v2_msg_count);
close:
close(fd);
return ret;
}
//******************************************************************************
/// \brief Get debug state
/// \param mxt Device context
/// \param value true (debug enabled) or false (debug disabled)
/// \return #mxt_rc
int sysfs_get_debug(struct mxt_device *mxt, bool *value)
{
// Check device is initialised
if (!mxt) {
mxt_err(mxt->ctx, "Device uninitialised");
return false;
}
return read_boolean_file(mxt, make_path(mxt, "debug_enable"), value);
}
//******************************************************************************
/// \brief Get sysfs directory
/// \param mxt Device context
/// \return location of the sysfs interface files
char *sysfs_get_directory(struct mxt_device *mxt)
{
// Check device is initialised
if (!mxt) {
mxt_err(mxt->ctx, "Device uninitialised");
return 0;
}
return mxt->conn->sysfs.path;
}
//******************************************************************************
/// \brief Get I2C adapter and address
/// \param conn mxt connection info
/// \param adapter OUT i2c adapter number
/// \param address OUT i2c address
/// \return #mxt_rc
int sysfs_get_i2c_address(struct libmaxtouch_ctx *ctx,
struct mxt_conn_info *conn,
int *adapter, int *address)
{
int ret;
if (conn->sysfs.acpi)
return MXT_ERROR_NOT_SUPPORTED;
ret = sscanf(basename(conn->sysfs.path), "%d-%x", adapter, address);
if (ret != 2) {
mxt_err(ctx, "Couldn't parse sysfs path for adapter/address");
return MXT_INTERNAL_ERROR;
}
return MXT_SUCCESS;
}
mxt-app-1.27/src/libmaxtouch/sysfs/sysfs_device.h 0000664 0000000 0000000 00000007027 12706171405 0022156 0 ustar 00root root 0000000 0000000 #pragma once
//------------------------------------------------------------------------------
/// \file sysfs_device.h
/// \brief headers for MXT device low level access via I2C
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
struct dmesg_item;
//******************************************************************************
/// \brief sysfs device connection information
struct sysfs_conn_info {
char *path;
bool acpi;
};
//******************************************************************************
/// \brief sysfs device
struct sysfs_device {
struct sysfs_conn_info conn;
char *mem_access_path;
char *temp_path;
size_t path_max;
bool debug_v2;
uint16_t debug_v2_msg_count;
uint16_t debug_v2_msg_ptr;
uint8_t *debug_v2_msg_buf;
char *debug_msg_buf;
int debug_msg_buf_size;
int debug_notify_fd;
size_t debug_v2_size;
int dmesg_count;
struct dmesg_item *dmesg_head;
struct dmesg_item *dmesg_ptr;
unsigned long timestamp;
unsigned long mtimestamp;
};
int sysfs_scan(struct libmaxtouch_ctx *ctx, struct mxt_conn_info **conn);
int sysfs_open(struct mxt_device *mxt);
void sysfs_release(struct mxt_device *mxt);
int sysfs_new_device(struct libmaxtouch_ctx *ctx, struct mxt_conn_info **conn, const char *dirname);
int sysfs_read_register(struct mxt_device *mxt, unsigned char *buf, int start_register, size_t count, size_t *bytes_transferred);
int sysfs_write_register(struct mxt_device *mxt, unsigned char const *buf, int start_register, size_t count);
int sysfs_set_debug(struct mxt_device *mxt, bool debug_state);
int sysfs_get_debug(struct mxt_device *mxt, bool *value);
char *sysfs_get_directory(struct mxt_device *mxt);
bool sysfs_has_debug_v2(struct mxt_device *mxt);
char *sysfs_get_msg_string_v2(struct mxt_device *mxt);
int sysfs_get_msg_bytes_v2(struct mxt_device *mxt, unsigned char *buf, size_t buflen, int *count);
int sysfs_get_msgs_v2(struct mxt_device *mxt, int *count);
int sysfs_msg_reset_v2(struct mxt_device *mxt);
int sysfs_get_debug_v2_fd(struct mxt_device *mxt);
int sysfs_get_i2c_address(struct libmaxtouch_ctx *ctx, struct mxt_conn_info *conn, int *adapter, int *address);
mxt-app-1.27/src/libmaxtouch/usb/ 0000775 0000000 0000000 00000000000 12706171405 0016733 5 ustar 00root root 0000000 0000000 mxt-app-1.27/src/libmaxtouch/usb/usb_device.c 0000664 0000000 0000000 00000100645 12706171405 0021215 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file usb_device.c
/// \brief MXT device low level access via USB
/// \author Tim Culmer
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include "libmaxtouch/log.h"
#include "libmaxtouch/libmaxtouch.h"
#include "libmaxtouch/info_block.h"
#include "usb_device.h"
/* USB device configuration */
#define VENDOR_ID 0x03EB
#define ENDPOINT_1_IN 0x81
#define ENDPOINT_2_OUT 0x02
/* timeout in ms */
#define USB_TRANSFER_TIMEOUT 2000
#define REPORT_ID 0x01
#define IIC_DATA_1 0x51
#define CMD_READ_PINS 0x82
#define CMD_CONFIG 0x80
#define CMD_CONFIG_I2C_RETRY_ON_NAK (1 << 7)
#define CMD_FIND_IIC_ADDRESS 0xE0
/* mXT command status codes */
#define COMMS_STATUS_OK 0x00
#define COMMS_STATUS_DATA_NACK 0x01
#define COMMS_STATUS_ADDR_NACK 0x01
#define COMMS_STATUS_WRITE_OK 0x04
//******************************************************************************
/// \brief Converts a libusb error code into a string
/// \return Error string
static const char *usb_error_name(int errcode)
{
switch (errcode) {
case LIBUSB_SUCCESS:
return "LIBUSB_SUCCESS";
case LIBUSB_ERROR_IO:
return "LIBUSB_ERROR_IO";
case LIBUSB_ERROR_INVALID_PARAM:
return "LIBUSB_ERROR_INVALID_PARAM";
case LIBUSB_ERROR_ACCESS:
return "LIBUSB_ERROR_ACCESS";
case LIBUSB_ERROR_NO_DEVICE:
return "LIBUSB_ERROR_NO_DEVICE";
case LIBUSB_ERROR_NOT_FOUND:
return "LIBUSB_ERROR_NOT_FOUND";
case LIBUSB_ERROR_BUSY:
return "LIBUSB_ERROR_BUSY";
case LIBUSB_ERROR_TIMEOUT:
return "LIBUSB_ERROR_TIMEOUT";
case LIBUSB_ERROR_OVERFLOW:
return "LIBUSB_ERROR_OVERFLOW";
case LIBUSB_ERROR_PIPE:
return "LIBUSB_ERROR_PIPE";
case LIBUSB_ERROR_INTERRUPTED:
return "LIBUSB_ERROR_INTERRUPTED";
case LIBUSB_ERROR_NO_MEM:
return "LIBUSB_ERROR_NO_MEM";
case LIBUSB_ERROR_NOT_SUPPORTED:
return "LIBUSB_ERROR_NOT_SUPPORTED";
case LIBUSB_ERROR_OTHER:
return "LIBUSB_ERROR_OTHER";
default:
return "unrecognised error code";
}
}
//******************************************************************************
/// \brief Convert errors from the libusb API to #mxt_rc values
/// \return #mxt_rc
static int usberror_to_rc(int errcode)
{
switch (errcode) {
case LIBUSB_SUCCESS:
return MXT_SUCCESS;
case LIBUSB_ERROR_NO_DEVICE:
return MXT_ERROR_NO_DEVICE;
case LIBUSB_ERROR_ACCESS:
return MXT_ERROR_ACCESS;
case LIBUSB_ERROR_NO_MEM:
return MXT_ERROR_NO_MEM;
case LIBUSB_ERROR_TIMEOUT:
return MXT_ERROR_TIMEOUT;
case LIBUSB_ERROR_INVALID_PARAM:
return MXT_INTERNAL_ERROR;
case LIBUSB_ERROR_INTERRUPTED:
return MXT_ERROR_INTERRUPTED;
case LIBUSB_ERROR_NOT_SUPPORTED:
return MXT_ERROR_NOT_SUPPORTED;
case LIBUSB_ERROR_IO:
case LIBUSB_ERROR_NOT_FOUND:
case LIBUSB_ERROR_BUSY:
case LIBUSB_ERROR_OVERFLOW:
case LIBUSB_ERROR_PIPE:
case LIBUSB_ERROR_OTHER:
default:
return MXT_ERROR_IO;
}
}
//******************************************************************************
/// \brief Read a packet of data from the MXT chip
/// \return #mxt_rc
static int usb_transfer(struct mxt_device *mxt, void *cmd, int cmd_size,
void *response, int response_size, bool ignore_response)
{
int ret;
int bytes_transferred;
/* Send command to request read */
ret = libusb_interrupt_transfer
(
mxt->usb.handle, ENDPOINT_2_OUT, cmd,
cmd_size, &bytes_transferred, USB_TRANSFER_TIMEOUT
);
if (ret != LIBUSB_SUCCESS) {
mxt_err(mxt->ctx, "USB command error %s", usb_error_name(ret));
return usberror_to_rc(ret);
} else if (bytes_transferred != cmd_size) {
mxt_err
(
mxt->ctx,
"Read request failed - %d bytes transferred, returned %s",
bytes_transferred, usb_error_name(ret)
);
return MXT_ERROR_IO;
} else {
mxt_log_buffer(mxt->ctx, LOG_VERBOSE, "TX:", cmd, cmd_size);
}
if (ignore_response) {
mxt_verb(mxt->ctx, "Ignoring response command");
return MXT_SUCCESS;
}
/* Read response from read request */
ret = libusb_interrupt_transfer
(
mxt->usb.handle, ENDPOINT_1_IN, response,
response_size, &bytes_transferred, USB_TRANSFER_TIMEOUT
);
if (ret != LIBUSB_SUCCESS) {
mxt_err(mxt->ctx, "USB response error %s", usb_error_name(ret));
return usberror_to_rc(ret);
} else if (bytes_transferred != response_size) {
mxt_err
(
mxt->ctx,
"Read response failed - %d bytes transferred, returned %s",
bytes_transferred, usb_error_name(ret)
);
return MXT_ERROR_IO;
} else {
mxt_log_buffer(mxt->ctx, LOG_VERBOSE, "RX:", response, response_size);
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Read register from MXT chip
/// \return #mxt_rc
int usb_read_register(struct mxt_device *mxt, unsigned char *buf,
uint16_t start_register, size_t count,
size_t *bytes_transferred)
{
unsigned char pkt[mxt->usb.ep1_in_max_packet_size];
size_t cmd_size;
size_t max_count;
off_t response_ofs;
int ret;
/* Check a device is present before trying to read from it */
if (!mxt->usb.device_connected) {
mxt_err(mxt->ctx, "Device uninitialised");
return MXT_ERROR_NO_DEVICE;
}
memset(&pkt, 0, sizeof(pkt));
/* Command packet */
if (mxt->usb.bridge_chip) {
cmd_size = 5;
max_count = mxt->usb.ep1_in_max_packet_size - cmd_size;
if (count > max_count)
count = max_count;
pkt[0] = IIC_DATA_1;
pkt[1] = 2;
pkt[2] = count;
pkt[3] = start_register & 0xFF;
pkt[4] = (start_register & 0xFF00) >> 8;
response_ofs = 0;
} else {
cmd_size = 6;
max_count = mxt->usb.ep1_in_max_packet_size - cmd_size;
if (count > max_count)
count = max_count;
pkt[0] = REPORT_ID;
pkt[1] = IIC_DATA_1;
pkt[2] = 2;
pkt[3] = count;
pkt[4] = start_register & 0xFF;
pkt[5] = (start_register & 0xFF00) >> 8;
response_ofs = 1;
}
mxt_verb(mxt->ctx, "Reading %" PRIuPTR " bytes starting from address %d",
count, start_register);
/* Command packet */
ret = usb_transfer(mxt, &pkt, cmd_size, &pkt, sizeof(pkt), false);
if (ret)
return ret;
/* Check the result in the response */
if (pkt[response_ofs] != COMMS_STATUS_OK) {
mxt_err
(
mxt->ctx,
"Wrong result in read response - expected 0x%02X got 0x%02X",
COMMS_STATUS_OK, pkt[response_ofs]
);
return MXT_ERROR_IO;
}
/* Output the data read from the registers */
(void)memcpy(buf, &pkt[response_ofs + 2], count);
*bytes_transferred = count;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Write a packet of data to the MXT chip
/// \return #mxt_rc
static int write_data(struct mxt_device *mxt, unsigned char const *buf,
uint16_t start_register, size_t count,
int *bytes_written, bool ignore_response)
{
unsigned char pkt[mxt->usb.ep1_in_max_packet_size];
int ret;
size_t max_count;
size_t cmd_size;
int packet_size;
off_t response_ofs;
/* Check a device is present before trying to write to it */
if (!mxt->usb.device_connected) {
mxt_err(mxt->ctx, "Device uninitialised");
return MXT_ERROR_NO_DEVICE;
}
memset(&pkt, 0, sizeof(pkt));
/* Command packet */
if (mxt->usb.bridge_chip) {
cmd_size = 5;
max_count = mxt->usb.ep1_in_max_packet_size - cmd_size;
if (count > max_count)
count = max_count;
pkt[0] = IIC_DATA_1;
pkt[1] = 2 + count;
pkt[2] = 0;
pkt[3] = start_register & 0xFF;
pkt[4] = (start_register & 0xFF00) >> 8;
response_ofs = 0;
} else {
cmd_size = 6;
max_count = mxt->usb.ep1_in_max_packet_size - cmd_size;
if (count > max_count)
count = max_count;
pkt[0] = REPORT_ID;
pkt[1] = IIC_DATA_1;
pkt[2] = 2 + count;
pkt[3] = 0;
pkt[4] = start_register & 0xFF;
pkt[5] = (start_register & 0xFF00) >> 8;
response_ofs = 1;
}
packet_size = cmd_size + count;
(void)memcpy(pkt + cmd_size, buf, count);
mxt_verb(mxt->ctx, "Writing %" PRIuPTR " bytes to address %d",
count, start_register);
ret = usb_transfer(mxt, pkt, packet_size, pkt, sizeof(pkt), ignore_response);
if (ret)
return ret;
/* Check the result in the response */
if (!ignore_response && pkt[response_ofs] != COMMS_STATUS_WRITE_OK) {
mxt_err
(
mxt->ctx,
"Wrong result in write response - expected 0x%02X got 0x%02X",
COMMS_STATUS_WRITE_OK, pkt[response_ofs]
);
return MXT_ERROR_IO;
}
*bytes_written = count;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Try to find descriptor of QRG interface
/// \return #mxt_rc
static int usb_scan_for_qrg_if(struct mxt_device *mxt)
{
int ret;
char buf[128];
const char qrg_if[] = "QRG-I/F";
ret = libusb_get_string_descriptor_ascii(mxt->usb.handle,
mxt->usb.desc.iProduct, (unsigned char *)buf, sizeof(buf));
if (ret < 0)
return usberror_to_rc(ret);
if (!strncmp(buf, qrg_if, sizeof(qrg_if))) {
mxt_dbg(mxt->ctx, "Found %s", qrg_if);
mxt->usb.interface = 0;
return MXT_SUCCESS;
} else {
return MXT_ERROR_NO_DEVICE;
}
}
//******************************************************************************
/// \brief Try to find control interface
/// \return #mxt_rc
static int usb_scan_for_control_if(struct mxt_device *mxt,
struct libusb_config_descriptor *config)
{
int j, k, ret;
char buf[128];
const char control_if[] = "Atmel maXTouch Control";
const char bootloader_if[] = "Atmel maXTouch Bootloader";
for (j = 0; j < config->bNumInterfaces; j++) {
const struct libusb_interface *interface = &config->interface[j];
for (k = 0; k < interface->num_altsetting; k++) {
const struct libusb_interface_descriptor *altsetting = &interface->altsetting[k];
if (altsetting->iInterface > 0) {
ret = libusb_get_string_descriptor_ascii(mxt->usb.handle,
altsetting->iInterface, (unsigned char *)buf, sizeof(buf));
if (ret > 0) {
if (!strncmp(buf, control_if, sizeof(control_if))) {
mxt_dbg(mxt->ctx, "Found %s at interface %d altsetting %d",
buf, altsetting->bInterfaceNumber, altsetting->bAlternateSetting);
mxt->usb.bootloader = false;
mxt->usb.interface = altsetting->bInterfaceNumber;
return MXT_SUCCESS;
} else if (!strncmp(buf, bootloader_if, sizeof(bootloader_if))) {
mxt_dbg(mxt->ctx, "Found %s at interface %d altsetting %d",
buf, altsetting->bInterfaceNumber, altsetting->bAlternateSetting);
mxt->usb.bootloader = true;
mxt->usb.interface = altsetting->bInterfaceNumber;
return MXT_SUCCESS;
} else {
mxt_verb(mxt->ctx, "Ignoring %s at interface %d altsetting %d",
buf, altsetting->bInterfaceNumber, altsetting->bAlternateSetting);
}
}
}
}
}
return MXT_ERROR_NO_DEVICE;
}
//******************************************************************************
/// \brief Device is bootloader
/// \return true or false
bool usb_is_bootloader(struct mxt_device *mxt)
{
return mxt->usb.bootloader;
}
//******************************************************************************
/// \brief Scan configurations
/// \return #mxt_rc
static int usb_scan_device_configs(struct mxt_device *mxt)
{
int i, ret;
if (mxt->usb.bridge_chip && mxt->usb.desc.bNumConfigurations == 1) {
return usb_scan_for_qrg_if(mxt);
}
/* Scan through interfaces */
for (i = 0; i < mxt->usb.desc.bNumConfigurations; ++i) {
struct libusb_config_descriptor *config;
ret = libusb_get_config_descriptor(mxt->usb.device, i, &config);
if (ret < 0) {
mxt_err(mxt->ctx, "Couldn't get config descriptor %d", i);
} else {
ret = usb_scan_for_control_if(mxt, config);
libusb_free_config_descriptor(config);
if (ret == MXT_SUCCESS)
// Found interface number
return ret;
}
}
return MXT_ERROR_NO_DEVICE;
}
//******************************************************************************
/// \brief Switch USB5030 to USB FS Bridge mode
/// \return #mxt_rc
static int bridge_set_fs_mode(struct mxt_device *mxt)
{
unsigned char pkt[mxt->usb.ep1_in_max_packet_size];
int ret;
memset(&pkt, 0, sizeof(pkt));
pkt[0] = 0;
pkt[1] = 0xFA;
pkt[2] = 0xE7;
ret = usb_transfer(mxt, &pkt, sizeof(pkt), &pkt, sizeof(pkt), true);
if (ret)
return ret;
libusb_reset_device(mxt->usb.handle);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Set the parameters for the comms mode on USB5030
/// \return #mxt_rc
static int bridge_configure(struct mxt_device *mxt)
{
unsigned char pkt[mxt->usb.ep1_in_max_packet_size];
/* Command packet */
memset(&pkt, 0, sizeof(pkt));
pkt[0] = CMD_CONFIG;
/* 200kHz */
pkt[1] = 0x20;
pkt[2] = CMD_CONFIG_I2C_RETRY_ON_NAK;
/* I2C retry delay */
pkt[5] = 25 * 8;
mxt_verb(mxt->ctx, "Sending CMD_CONFIG");
return usb_transfer(mxt, &pkt, sizeof(pkt), &pkt, sizeof(pkt), false);
}
//******************************************************************************
/// \brief Hunt for I2C device using bridge chip
/// \return #mxt_rc
static int bridge_find_i2c_address(struct mxt_device *mxt)
{
int ret;
unsigned char pkt[mxt->usb.ep1_in_max_packet_size];
unsigned char response;
/* Command packet */
memset(&pkt, 0, sizeof(pkt));
pkt[0] = CMD_FIND_IIC_ADDRESS;
mxt_verb(mxt->ctx, "Sending CMD_FIND_IIC_ADDRESS");
ret = usb_transfer(mxt, &pkt, sizeof(pkt), &pkt, sizeof(pkt), false);
if (ret)
return ret;
response = pkt[1];
if (response == 0x81) {
mxt_err(mxt->ctx, "No device found by bridge chip");
return MXT_ERROR_NO_DEVICE;
} else {
if (response < 0x4a) {
mxt->usb.bootloader = true;
mxt_info(mxt->ctx, "Bridge found bootloader at 0x%02X", response);
} else {
mxt_info(mxt->ctx, "Bridge found control interface at 0x%02X", response);
}
return MXT_SUCCESS;
}
}
//******************************************************************************
/// \brief Find device by bus/number
/// \return #mxt_rc
static int usb_find_device(struct libmaxtouch_ctx *ctx, struct mxt_device *mxt)
{
int ret, count, i;
struct libusb_device **devs;
int usb_bus, usb_device;
count = libusb_get_device_list(ctx->usb.libusb_ctx, &devs);
if (count <= 0) {
mxt_err(mxt->ctx, "%s enumerating devices", usb_error_name(count));
return usberror_to_rc(count);
}
for (i = 0; i < count; i++) {
struct libusb_device_descriptor desc;
ret = libusb_get_device_descriptor(devs[i], &desc);
if (ret != LIBUSB_SUCCESS) {
mxt_warn(mxt->ctx, "%s trying to retrieve descriptor",
usb_error_name(ret));
continue;
}
usb_bus = libusb_get_bus_number(devs[i]);
usb_device = libusb_get_device_address(devs[i]);
if (mxt->conn->usb.bus == usb_bus && mxt->conn->usb.device == usb_device) {
if (desc.idProduct == 0x6123) {
mxt->usb.bridge_chip = true;
mxt_dbg(mxt->ctx, "Found usb:%03d-%03d 5030 bridge chip",
usb_bus, usb_device);
} else {
mxt->usb.bridge_chip = false;
mxt_verb(mxt->ctx, "Found usb:%03d-%03d VID=%04X PID=%04X",
usb_bus, usb_device,
desc.idVendor, desc.idProduct);
}
mxt->usb.device = devs[i];
libusb_ref_device(mxt->usb.device);
mxt->usb.desc = desc;
ret = MXT_SUCCESS;
goto free_device_list;
} else {
mxt_verb(mxt->ctx, "Ignoring usb:%03d-%03d VID=%04X PID=%04X",
usb_bus, usb_device,
desc.idVendor, desc.idProduct);
}
}
mxt_err(mxt->ctx, "Could not find device usb:%03d-%03d",
mxt->conn->usb.bus, mxt->conn->usb.device);
ret = MXT_ERROR_NO_DEVICE;
free_device_list:
libusb_free_device_list(devs, 1);
return ret;
}
//******************************************************************************
/// \brief Initialise library if necessary
/// \return #mxt_rc
static int usb_initialise_libusb(struct libmaxtouch_ctx *ctx)
{
int ret;
/* Skip if already initialised */
if (ctx->usb.libusb_ctx)
return MXT_SUCCESS;
/* Initialise library */
ret = libusb_init(&(ctx->usb.libusb_ctx));
if (ret != LIBUSB_SUCCESS) {
mxt_err(ctx, "%s initialising libusb", usb_error_name(ret));
return usberror_to_rc(ret);
}
mxt_verb(ctx, "Initialised libusb");
/* Set the debug level for the library */
if (mxt_get_log_level(ctx) < LOG_DEBUG) {
mxt_dbg(ctx, "Enabling libusb debug");
/* Level 3: informational messages are printed to stdout, warning and
* error messages are printed to stderr */
libusb_set_debug(ctx->usb.libusb_ctx, 3);
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Try to connect device
/// \return #mxt_rc
int usb_open(struct mxt_device *mxt)
{
int ret;
unsigned int tries = 5;
ret = usb_initialise_libusb(mxt->ctx);
if (ret)
return ret;
ret = usb_find_device(mxt->ctx, mxt);
if (ret != 0)
return MXT_ERROR_NO_DEVICE;
retry:
ret = libusb_open(mxt->usb.device, &mxt->usb.handle);
if (ret == LIBUSB_ERROR_NO_DEVICE) {
usleep(500000);
if (tries--) {
mxt_warn(mxt->ctx, "%s opening USB device, retrying", usb_error_name(ret));
goto retry;
} else {
mxt_err(mxt->ctx, "%s opening USB device", usb_error_name(ret));
return usberror_to_rc(ret);
}
} else if (ret != LIBUSB_SUCCESS) {
mxt_err(mxt->ctx, "%s opening USB device", usb_error_name(ret));
return usberror_to_rc(ret);
}
mxt->usb.interface = -1;
ret = usb_scan_device_configs(mxt);
if (ret) {
mxt_warn(mxt->ctx, "Did not find control interface");
return ret;
}
/* Disconnect the kernel driver if it is active */
if (libusb_kernel_driver_active(mxt->usb.handle, mxt->usb.interface) == 1) {
mxt_verb(mxt->ctx, "Kernel driver is active - must be detached before claiming the interface");
if (libusb_detach_kernel_driver(mxt->usb.handle, mxt->usb.interface) == 0) {
mxt_verb(mxt->ctx, "Detached kernel driver");
}
}
/* Claim the bInterfaceNumber 1 of the device */
ret = libusb_claim_interface(mxt->usb.handle, mxt->usb.interface);
if (ret != LIBUSB_SUCCESS) {
mxt_err
(
mxt->ctx,
"Unable to claim bInterfaceNumber %d of the device, returned %s",
mxt->usb.interface, usb_error_name(ret)
);
return usberror_to_rc(ret);
} else {
mxt_verb(mxt->ctx, "Claimed the USB interface");
}
/* Get the maximum size of packets on endpoint 1 */
ret = libusb_get_max_packet_size(libusb_get_device(mxt->usb.handle),
ENDPOINT_1_IN);
if (ret < LIBUSB_SUCCESS) {
mxt_err(mxt->ctx, "%s getting maximum packet size on endpoint 1 IN",
usb_error_name(ret));
return usberror_to_rc(ret);
}
mxt->usb.ep1_in_max_packet_size = ret;
mxt_verb(mxt->ctx, "Maximum packet size on endpoint 1 IN is %d bytes",
mxt->usb.ep1_in_max_packet_size);
/* Configure bridge chip if necessary */
if (mxt->usb.bridge_chip) {
mxt->usb.report_id = 0;
ret = bridge_set_fs_mode(mxt);
if (ret)
return ret;
ret = bridge_configure(mxt);
if (ret)
return ret;
ret = bridge_find_i2c_address(mxt);
if (ret)
return ret;
} else {
mxt->usb.report_id = 1;
}
mxt->usb.device_connected = true;
mxt_info(mxt->ctx, "Registered usb:%03d-%03d VID=0x%04X PID=0x%04X Interface=%d",
mxt->conn->usb.bus, mxt->conn->usb.device,
mxt->usb.desc.idVendor, mxt->usb.desc.idProduct, mxt->usb.interface);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Check USB product ID against supported list
static bool usb_supported_pid_vid(struct libusb_device_descriptor desc)
{
return ((desc.idVendor == VENDOR_ID) &&
((desc.idProduct == 0x211D) ||
(desc.idProduct >= 0x2126 && desc.idProduct <= 0x212D) ||
(desc.idProduct >= 0x2135 && desc.idProduct <= 0x2139) ||
(desc.idProduct >= 0x213A && desc.idProduct <= 0x21FC) ||
(desc.idProduct >= 0x8000 && desc.idProduct <= 0x8FFF) ||
(desc.idProduct == 0x6123)));
}
//******************************************************************************
/// \brief Scan for supported devices on the USB bus
/// \return #mxt_rc
int usb_scan(struct libmaxtouch_ctx *ctx, struct mxt_conn_info **conn)
{
int ret, count, i;
struct libusb_device **devs;
int usb_bus, usb_device;
ret = usb_initialise_libusb(ctx);
if (ret)
return ret;
count = libusb_get_device_list(ctx->usb.libusb_ctx, &devs);
if (count <= 0) {
mxt_err(ctx, "%s enumerating devices", usb_error_name(count));
return usberror_to_rc(count);
}
for (i = 0; i < count; i++) {
struct libusb_device_descriptor desc;
ret = libusb_get_device_descriptor(devs[i], &desc);
if (ret != LIBUSB_SUCCESS) {
mxt_warn(ctx, "%s trying to retrieve descriptor",
usb_error_name(ret));
continue;
}
if (usb_supported_pid_vid(desc)) {
usb_bus = libusb_get_bus_number(devs[i]);
usb_device = libusb_get_device_address(devs[i]);
ctx->scan_count++;
if (ctx->query) {
printf("usb:%03u-%03u Atmel %04X:%04X\n",
usb_bus, usb_device,
desc.idVendor, desc.idProduct);
} else {
struct mxt_conn_info *new_conn;
ret = mxt_new_conn(&new_conn, E_USB);
if (ret)
return ret;
new_conn->usb.bus = usb_bus;
new_conn->usb.device = usb_device;
mxt_verb(ctx, "Found VID=%04X PID=%04X %03d-%03d",
desc.idVendor, desc.idProduct, usb_bus, usb_device);
*conn = new_conn;
ret = MXT_SUCCESS;
goto free_device_list;
}
} else {
mxt_verb(ctx, "Ignoring VID=%04X PID=%04X", desc.idVendor, desc.idProduct);
}
}
ret = MXT_ERROR_NO_DEVICE;
free_device_list:
libusb_free_device_list(devs, 1);
return ret;
}
//******************************************************************************
/// \brief Release device
void usb_release(struct mxt_device *mxt)
{
/* Are we connected to a device? */
if (mxt->usb.device_connected) {
libusb_release_interface(mxt->usb.handle, mxt->usb.interface);
mxt_dbg(mxt->ctx, "Released the USB interface");
libusb_close(mxt->usb.handle);
mxt_dbg(mxt->ctx, "Disconnected from the device");
mxt->usb.handle = NULL;
mxt->usb.device_connected = false;
}
if (mxt->usb.device) {
libusb_unref_device(mxt->usb.device);
mxt->usb.device = NULL;
}
}
//******************************************************************************
/// \brief Release USB library
int usb_close(struct libmaxtouch_ctx *ctx)
{
/* Is the library initialised? */
if (ctx->usb.libusb_ctx) {
libusb_exit(ctx->usb.libusb_ctx);
ctx->usb.libusb_ctx = NULL;
mxt_dbg(ctx, "Exited from libusb");
}
return 0;
}
//******************************************************************************
/// \brief Enumerate the maxtouch devices on the same bus
/// \return #mxt_rc
int usb_find_bus_devices(struct mxt_device *mxt, bool *found)
{
int ret, count, i;
struct libusb_device **devs;
int usb_bus = 0;
int usb_device = 0;
count = libusb_get_device_list(mxt->ctx->usb.libusb_ctx, &devs);
if (count <= 0) {
mxt_err(mxt->ctx, "%s enumerating devices", usb_error_name(count));
return usberror_to_rc(count);
}
for (i = 0; i < count; i++) {
struct libusb_device_descriptor desc;
ret = libusb_get_device_descriptor(devs[i], &desc);
if (ret != LIBUSB_SUCCESS) {
mxt_warn(mxt->ctx, "%s trying to retrieve descriptor",
usb_error_name(ret));
continue;
}
usb_bus = libusb_get_bus_number(devs[i]);
usb_device = libusb_get_device_address(devs[i]);
if ((usb_bus == mxt->conn->usb.bus) && (usb_supported_pid_vid(desc))) {
found[usb_device] = true;
}
}
libusb_free_device_list(devs, 1);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Rediscover device on bus
/// \return #mxt_rc
int usb_rediscover_device(struct mxt_device *mxt, bool *device_list)
{
int ret, count, i;
struct libusb_device **devs;
int usb_bus = 0;
int usb_device = 0;
count = libusb_get_device_list(mxt->ctx->usb.libusb_ctx, &devs);
if (count <= 0) {
mxt_err(mxt->ctx, "%s enumerating devices", usb_error_name(count));
return usberror_to_rc(count);
}
for (i = 0; i < count; i++) {
struct libusb_device_descriptor desc;
ret = libusb_get_device_descriptor(devs[i], &desc);
if (ret != LIBUSB_SUCCESS) {
mxt_warn(mxt->ctx, "%s trying to retrieve descriptor",
usb_error_name(ret));
continue;
}
usb_bus = libusb_get_bus_number(devs[i]);
usb_device = libusb_get_device_address(devs[i]);
if (usb_supported_pid_vid(desc)) {
if (usb_bus == mxt->conn->usb.bus) {
if (usb_device == mxt->conn->usb.device) {
/* Old device still connected, fine */
mxt_dbg(mxt->ctx, "USB device still there at %03d-%03d",
usb_bus, usb_device);
ret = MXT_SUCCESS;
goto free_device_list;
} else if (device_list[usb_device] == false) {
/* Found a new device on bus. We make the assumption that it is the
* device that just reset. It might be another device with the same
* PID/VID just plugged in, but there's no way of knowing */
mxt->conn->usb.device = usb_device;
mxt_info(mxt->ctx, "Found new device on bus at address %03d-%03d",
usb_bus, usb_device);
ret = MXT_SUCCESS;
goto free_device_list;
}
}
} else {
mxt_verb(mxt->ctx, "Ignoring usb:%03d-%03d VID=%04X PID=%04X",
usb_bus, usb_device, desc.idVendor, desc.idProduct);
}
}
ret = MXT_ERROR_NO_DEVICE;
free_device_list:
libusb_free_device_list(devs, 1);
return ret;
}
//******************************************************************************
/// \brief Reset the maxtouch chip, in normal or bootloader mode
/// \return #mxt_rc
int usb_reset_chip(struct mxt_device *mxt, bool bootloader_mode)
{
int ret;
uint16_t t6_addr;
unsigned char write_value = RESET_COMMAND;
bool bus_devices[USB_MAX_BUS_DEVICES] = { 0 };
int tries;
int bytes_written;
/* Obtain command processor's address */
t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0);
if (t6_addr == OBJECT_NOT_FOUND)
return MXT_ERROR_OBJECT_NOT_FOUND;
/* The value written determines which mode the chip will boot into */
if (bootloader_mode)
write_value = BOOTLOADER_COMMAND;
/* Store bus device list */
ret = usb_find_bus_devices(mxt, bus_devices);
if (ret)
return ret;
tries = 10;
retry:
/* Send write command to reset the chip */
ret = write_data(mxt, &write_value, t6_addr + MXT_T6_RESET_OFFSET, 1,
&bytes_written, true);
if (ret == MXT_ERROR_NO_DEVICE && tries--) {
usleep(500000);
mxt_warn(mxt->ctx, "Error sending reset command, retrying");
goto retry;
} else if (ret) {
mxt_err(mxt->ctx, "Reset of the chip unsuccessful");
return ret;
}
mxt_info(mxt->ctx, "Sent reset command");
usb_release(mxt);
tries = 10;
while (tries--) {
/* sleep 500 ms */
usleep(500000);
ret = usb_rediscover_device(mxt, bus_devices);
if (ret == MXT_SUCCESS)
break;
}
if (ret) {
mxt_err(mxt->ctx, "Did not find device after reset");
return ret;
}
/* Re-connect to chip */
ret = usb_open(mxt);
if (ret) {
mxt_err(mxt->ctx, "Failed to re-connect to chip after reset");
return ret;
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Write register to MXT chip
/// \return #mxt_rc
int usb_write_register(struct mxt_device *mxt, unsigned char const *buf,
uint16_t start_register, size_t count)
{
int ret;
int sent = 0;
size_t off = 0;
while (off < count) {
ret = write_data(mxt, buf + off, start_register + off,
count - off, &sent, false);
if (ret)
return ret;
off += sent;
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Read from bootloader
int usb_bootloader_read(struct mxt_device *mxt, uint8_t *buf, size_t count)
{
unsigned char pkt[mxt->usb.ep1_in_max_packet_size];
const off_t data_offset = 2;
size_t max_count = mxt->usb.ep1_in_max_packet_size - data_offset;
int ret;
if (count > max_count)
return MXT_ERROR_IO;
memset(&pkt, 0, sizeof(pkt));
pkt[0] = IIC_DATA_1;
pkt[1] = 0x00;
pkt[2] = (uint8_t)count;
ret = usb_transfer(mxt, pkt, sizeof(pkt), pkt, sizeof(pkt), false);
if (ret)
return ret;
/* Output the data read from the registers */
(void)memcpy(buf, &pkt[data_offset], count);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Write packet to bootloader
/// \return #mxt_rc
static int usb_bootloader_write_packet(struct mxt_device *mxt, uint8_t const *buf,
size_t count, int *bytes_transferred)
{
unsigned char pkt[mxt->usb.ep1_in_max_packet_size];
const off_t data_offset = 3;
size_t max_count = mxt->usb.ep1_in_max_packet_size - data_offset;
int ret;
if (count > max_count)
count = max_count;
memset(&pkt, 0, sizeof(pkt));
pkt[0] = IIC_DATA_1;
pkt[1] = (uint8_t)count;
pkt[2] = 0x00;
(void)memcpy(&pkt[data_offset], buf, count);
ret = usb_transfer(mxt, pkt, sizeof(pkt), pkt, sizeof(pkt), false);
if (ret)
return ret;
*bytes_transferred = count;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Write to bootloader
int usb_bootloader_write(struct mxt_device *mxt, unsigned char const *buf, size_t count)
{
int ret;
int bytes_transferred;
size_t bytes = 0;
while (bytes < count) {
ret = usb_bootloader_write_packet(mxt, buf + bytes, count - bytes,
&bytes_transferred);
if (ret)
return ret;
bytes += bytes_transferred;
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Read CHG line
/// \return #mxt_rc
int usb_read_chg(struct mxt_device *mxt, bool *value)
{
unsigned char pkt[mxt->usb.ep1_in_max_packet_size];
bool chg;
int ret;
memset(&pkt, 0, sizeof(pkt));
pkt[0] = CMD_READ_PINS;
ret = usb_transfer(mxt, pkt, sizeof(pkt), pkt, sizeof(pkt), false);
if (ret)
return ret;
chg = pkt[2] & 0x4;
mxt_verb(mxt->ctx, "CHG line %s", chg ? "HIGH" : "LOW");
*value = chg;
return MXT_SUCCESS;
}
mxt-app-1.27/src/libmaxtouch/usb/usb_device.h 0000664 0000000 0000000 00000006554 12706171405 0021226 0 ustar 00root root 0000000 0000000 #pragma once
//------------------------------------------------------------------------------
/// \file usb_device.h
/// \brief Headers for MXT device low level access via USB
/// \author Tim Culmer
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#ifdef ANDROID
#include
#else
#include
#endif
#define USB_MAX_BUS_DEVICES 127
//******************************************************************************
/// \brief USB library context
struct usb_context {
libusb_context *libusb_ctx;
};
//******************************************************************************
/// \brief USB library context
struct usb_conn_info {
int bus;
int device;
};
//******************************************************************************
/// \brief USB device information
struct usb_device {
bool device_connected;
bool bridge_chip;
libusb_device *device;
libusb_device_handle *handle;
struct libusb_device_descriptor desc;
int ep1_in_max_packet_size;
int interface;
bool bootloader;
int report_id;
};
int usb_scan(struct libmaxtouch_ctx *ctx, struct mxt_conn_info **conn);
int usb_open(struct mxt_device *mxt);
int usb_close(struct libmaxtouch_ctx *ctx);
void usb_release(struct mxt_device *mxt);
int usb_reset_chip(struct mxt_device *mxt, bool bootloader_mode);
int usb_read_register(struct mxt_device *mxt, unsigned char *buf, uint16_t start_register, size_t count, size_t *bytes_transferred);
int usb_write_register(struct mxt_device *mxt, unsigned char const *buf, uint16_t start_register, size_t count);
int usb_bootloader_read(struct mxt_device *mxt, unsigned char *buf, size_t count);
int usb_bootloader_write(struct mxt_device *mxt, unsigned char const *buf, size_t count);
bool usb_is_bootloader(struct mxt_device *mxt);
int usb_read_chg(struct mxt_device *mxt, bool *value);
int usb_find_bus_devices(struct mxt_device *mxt, bool *device_list);
int usb_rediscover_device(struct mxt_device *mxt, bool *device_list);
mxt-app-1.27/src/libmaxtouch/utilfuncs.c 0000664 0000000 0000000 00000023107 12706171405 0020325 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file utilfuncs.c
/// \brief Utility functions for Linux maXTtouch app.
/// \author Iiro Valkonen.
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include
#include "libmaxtouch.h"
#include "utilfuncs.h"
#define BUF_SIZE 1024
#define BYTETOBINARYPATTERN "%d%d%d%d %d%d%d%d"
#define BYTETOBINARY(byte) \
(byte & 0x80 ? 1 : 0), \
(byte & 0x40 ? 1 : 0), \
(byte & 0x20 ? 1 : 0), \
(byte & 0x10 ? 1 : 0), \
(byte & 0x08 ? 1 : 0), \
(byte & 0x04 ? 1 : 0), \
(byte & 0x02 ? 1 : 0), \
(byte & 0x01 ? 1 : 0)
//******************************************************************************
/// \brief Print out info block
void mxt_print_info_block(struct mxt_device *mxt)
{
int i;
int report_id = 1;
int report_id_start, report_id_end;
struct mxt_object obj;
struct mxt_id_info *id = mxt->info.id;
/* Show the Version Info */
printf("\nFamily: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n",
id->family, id->variant,
id->version >> 4,
id->version & 0x0F,
id->build, id->num_objects);
printf("Matrix size: X%uY%u\n",
id->matrix_x_size, id->matrix_y_size);
/* Show the CRC */
printf("Information Block CRC: 0x%06X\n\n", mxt->info.crc);
/* Show the object table */
printf("Type Start Size Instances ReportIds Name\n");
printf("-----------------------------------------------------------------\n");
for (i = 0; i < id->num_objects; i++) {
obj = mxt->info.objects[i];
if (obj.num_report_ids > 0) {
report_id_start = report_id;
report_id_end = report_id_start + obj.num_report_ids * MXT_INSTANCES(obj) - 1;
report_id = report_id_end + 1;
} else {
report_id_start = 0;
report_id_end = 0;
}
printf("T%-3u %4u %4u %2u %2u-%-2u ",
obj.type,
mxt_get_start_position(obj, 0),
MXT_SIZE(obj),
MXT_INSTANCES(obj),
report_id_start, report_id_end);
const char *obj_name = mxt_get_object_name(obj.type);
if (obj_name)
printf("%s\n", obj_name);
else
printf("UNKNOWN_T%d\n", obj.type);
}
printf("\n");
}
//******************************************************************************
/// \brief Convert object type to object name
/// \return null terminated string, or NULL for object not found
const char *mxt_get_object_name(uint8_t objtype)
{
switch(objtype) {
OBJECT_LIST(F_SWITCH)
default:
return NULL;
}
}
//******************************************************************************
/// \brief Menu function to read values from object
/// \return #mxt_rc
int mxt_read_object(struct mxt_device *mxt, uint16_t object_type,
uint8_t instance, uint16_t address,
size_t count, bool format)
{
uint8_t *databuf;
uint16_t object_address = 0;
uint16_t i;
int ret;
if (object_type > 0) {
object_address = mxt_get_object_address(mxt, object_type, instance);
if (object_address == OBJECT_NOT_FOUND) {
printf("No such object\n");
return MXT_ERROR_OBJECT_NOT_FOUND;
}
mxt_dbg(mxt->ctx, "T%u address:%u offset:%u", object_type,
object_address, address);
address = object_address + address;
if (count == 0) {
count = mxt_get_object_size(mxt, object_type);
}
} else if (count == 0) {
mxt_err(mxt->ctx, "No length information");
return MXT_ERROR_BAD_INPUT;
}
databuf = (uint8_t *)calloc(count, sizeof(uint8_t));
if (databuf == NULL) {
mxt_err(mxt->ctx, "Memory allocation failure");
return MXT_ERROR_NO_MEM;
}
ret = mxt_read_register(mxt, databuf, address, count);
if (ret) {
printf("Read error\n");
goto free;
}
if (format) {
if (object_type > 0) {
const char *obj_name = mxt_get_object_name(object_type);
if (obj_name)
printf("%s\n\n", obj_name);
else
printf("UNKNOWN_T%d\n\n", object_type);
}
for (i = 0; i < count; i++) {
printf("%02d:\t0x%02X\t%3d\t" BYTETOBINARYPATTERN "\n",
address - object_address + i,
databuf[i],
databuf[i],
BYTETOBINARY(databuf[i]));
}
} else {
for (i = 0; i < count; i++) {
printf("%02X ", databuf[i]);
}
printf("\n");
}
ret = MXT_SUCCESS;
free:
free(databuf);
return ret;
}
//******************************************************************************
/// \brief Handles parsing of the write parameters
/// \return #mxt_rc
int mxt_handle_write_cmd(struct mxt_device *mxt, const uint16_t type,
uint16_t count, const uint8_t inst, uint16_t address,
int argc, char *argv[])
{
uint16_t obj_addr = 0;
unsigned char databuf[BUF_SIZE];
unsigned char *p_databuf = databuf;
int ret = MXT_SUCCESS;
if (type > 0) {
obj_addr = mxt_get_object_address(mxt, type, inst);
if (obj_addr == OBJECT_NOT_FOUND) {
fprintf(stderr, "No such object\n");
return MXT_ERROR_OBJECT_NOT_FOUND;
}
mxt_verb(mxt->ctx, "T%u address:%u offset:%u", type, obj_addr, address);
address = obj_addr + address;
if (count == 0) {
count = mxt_get_object_size(mxt, type);
}
} else if (count == 0) {
fprintf(stderr, "Not enough arguments!\n");
return MXT_ERROR_BAD_INPUT;
}
/* Parse unprocessed arguments */
while (optind < argc) {
ret = mxt_convert_hex(argv[optind++], p_databuf, &count, sizeof(databuf) - (p_databuf - databuf));
if (ret || count == 0) {
fprintf(stderr, "Hex convert error\n");
return MXT_ERROR_BAD_INPUT;
}
p_databuf += count;
}
ret = mxt_write_register(mxt, databuf, address, (p_databuf - databuf));
if (ret)
fprintf(stderr, "Write error\n");
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Convert hex nibble to digit
/// \return #mxt_rc
static int to_digit(const char hex, char *const decimal)
{
if (hex >= '0' && hex <= '9')
*decimal = hex - '0';
else if (hex >= 'A' && hex <= 'F')
*decimal = hex - 'A' + 10;
else if (hex >= 'a' && hex <= 'f')
*decimal = hex - 'a' + 10;
else {
*decimal = 0;
return MXT_ERROR_BAD_INPUT;
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Convert ASCII buffer containing hex digits to binary
/// \return #mxt_rc
int mxt_convert_hex(char *hex, unsigned char *databuf,
uint16_t *count, unsigned int buf_size)
{
unsigned int pos = 0;
uint16_t datapos = 0;
char highnibble;
char lownibble;
char high_dec_nibble;
char low_dec_nibble;
int ret = MXT_SUCCESS;
while (1) {
highnibble = *(hex + pos);
lownibble = *(hex + pos + 1);
/* end of string */
if (highnibble == '\0' || highnibble == '\n')
break;
/* uneven number of hex digits */
if (lownibble == '\0' || lownibble == '\n') {
ret = MXT_ERROR_BAD_INPUT;
break;
}
if (pos > buf_size) {
ret = MXT_ERROR_NO_MEM;
break;
}
ret = to_digit(highnibble, &high_dec_nibble);
if (ret)
break;
ret = to_digit(lownibble, &low_dec_nibble);
if (ret)
break;
*(databuf + datapos) = (high_dec_nibble << 4) | low_dec_nibble;
datapos++;
pos += 2;
}
*count = datapos;
return ret;
}
//******************************************************************************
/// \brief Output timestamp to stream with millisecond accuracy
/// \param stream pointer to FILE object
/// \param date output date, true or false
/// \return #mxt_rc
int mxt_print_timestamp(FILE *stream, bool date)
{
struct timeval tv;
time_t nowtime;
struct tm *nowtm;
char tmbuf[64];
int ret;
gettimeofday(&tv, NULL);
nowtime = tv.tv_sec;
nowtm = localtime(&nowtime);
if (date) {
strftime(tmbuf, sizeof(tmbuf), "%c", nowtm);
ret = fprintf(stream, "%s", tmbuf);
} else {
strftime(tmbuf, sizeof(tmbuf), "%H:%M:%S", nowtm);
ret = fprintf(stream, "%s.%06ld", tmbuf, tv.tv_usec);
}
return (ret < 0) ? MXT_ERROR_IO : MXT_SUCCESS;
}
mxt-app-1.27/src/libmaxtouch/utilfuncs.h 0000664 0000000 0000000 00000004231 12706171405 0020327 0 ustar 00root root 0000000 0000000 #pragma once
//------------------------------------------------------------------------------
/// \file utilfuncs.h
/// \brief Utility functions
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
void mxt_print_info_block(struct mxt_device *dev);
const char *mxt_get_object_name(uint8_t objtype);
int mxt_read_object(struct mxt_device *dev, uint16_t object_type, uint8_t instance, uint16_t offset, size_t count, bool format);
int mxt_handle_write_cmd(struct mxt_device *mxt, const uint16_t type, uint16_t count, const uint8_t inst, uint16_t address, int argc, char *argv[]);
int mxt_convert_hex(char *hex, unsigned char *databuf, uint16_t *count, unsigned int buf_size);
int mxt_print_timestamp(FILE *stream, bool date);
mxt-app-1.27/src/mxt-app/ 0000775 0000000 0000000 00000000000 12706171405 0015211 5 ustar 00root root 0000000 0000000 mxt-app-1.27/src/mxt-app/Android.mk 0000664 0000000 0000000 00000000770 12706171405 0017126 0 ustar 00root root 0000000 0000000 LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CFLAGS += -DHAVE_LIBUSB -DMXT_VERSION=\"$(GIT_VERSION)\"
LOCAL_C_INCLUDES := $(TOP_DIR)/src $(TOP_DIR)/lib/libusbdroid/code/src
LOCAL_SRC_FILES := \
mxt_app.c \
menu.c \
bootloader.c \
diagnostic_data.c \
touch_app.c \
self_test.c \
bridge.c \
buffer.c \
gr.c \
serial_data.c \
self_cap.c \
signal.c
LOCAL_LDLIBS := -llog
LOCAL_STATIC_LIBRARIES := maxtouch libusbdroid
LOCAL_MODULE := mxt-app
include $(BUILD_EXECUTABLE)
mxt-app-1.27/src/mxt-app/bootloader.c 0000664 0000000 0000000 00000047353 12706171405 0017523 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file bootloader.c
/// \brief Bootloader functions
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include "libmaxtouch/libmaxtouch.h"
#include "libmaxtouch/info_block.h"
#include "libmaxtouch/log.h"
#include "libmaxtouch/sysfs/sysfs_device.h"
#ifdef HAVE_LIBUSB
#include "libmaxtouch/usb/usb_device.h"
#endif
#include "mxt_app.h"
#define MXT_UNLOCK_CMD_MSB 0xaa
#define MXT_UNLOCK_CMD_LSB 0xdc
/* Bootloader mode status */
#define MXT_WAITING_BOOTLOAD_CMD 0xc0 /* valid 7 6 bit only */
#define MXT_WAITING_FRAME_DATA 0x80 /* valid 7 6 bit only */
#define MXT_FRAME_CRC_CHECK 0x02
#define MXT_FRAME_CRC_FAIL 0x03
#define MXT_FRAME_CRC_PASS 0x04
#define MXT_APP_CRC_FAIL 0x40 /* valid 7 6 bit only */
#define MXT_BOOT_STATUS_MASK 0x3f
#define MXT_BOOT_ID_MASK 0x1f
#define FIRMWARE_BUFFER_SIZE 1024
#define MXT_RESET_TIME 2
#define MXT_BOOTLOADER_DELAY 50000
//******************************************************************************
/// \brief Bootloader context object
struct flash_context {
struct mxt_device *mxt;
struct mxt_conn_info *conn;
struct libmaxtouch_ctx *ctx;
bool have_bootloader_version;
bool extended_id_mode;
FILE *fp;
long file_size;
char curr_version[MXT_FW_VER_LEN];
int i2c_adapter;
int appmode_address;
int bootloader_address;
bool check_version;
const char *new_version;
bool usb_bootloader;
};
//******************************************************************************
/// \brief Wait for CHG line to indicate bootloader state change
/// \return #mxt_rc
static int wait_for_chg(struct mxt_device *mxt)
{
#ifdef HAVE_LIBUSB
int try = 0;
int ret;
bool chg;
if (mxt->conn->type == E_USB) {
while (true) {
ret = usb_read_chg(mxt, &chg);
if (ret)
return ret;
if (!chg)
break;
if (++try > 100) {
mxt_warn(mxt->ctx, "Timed out awaiting CHG");
return MXT_ERROR_TIMEOUT;
}
usleep(1000);
}
mxt_verb(mxt->ctx, "CHG line cycles %d", try);
} else
#endif
{
usleep(MXT_BOOTLOADER_DELAY);
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Send a frame with length field set to 0x0000. This should force a
// bootloader reset
/// \return #mxt_rc
static int send_zero_frame(struct flash_context *fw)
{
unsigned char buf[2];
buf[0] = 0;
buf[1] = 0;
mxt_info(fw->ctx, "Attempting bootloader reset");
return mxt_bootloader_write(fw->mxt, buf, sizeof(buf));
}
//******************************************************************************
/// \brief Send command to unlock bootloader
/// \return #mxt_rc
static int unlock_bootloader(struct flash_context *fw)
{
unsigned char buf[2];
buf[0] = MXT_UNLOCK_CMD_LSB;
buf[1] = MXT_UNLOCK_CMD_MSB;
return mxt_bootloader_write(fw->mxt, buf, sizeof(buf));
}
//******************************************************************************
/// \brief Read bootloader state
/// \return #mxt_rc
static int mxt_check_bootloader(struct flash_context *fw, unsigned int state)
{
unsigned char buf[3];
unsigned char val;
unsigned char bootloader_id;
unsigned char bootloader_version;
int ret;
recheck:
if (state != MXT_WAITING_BOOTLOAD_CMD)
wait_for_chg(fw->mxt);
if ((!fw->have_bootloader_version) && fw->extended_id_mode
&& (state == MXT_WAITING_FRAME_DATA)) {
mxt_dbg(fw->ctx, "Attempting to retrieve bootloader version");
ret = mxt_bootloader_read(fw->mxt, buf, sizeof(buf));
if (ret)
return ret;
val = buf[0];
bootloader_id = buf[1] & MXT_BOOT_ID_MASK;
bootloader_version = buf[2];
mxt_info(fw->ctx, "Bootloader ID:%d Version:%d",
bootloader_id, bootloader_version);
fw->have_bootloader_version = true;
} else {
ret = mxt_bootloader_read(fw->mxt, &val, 1);
if (ret) {
mxt_err(fw->ctx, "Bootloader read failure");
return ret;
}
}
mxt_verb(fw->ctx, "Bootloader status %02X", val);
switch (state) {
case MXT_WAITING_BOOTLOAD_CMD:
bootloader_id = val & MXT_BOOT_STATUS_MASK;
val &= ~MXT_BOOT_STATUS_MASK;
if (val == MXT_APP_CRC_FAIL) {
mxt_info(fw->ctx, "Bootloader reports APP CRC failure");
goto recheck;
} else if (val == MXT_WAITING_FRAME_DATA) {
mxt_info(fw->ctx, "Bootloader already unlocked");
return MXT_ERROR_BOOTLOADER_UNLOCKED;
}
break;
case MXT_WAITING_FRAME_DATA:
val &= ~MXT_BOOT_STATUS_MASK;
break;
case MXT_FRAME_CRC_PASS:
if (val == MXT_FRAME_CRC_CHECK) {
goto recheck;
} else if (val == MXT_FRAME_CRC_FAIL) {
mxt_info(fw->ctx, "Bootloader reports FRAME_CRC_FAIL");
return MXT_ERROR_BOOTLOADER_FRAME_CRC_FAIL;
}
break;
default:
return MXT_ERROR_UNEXPECTED_DEVICE_STATE;
}
if (val != state) {
mxt_info(fw->ctx, "Invalid bootloader mode state %02X", val);
if (state == MXT_WAITING_BOOTLOAD_CMD)
send_zero_frame(fw);
return MXT_ERROR_UNEXPECTED_DEVICE_STATE;
}
if (!fw->have_bootloader_version
&& state == MXT_WAITING_BOOTLOAD_CMD) {
if (bootloader_id | 0x20) {
mxt_dbg(fw->ctx, "Bootloader using extended ID mode");
fw->extended_id_mode = true;
} else {
bootloader_id &= MXT_BOOT_ID_MASK;
mxt_info(fw->ctx, "Bootloader ID:%d", bootloader_id);
fw->have_bootloader_version = true;
}
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Read hexadecimal value from file
static int get_hex_value(struct flash_context *fw, unsigned char *ptr)
{
char str[] = "00\0";
int val;
int ret;
str[0] = fgetc(fw->fp);
str[1] = fgetc(fw->fp);
if (feof(fw->fp)) return EOF;
ret = sscanf(str, "%x", &val);
*ptr = val;
return ret;
}
//******************************************************************************
/// \brief Send firmware frames to bootloader
/// \return #mxt_rc
static int send_frames(struct flash_context *fw)
{
unsigned char buffer[FIRMWARE_BUFFER_SIZE];
uint8_t last_percent = 100;
uint8_t cur_percent = 0;
int ret;
int i;
int frame_size = 0;
int frame;
int frame_retry = 0;
int bytes_sent = 0;
fw->have_bootloader_version = false;
fw->extended_id_mode = false;
ret = mxt_check_bootloader(fw, MXT_WAITING_BOOTLOAD_CMD);
if (ret == MXT_SUCCESS) {
mxt_info(fw->ctx, "Unlocking bootloader");
ret = unlock_bootloader(fw);
if (ret) {
mxt_err(fw->ctx, "Failure to unlock bootloader");
return ret;
}
mxt_info(fw->ctx, "Bootloader unlocked");
} else if (ret == MXT_ERROR_BOOTLOADER_UNLOCKED) {
mxt_info(fw->ctx, "Bootloader found");
} else {
mxt_err(fw->ctx, "Bootloader not found");
return MXT_ERROR_NO_DEVICE;
}
mxt_info(fw->ctx, "Sending frames...");
frame = 1;
while (!feof(fw->fp)) {
if (frame_retry == 0) {
if (get_hex_value(fw, &buffer[0]) == EOF) {
mxt_info(fw->ctx, "End of file");
break;
}
if (get_hex_value(fw, &buffer[1]) == EOF) {
mxt_err(fw->ctx, "Unexpected end of firmware file");
return MXT_ERROR_FILE_FORMAT;
}
frame_size = (buffer[0] << 8) | buffer[1];
mxt_dbg(fw->ctx, "Frame %d: size %d", frame, frame_size);
/* Allow for CRC bytes at end of frame */
frame_size += 2;
if (frame_size > FIRMWARE_BUFFER_SIZE) {
mxt_err(fw->ctx, "Frame too big");
return MXT_ERROR_NO_MEM;
}
for (i = 2; i < frame_size; i++) {
ret = get_hex_value(fw, &buffer[i]);
if (ret == EOF) {
mxt_err(fw->ctx, "Unexpected end of firmware file");
return MXT_ERROR_FILE_FORMAT;
}
}
}
if (mxt_check_bootloader(fw, MXT_WAITING_FRAME_DATA) < 0) {
mxt_err(fw->ctx, "Unexpected bootloader state");
return MXT_ERROR_UNEXPECTED_DEVICE_STATE;
}
/* Write one frame to device */
ret = mxt_bootloader_write(fw->mxt, buffer, frame_size);
if (ret)
return ret;
// Check CRC
mxt_verb(fw->ctx, "Checking CRC");
ret = mxt_check_bootloader(fw, MXT_FRAME_CRC_PASS);
if (ret == MXT_ERROR_BOOTLOADER_FRAME_CRC_FAIL) {
if (frame_retry > 0) {
mxt_err(fw->ctx, "Failure sending frame %d - aborting", frame);
return MXT_ERROR_BOOTLOADER_FRAME_CRC_FAIL;
} else {
frame_retry++;
mxt_err(fw->ctx, "Frame %d: CRC fail, retry %d", frame, frame_retry);
}
} else if (ret) {
mxt_err(fw->ctx, "Unexpected bootloader state");
return ret;
} else {
mxt_verb(fw->ctx, "CRC pass");
frame++;
bytes_sent += frame_size;
cur_percent = (unsigned char)(0.5f + (100.0 * ftell(fw->fp)) / fw->file_size);
/* Display at 10% or difference is greater than 10% */
if (cur_percent % 10 == 0 || (cur_percent - last_percent) > 10) {
/* No need to repeat for the same percentage */
if (last_percent != cur_percent) {
/* clear previous line after first progress report */
if (cur_percent != 0) {
/* \033[F = Previous line, \033[J = clear line */
mxt_info(fw->ctx, "\033[F\033[J\033[F");
}
mxt_info(fw->ctx, "Sent %d frames, %d bytes. % 3d%%", frame, bytes_sent, cur_percent);
last_percent = cur_percent;
}
}
}
}
fclose(fw->fp);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Lookup bootloader I2C address
static int lookup_bootloader_addr(struct flash_context *fw, int addr)
{
switch (addr) {
case 0x4a:
case 0x4b:
if (fw->mxt->info.id->family >= 0xa2) {
return (addr - 0x24);
}
/* Fall through for normal case */
case 0x4c:
case 0x4d:
case 0x5a:
case 0x5b:
return (addr - 0x26);
break;
default:
return -1;
}
}
//******************************************************************************
/// \brief Initialise chip in bootloader mode
/// \return #mxt_rc
static int mxt_bootloader_init_chip(struct flash_context *fw)
{
int ret;
if (!fw->conn) {
ret = mxt_scan(fw->ctx, &fw->conn, false);
if (ret) {
mxt_info(fw->ctx, "Could not find a device");
return ret;
}
}
switch (fw->conn->type) {
case E_SYSFS:
mxt_info(fw->ctx, "Switching to i2c-dev mode");
struct mxt_conn_info *new_conn;
ret = mxt_new_conn(&new_conn, E_I2C_DEV);
if (ret)
return ret;
ret = sysfs_get_i2c_address(fw->ctx, fw->conn,
&fw->i2c_adapter, &fw->appmode_address);
if (ret)
return ret;
new_conn->i2c_dev.adapter = fw->i2c_adapter;
new_conn->i2c_dev.address = fw->appmode_address;
mxt_unref_conn(fw->conn);
fw->conn = new_conn;
break;
#ifdef HAVE_LIBUSB
case E_USB:
break;
#endif
case E_I2C_DEV:
if (fw->conn->i2c_dev.address < 0x4a) {
mxt_info(fw->ctx, "Using bootloader address");
fw->appmode_address = -1;
return MXT_DEVICE_IN_BOOTLOADER;
}
break;
case E_HIDRAW:
mxt_err(fw->ctx, "Device type not supported");
return MXT_ERROR_NOT_SUPPORTED;
break;
}
ret = mxt_new_device(fw->ctx, fw->conn, &fw->mxt);
if (ret) {
mxt_err(fw->ctx, "Could not open device");
return ret;
}
#ifdef HAVE_LIBUSB
if (fw->conn->type == E_USB && usb_is_bootloader(fw->mxt)) {
mxt_info(fw->ctx, "USB device in bootloader mode");
fw->usb_bootloader = true;
mxt_free_device(fw->mxt);
return MXT_DEVICE_IN_BOOTLOADER;
} else {
fw->usb_bootloader = false;
}
#endif
ret = mxt_get_info(fw->mxt);
if (ret) {
mxt_err(fw->ctx, "Could not get info block");
return ret;
}
mxt_info(fw->ctx, "Chip detected");
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Test firmware to flash against current firmware
/// \return #mxt_rc
static int mxt_check_firmware_version(struct flash_context *fw)
{
mxt_get_firmware_version(fw->mxt, fw->curr_version);
mxt_info(fw->ctx, "Current firmware version: %s", fw->curr_version);
if (!strcmp(fw->curr_version, fw->new_version)) {
mxt_info(fw->ctx, "Version already %s, exiting",
fw->curr_version);
return MXT_FIRMWARE_UPDATE_NOT_REQUIRED;
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Reset into bootloader mode
/// \return #mxt_rc
static int mxt_enter_bootloader_mode(struct flash_context *fw)
{
int ret;
/* Change to the bootloader mode */
ret = mxt_reset_chip(fw->mxt, true);
if (ret) {
mxt_err(fw->ctx, "Reset failure - aborting");
return ret;
} else {
sleep(MXT_RESET_TIME);
}
if (fw->conn->type == E_I2C_DEV) {
fw->appmode_address = fw->conn->i2c_dev.address;
fw->conn->i2c_dev.address = lookup_bootloader_addr(fw, fw->appmode_address);
if (fw->conn->i2c_dev.address == -1) {
mxt_err(fw->ctx, "No bootloader address!");
return MXT_ERROR_BOOTLOADER_NO_ADDRESS;
}
mxt_dbg(fw->ctx, "I2C Adapter:%d", fw->conn->i2c_dev.adapter);
mxt_dbg(fw->ctx, "Bootloader addr:0x%02x", fw->conn->i2c_dev.address);
mxt_dbg(fw->ctx, "App mode addr:0x%02x", fw->appmode_address);
}
mxt_free_device(fw->mxt);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Flash firmware to chip
int mxt_flash_firmware(struct libmaxtouch_ctx *ctx,
struct mxt_device *maxtouch,
const char *filename, const char *new_version,
struct mxt_conn_info *conn)
{
struct flash_context fw = { 0 };
int ret;
fw.ctx = ctx;
fw.mxt = maxtouch;
fw.conn = conn;
mxt_info(fw.ctx, "Opening firmware file %s", filename);
fw.fp = fopen(filename, "r");
if (!fw.fp) {
mxt_err(fw.ctx, "Cannot open firmware file %s!", filename);
return mxt_errno_to_rc(errno);
}
fseek(fw.fp, 0L, SEEK_END);
fw.file_size = ftell(fw.fp);
rewind(fw.fp);
ret = mxt_bootloader_init_chip(&fw);
if (ret && (ret != MXT_DEVICE_IN_BOOTLOADER))
return ret;
if (ret != MXT_DEVICE_IN_BOOTLOADER) {
if (strlen(new_version) > 0) {
fw.check_version = true;
fw.new_version = new_version;
mxt_dbg(fw.ctx, "New firmware version is:%s", fw.new_version);
ret = mxt_check_firmware_version(&fw);
if (ret)
goto release;
} else {
fw.check_version = false;
mxt_dbg(fw.ctx, "check_version:%d", fw.check_version);
}
ret = mxt_enter_bootloader_mode(&fw);
if (ret) {
mxt_err(fw.ctx, "Could not enter bootloader mode");
goto release;
}
}
ret = mxt_new_device(fw.ctx, fw.conn, &fw.mxt);
if (ret) {
mxt_info(fw.ctx, "Could not initialise chip");
return ret;
}
ret = send_frames(&fw);
if (ret)
return ret;
/* Handle transition back to appmode address */
if (fw.mxt->conn->type == E_I2C_DEV) {
sleep(MXT_RESET_TIME);
if (fw.appmode_address < 0) {
mxt_info(fw.ctx, "Sent all firmware frames");
ret = 0;
goto release;
} else {
mxt_info(fw.ctx, "Switching back to app mode");
struct mxt_conn_info *new_conn;
ret = mxt_new_conn(&new_conn, E_I2C_DEV);
if (ret)
return ret;
new_conn->i2c_dev.adapter = fw.i2c_adapter;
new_conn->i2c_dev.address = fw.appmode_address;
mxt_unref_conn(fw.conn);
fw.conn = new_conn;
}
}
#ifdef HAVE_LIBUSB
else if (fw.mxt->conn->type == E_USB) {
bool bus_devices[USB_MAX_BUS_DEVICES] = { 0 };
int tries = 10;
ret = usb_find_bus_devices(fw.mxt, bus_devices);
if (ret)
return ret;
while (tries--) {
sleep(MXT_RESET_TIME);
ret = usb_rediscover_device(fw.mxt, bus_devices);
if (ret == MXT_SUCCESS)
break;
}
if (ret) {
mxt_err(fw.ctx, "Did not find device after reset");
return ret;
}
}
#endif
mxt_free_device(fw.mxt);
ret = mxt_new_device(fw.ctx, fw.conn, &fw.mxt);
if (ret) {
mxt_err(fw.ctx, "FAILURE - chip did not reset");
return MXT_ERROR_RESET_FAILURE;
}
#ifdef HAVE_LIBUSB
if (fw.mxt->conn->type == E_USB && usb_is_bootloader(fw.mxt)) {
mxt_err(fw.ctx, "USB device still in bootloader mode");
ret = MXT_ERROR_RESET_FAILURE;
goto release;
}
#endif
ret = mxt_get_info(fw.mxt);
if (ret) {
mxt_err(fw.ctx, "Failed to get info block");
goto release;
}
mxt_get_firmware_version(fw.mxt, (char *)&fw.curr_version);
if (!fw.check_version) {
mxt_info(fw.ctx, "SUCCESS - version is %s", fw.curr_version);
ret = MXT_SUCCESS;
goto release;
}
if (!strcmp(fw.curr_version, fw.new_version)) {
mxt_info(fw.ctx, "SUCCESS - version %s verified", fw.curr_version);
ret = MXT_SUCCESS;
} else {
mxt_err(fw.ctx, "FAILURE - detected version is %s", fw.curr_version);
ret = MXT_ERROR_FIRMWARE_UPDATE_FAILED;
}
release:
mxt_free_device(fw.mxt);
mxt_unref_conn(fw.conn);
return ret;
}
//******************************************************************************
/// \brief Bootloader version query
int mxt_bootloader_version(struct libmaxtouch_ctx *ctx, struct mxt_device *mxt, struct mxt_conn_info *conn)
{
struct flash_context fw = {0};
int ret;
unsigned char buf[3];
fw.ctx = ctx;
fw.mxt = mxt;
fw.conn = conn;
ret = mxt_bootloader_init_chip(&fw);
if (ret && ret != MXT_DEVICE_IN_BOOTLOADER) {
mxt_err(fw.ctx, "Could not init device");
return ret;
}
if (ret != MXT_DEVICE_IN_BOOTLOADER) {
ret = mxt_enter_bootloader_mode(&fw);
if (ret) {
mxt_err(fw.ctx, "Could not enter bootloader mode");
return ret;
}
}
ret = mxt_new_device(fw.ctx, fw.conn, &fw.mxt);
if (ret) {
mxt_err(fw.ctx, "Could not open device");
return ret;
}
ret = mxt_check_bootloader(&fw, MXT_WAITING_BOOTLOAD_CMD);
if (ret)
goto release;
ret = mxt_bootloader_read(fw.mxt, buf, sizeof(buf));
if (ret)
goto release;
if (fw.extended_id_mode)
printf("Bootloader ID:%d Version:%d\n",
(buf[1] & MXT_BOOT_ID_MASK), buf[2]);
else
printf("Bootloader ID:%d\n", (buf[1] & MXT_BOOT_ID_MASK));
release:
mxt_info(fw.ctx, "Reset into app mode");
send_zero_frame(&fw);
mxt_free_device(fw.mxt);
mxt_unref_conn(fw.conn);
return ret;
}
mxt-app-1.27/src/mxt-app/bridge.c 0000664 0000000 0000000 00000046757 12706171405 0016634 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file bridge.c
/// \brief TCP bridge functions
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "libmaxtouch/libmaxtouch.h"
#include "libmaxtouch/log.h"
#include "libmaxtouch/utilfuncs.h"
#include "mxt_app.h"
#include "buffer.h"
#define MAX_LINESIZE 10000
struct bridge_context {
int sockfd;
bool msgs_enabled;
};
//******************************************************************************
/// \brief Read command on a single line
/// \return #mxt_rc
static int readline(struct mxt_device *mxt, int fd, struct mxt_buffer *linebuf)
{
int ret;
int n;
int readcount;
char c;
mxt_buf_reset(linebuf);
for (n = 1; n < MAX_LINESIZE; n++) {
/* read 1 character at a time */
readcount = read(fd, &c, 1);
if (readcount == 1) {
if ((c == '\n') || (c == '\r'))
break;
ret = mxt_buf_add(linebuf, c);
if (ret)
return ret;
} else if (readcount == 0) {
if (n == 1)
return MXT_SUCCESS;
else
break;
} else {
mxt_err(mxt->ctx, "Read error: %s (%d)", strerror(errno), errno);
return mxt_errno_to_rc(errno);
}
}
/* null-terminate the buffer */
ret = mxt_buf_add(linebuf, '\0');
if (ret)
return ret;
return MXT_SUCCESS;
}
#define MXT_ADB_CLIENT_MSG_PREFIX "MSG "
//******************************************************************************
/// \brief Read MXT messages and send them to other end
/// \return #mxt_rc
static int handle_messages(struct mxt_device *mxt, struct bridge_context *bridge_ctx)
{
int msg_count, length;
int ret;
int i, j;
unsigned char databuf[20];
if (!bridge_ctx->msgs_enabled)
return MXT_SUCCESS;
ret = mxt_get_msg_count(mxt, &msg_count);
if (ret)
return ret;
for (i = 0; i < msg_count; i++) {
int num_bytes;
ret = mxt_get_msg_bytes(mxt, databuf, sizeof(databuf), &num_bytes);
if (ret == MXT_ERROR_NO_MESSAGE)
continue;
else if (ret)
return ret;
length = snprintf(mxt->msg_string, sizeof(mxt->msg_string),
MXT_ADB_CLIENT_MSG_PREFIX);
for (j = 0; j < num_bytes; j++) {
length += snprintf(mxt->msg_string + length,
sizeof(mxt->msg_string) - length,
"%02X", databuf[j]);
}
ret = write(bridge_ctx->sockfd, mxt->msg_string, strlen(mxt->msg_string));
if (ret < 0) {
mxt_err(mxt->ctx, "Write failure: %s (%d)", strerror(errno), errno);
return mxt_errno_to_rc(ret);
}
ret = write(bridge_ctx->sockfd, "\n", 1);
if (ret < 0) {
mxt_err(mxt->ctx, "Write failure: %s (%d)", strerror(errno), errno);
return mxt_errno_to_rc(ret);
}
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Handle bridge read
/// \return #mxt_rc
static int bridge_rea_cmd(struct mxt_device *mxt, struct bridge_context *bridge_ctx,
uint16_t address, uint16_t count)
{
int ret;
uint8_t *databuf;
char *response;
const char * const PREFIX = "RRP ";
size_t response_len;
int i;
databuf = calloc(count, sizeof(uint8_t));
if (!databuf) {
mxt_err(mxt->ctx, "Failed to allocate memory");
return MXT_ERROR_NO_MEM;
}
/* Allow for newline/null byte */
response_len = strlen(PREFIX) + count*2 + 1;
response = calloc(response_len, sizeof(uint8_t));
if (!response) {
mxt_err(mxt->ctx, "Failed to allocate memory");
ret = MXT_ERROR_NO_MEM;
goto free_databuf;
}
strcpy(response, PREFIX);
ret = mxt_read_register(mxt, databuf, address, count);
if (ret) {
mxt_warn(mxt->ctx, "RRP ERR");
strcpy(response + strlen(PREFIX), "ERR\n");
response_len = strlen(response);
} else {
for (i = 0; i < count; i++) {
sprintf(response + strlen(PREFIX) + i*2, "%02X", databuf[i]);
}
mxt_info(mxt->ctx, "%s", response);
response[response_len - 1] = '\n';
}
ret = write(bridge_ctx->sockfd, response, response_len);
if (ret < 0) {
mxt_err(mxt->ctx, "Socket write error: %s (%d)", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
goto free;
}
ret = MXT_SUCCESS;
free:
free(response);
free_databuf:
free(databuf);
return ret;
}
//******************************************************************************
/// \brief Handle bridge write
/// \return #mxt_rc
static int bridge_wri_cmd(struct mxt_device *mxt, struct bridge_context *bridge_ctx, uint16_t address,
char *hex, uint16_t bytes)
{
int ret;
uint16_t count;
const char * const FAIL = "WRP ERR\n";
const char * const PASS = "WRP OK\n";
const char *response;
uint8_t *databuf;
databuf = calloc(bytes, sizeof(uint8_t));
if (!databuf) {
mxt_err(mxt->ctx, "Failed to allocate memory");
return MXT_ERROR_NO_MEM;
}
ret = mxt_convert_hex(hex, databuf, &count, bytes);
if (ret) {
response = FAIL;
} else {
ret = mxt_write_register(mxt, databuf, address, count);
if (ret) {
mxt_verb(mxt->ctx, "WRI OK");
response = FAIL;
} else {
response = PASS;
}
}
ret = write(bridge_ctx->sockfd, response, strlen(response));
if (ret < 0) {
mxt_err(mxt->ctx, "Socket write error: %s (%d)", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
}
ret = MXT_SUCCESS;
free(databuf);
return ret;
}
//******************************************************************************
/// \brief Handle bridge reset command
/// \return #mxt_rc
static int bridge_handle_reset(struct mxt_device *mxt,
struct bridge_context *bridge_ctx,
uint16_t address)
{
int ret;
char *response;
const char * const PREFIX = "RST ";
size_t response_len = 8;
/* Allow for newline/null byte */
response = calloc(response_len, sizeof(uint8_t));
if (!response) {
mxt_err(mxt->ctx, "Failed to allocate memory");
ret = MXT_ERROR_NO_MEM;
goto free;
}
strcpy(response, PREFIX);
ret = mxt_reset_chip(mxt, false);
if (ret) {
mxt_warn(mxt->ctx, "RST ERR");
strcpy(response + strlen(PREFIX), "ERR\n");
response_len = strlen(response);
} else {
mxt_info(mxt->ctx, "RST OK");
strcpy(response + strlen(PREFIX), "OK\n");
response_len = strlen(response);
}
ret = write(bridge_ctx->sockfd, response, response_len);
if (ret < 0) {
mxt_err(mxt->ctx, "Socket write error: %s (%d)", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
goto free;
}
ret = MXT_SUCCESS;
free:
free(response);
return ret;
}
//******************************************************************************
/// \brief Output version information
static int bridge_info_version(struct mxt_device *mxt, struct bridge_context *bridge_ctx)
{
char *outstr;
int ret;
ret = asprintf(&outstr, "INFO VERSION mxt-app %s%s\n",
MXT_VERSION, ENABLE_DEBUG ? " DEBUG":"");
if (ret == -1) {
mxt_err(mxt->ctx, "asprintf failed");
return MXT_ERROR_NO_MEM;
}
ret = write(bridge_ctx->sockfd, outstr, strlen(outstr));
if (ret < 0) {
mxt_err(mxt->ctx, "Socket write error: %s (%d)", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
}
free(outstr);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Output connection information
static int bridge_info_connection(struct mxt_device *mxt, struct bridge_context *bridge_ctx)
{
uint16_t idProduct = 0;
uint16_t idVendor = 0;
int i2c_address = 0;
int i2c_adapter;
const char *typestring = "UNKNOWN";
char *outstr;
int ret;
switch (mxt->conn->type) {
case E_I2C_DEV:
i2c_address = mxt->conn->i2c_dev.address;
typestring = "I2C";
break;
#ifdef HAVE_LIBUSB
case E_USB:
idProduct = mxt->usb.desc.idProduct;
idVendor = mxt->usb.desc.idVendor;
typestring = "USB";
break;
#endif
case E_SYSFS:
ret = sysfs_get_i2c_address(mxt->ctx, mxt->conn,
&i2c_adapter, &i2c_address);
if (ret)
i2c_address = 0;
typestring = "I2C";
break;
case E_HIDRAW:
typestring = "HIDI2C";
break;
}
ret = asprintf(&outstr, "INFO CONNECTION %s %X %04X %04X\n",
typestring, i2c_address, idProduct, idVendor);
if (ret == -1) {
mxt_err(mxt->ctx, "asprintf failed");
return MXT_ERROR_NO_MEM;
}
ret = write(bridge_ctx->sockfd, outstr, strlen(outstr));
if (ret < 0) {
mxt_err(mxt->ctx, "Socket write error: %s (%d)", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
}
free(outstr);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Handle info command
/// \return #mxt_rc
static int bridge_info_cmd(struct mxt_device *mxt, struct bridge_context *bridge_ctx,
char *info)
{
int ret;
if (!strcmp(info, "CONNECTION")) {
ret = bridge_info_connection(mxt, bridge_ctx);
} else if (!strcmp(info, "VERSION")) {
ret = bridge_info_version(mxt, bridge_ctx);
} else {
mxt_warn(mxt->ctx, "%s unknown: \"%s\"", __func__, info);
ret = MXT_SUCCESS;
}
return ret;
}
//******************************************************************************
/// \brief Send chip attach message
/// \return #mxt_rc
static int send_chip_attach(struct mxt_device *mxt, struct bridge_context *bridge_ctx)
{
int ret;
const char * const msg = "CAT\n";
mxt_dbg(mxt->ctx, "Sending chip attach");
ret = write(bridge_ctx->sockfd, msg, strlen(msg));
if (ret < 0) {
mxt_err(mxt->ctx, "Socket write error: %s (%d)", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Send chip detach message
/// \return #mxt_rc
static int send_chip_detach(struct mxt_device *mxt,
struct bridge_context *bridge_ctx)
{
int ret;
const char * const msg = "CDT\n";
ret = write(bridge_ctx->sockfd, msg, strlen(msg));
if (ret < 0) {
mxt_err(mxt->ctx, "Socket write error: %s (%d)", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Read and deal with incoming command
/// \return #mxt_rc
static int handle_cmd(struct mxt_device *mxt, struct bridge_context *bridge_ctx)
{
int ret;
const char * const unknown_cmd = "UNKNOWN COMMAND\n";
const char * const msgcfg_ok = "MSGCFG OK\n";
const char * const msgcfg_err = "MSGCFG ERR\n";
const char * msgcfg_response;
const char * const info_cmd = "INFO ";
uint16_t address;
uint16_t count;
struct mxt_buffer linebuf;
char *line;
int offset;
ret = mxt_buf_init(&linebuf);
if (ret)
return ret;
ret = readline(mxt, bridge_ctx->sockfd, &linebuf);
if (ret) {
mxt_dbg(mxt->ctx, "Error reading or peer closed socket");
goto free;
}
line = (char *)linebuf.data;
if (strlen(line) == 0) {
ret = MXT_SUCCESS;
goto free;
}
mxt_verb(mxt->ctx, "%s", line);
if (!strcmp(line, "SAT")) {
mxt_info(mxt->ctx, "Server attached");
ret = MXT_SUCCESS;
} else if (!strcmp(line, "SDT")) {
mxt_info(mxt->ctx, "Server detached");
ret = MXT_SUCCESS;
} else if (sscanf(line, "REA %" SCNu16 " %" SCNu16, &address, &count) == 2) {
ret = bridge_rea_cmd(mxt, bridge_ctx, address, count);
} else if (sscanf(line, "WRI %" SCNu16 "%n", &address, &offset) == 1) {
/* skip space */
offset += 1;
ret = bridge_wri_cmd(mxt, bridge_ctx, address,
line + offset,
strlen(line) - offset);
} else if (sscanf(line, "RST %" SCNu16 "%n", &address, &offset) == 1) {
ret = bridge_handle_reset(mxt, bridge_ctx, address);
ret = MXT_SUCCESS;
} else if (sscanf(line, "MSGCFG %" SCNu16 "%n", &address, &offset) == 1) {
mxt_info(mxt->ctx, "Configuring Messages");
ret = mxt_msg_reset(mxt);
if (ret) {
mxt_warn(mxt->ctx, "Failure to reset msgs");
msgcfg_response = msgcfg_err;
} else {
bridge_ctx->msgs_enabled = true;
msgcfg_response = msgcfg_ok;
}
ret = write(bridge_ctx->sockfd, msgcfg_response, strlen(msgcfg_response));
if (ret < 0) {
mxt_err(mxt->ctx, "Socket write error: %s (%d)", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
}
ret = MXT_SUCCESS;
} else if (!strncmp(line, info_cmd, strlen(info_cmd))) {
ret = bridge_info_cmd(mxt, bridge_ctx, line + strlen(info_cmd));
} else {
ret = write(bridge_ctx->sockfd, unknown_cmd, strlen(unknown_cmd));
if (ret < 0) {
mxt_err(mxt->ctx, "Socket write error: %s (%d)", strerror(errno), errno);
ret = mxt_errno_to_rc(errno);
}
mxt_warn(mxt->ctx, "UNKNOWN: \"%s\"", line);
ret = MXT_SUCCESS;
}
free:
mxt_buf_free(&linebuf);
return ret;
}
//******************************************************************************
/// \brief Main bridge function to handle a single connection
/// \return #mxt_rc
static int bridge(struct mxt_device *mxt, struct bridge_context *bridge_ctx)
{
int ret, pollret;
struct pollfd fds[2];
int fopts = 0;
int debug_ng_fd = 0;
int numfds = 1;
int timeout;
fds[0].fd = bridge_ctx->sockfd;
fds[0].events = POLLIN | POLLERR;
ret = send_chip_attach(mxt, bridge_ctx);
if (ret)
return ret;
while (1) {
debug_ng_fd = mxt_get_msg_poll_fd(mxt);
if (debug_ng_fd) {
fds[1].fd = debug_ng_fd;
fds[1].events = POLLPRI;
numfds = 2;
timeout = -1;
} else {
timeout = 25; // milliseconds
}
pollret = poll(fds, numfds, timeout);
if (pollret == -1 && errno == EINTR) {
mxt_dbg(mxt->ctx, "Interrupted");
continue;
} else if (pollret == -1) {
mxt_err(mxt->ctx, "Poll returned %d (%s)", errno, strerror(errno));
ret = mxt_errno_to_rc(errno);
goto disconnect;
}
/* Detect socket disconnect */
if (fcntl(bridge_ctx->sockfd, F_GETFL, &fopts) < 0) {
ret = MXT_SUCCESS;
mxt_warn(mxt->ctx, "Socket disconnected");
goto disconnect;
}
if (fds[0].revents) {
ret = handle_cmd(mxt, bridge_ctx);
if (ret) {
mxt_err(mxt->ctx, "handle_cmd returned %d", ret);
goto disconnect;
}
}
/* If timeout or msg poll fd event */
if (pollret == 0 || fds[1].revents) {
ret = handle_messages(mxt, bridge_ctx);
if (ret) {
mxt_err(mxt->ctx, "handle_messages returned %d", ret);
goto disconnect;
}
}
}
disconnect:
send_chip_detach(mxt, bridge_ctx);
mxt_info(mxt->ctx, "Disconnected");
return ret;
}
//******************************************************************************
/// \brief Bridge client
/// \return #mxt_rc
int mxt_socket_client(struct mxt_device *mxt, char *ip_address, uint16_t port)
{
struct hostent *server;
struct bridge_context bridge_ctx;
bridge_ctx.msgs_enabled = false;
int ret;
struct sockaddr_in serv_addr;
server = gethostbyname(ip_address);
if (server == NULL) {
mxt_err(mxt->ctx, "Error, no such host");
return MXT_ERROR_CONNECTION_FAILURE;
}
bridge_ctx.sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (bridge_ctx.sockfd < 0) {
mxt_err(mxt->ctx, "Socket error: %s (%d)", strerror(errno), errno);
return MXT_ERROR_CONNECTION_FAILURE;
}
/* Set up socket options */
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(port);
/* Connect */
mxt_info(mxt->ctx, "Connecting to %s:%u", ip_address, port);
ret = connect(bridge_ctx.sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
if (ret < 0) {
mxt_err(mxt->ctx, "Connect error: %s (%d)", strerror(errno), errno);
return MXT_ERROR_CONNECTION_FAILURE;
}
ret = bridge(mxt, &bridge_ctx);
close(bridge_ctx.sockfd);
return ret;
}
//******************************************************************************
/// \brief Bridge server
int mxt_socket_server(struct mxt_device *mxt, uint16_t portno)
{
int serversock;
struct bridge_context bridge_ctx;
bridge_ctx.msgs_enabled = false;
int ret;
int one = 1;
struct sockaddr_in server_addr, client_addr;
socklen_t sin_size = sizeof(client_addr);
/* Create endpoint */
serversock = socket(AF_INET, SOCK_STREAM, 0);
if (serversock < 0) {
mxt_err(mxt->ctx, "Socket error: %s (%d)", strerror(errno), errno);
return MXT_ERROR_CONNECTION_FAILURE;
}
/* Set up socket options */
bzero((char *) &server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(portno);
/* Bind name to socket */
ret = bind(serversock, (struct sockaddr *) &server_addr, sizeof(server_addr));
if (ret < 0) {
mxt_err(mxt->ctx, "Bind error: %s (%d)", strerror(errno), errno);
close(serversock);
return MXT_ERROR_CONNECTION_FAILURE;
}
ret = setsockopt(serversock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
if (ret < 0) {
mxt_err(mxt->ctx, "Setsockopt error: %s (%d)", strerror(errno), errno);
close(serversock);
return MXT_ERROR_CONNECTION_FAILURE;
}
/* Start listening */
ret = listen(serversock, 1);
if (ret < 0) {
mxt_err(mxt->ctx, "Listen error: %s (%d)", strerror(errno), errno);
close(serversock);
return MXT_ERROR_CONNECTION_FAILURE;
}
/* This string is used by ADB bridge client to signal it can connect */
printf("AWAITING_CONNECTION\n");
bridge_ctx.sockfd = accept(serversock, (struct sockaddr *) &client_addr, &sin_size);
if (bridge_ctx.sockfd < 0) {
mxt_err(mxt->ctx, "Accept error: %s (%d)", strerror(errno), errno);
close(serversock);
return MXT_ERROR_CONNECTION_FAILURE;
}
printf("CONNECTED\n");
ret = bridge(mxt, &bridge_ctx);
close(serversock);
printf("DISCONNECTED\n");
return ret;
}
mxt-app-1.27/src/mxt-app/buffer.c 0000664 0000000 0000000 00000007137 12706171405 0016636 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file buffer.c
/// \brief Buffer allocation functions
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2012 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include "libmaxtouch/libmaxtouch.h"
#include "libmaxtouch/log.h"
#include "buffer.h"
#define BUFFER_BLOCKSIZE 16
//******************************************************************************
/// \brief Allocate memory associated with buffer
/// \return #mxt_rc
int mxt_buf_init(struct mxt_buffer *ctx)
{
int *ptr;
ctx->capacity = BUFFER_BLOCKSIZE;
ctx->size = 0;
ptr = calloc(ctx->capacity, sizeof(uint8_t));
if (ptr) {
ctx->data = (uint8_t *)ptr;
return MXT_SUCCESS;
} else {
return MXT_ERROR_NO_MEM;
}
}
//******************************************************************************
/// \brief Reallocate buffer memory if necessary
/// \return #mxt_rc
static int mxt_buf_realloc(struct mxt_buffer *ctx, size_t new_size)
{
int *ptr = 0;
size_t new_capacity;
/* Check whether we are still within bounds of buffer */
if (new_size <= ctx->capacity)
return MXT_SUCCESS;
new_capacity = ctx->capacity + BUFFER_BLOCKSIZE;
ptr = realloc(ctx->data, new_capacity * sizeof(uint8_t));
if (ptr) {
ctx->data = (uint8_t *)ptr;
ctx->capacity = new_capacity;
return MXT_SUCCESS;
} else {
return MXT_ERROR_NO_MEM;
}
}
//******************************************************************************
/// \brief Add value to buffer
/// \return #mxt_rc
int mxt_buf_add(struct mxt_buffer *ctx, uint8_t value)
{
int ret;
size_t new_size = ctx->size + 1;
ret = mxt_buf_realloc(ctx, new_size);
if (ret)
return ret;
*(ctx->data + ctx->size) = value;
/* update new size */
ctx->size = new_size;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Free memory associated with buffer
void mxt_buf_free(struct mxt_buffer *ctx)
{
if (ctx->data) {
free(ctx->data);
ctx->data = 0;
}
}
//******************************************************************************
/// \brief Reset buffer
void mxt_buf_reset(struct mxt_buffer *ctx)
{
ctx->size = 0;
}
mxt-app-1.27/src/mxt-app/buffer.h 0000664 0000000 0000000 00000003755 12706171405 0016645 0 ustar 00root root 0000000 0000000 #pragma once
//------------------------------------------------------------------------------
/// \file buffer.h
/// \brief Buffer allocation functions
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2012 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
//******************************************************************************
/// \brief Buffer object
struct mxt_buffer {
size_t size;
size_t capacity;
uint8_t *data;
};
int mxt_buf_init(struct mxt_buffer *ctx);
int mxt_buf_add(struct mxt_buffer *ctx, uint8_t value);
void mxt_buf_free(struct mxt_buffer *ctx);
void mxt_buf_reset(struct mxt_buffer *ctx);
mxt-app-1.27/src/mxt-app/diagnostic_data.c 0000664 0000000 0000000 00000047672 12706171405 0020512 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file diagnostic_data.c
/// \brief T37 Diagnostic Data functions
/// \author Atul Tiwari/Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2012 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "libmaxtouch/libmaxtouch.h"
#include "libmaxtouch/info_block.h"
#include "libmaxtouch/log.h"
#include "libmaxtouch/utilfuncs.h"
#include "mxt_app.h"
#define MAX_FILENAME_LENGTH 255
//******************************************************************************
/// \brief T37 Diagnostic Data object
struct t37_diagnostic_data {
uint8_t mode;
uint8_t page;
uint8_t data[];
};
//******************************************************************************
/// \brief Retrieve and store object information for debug data operation
/// \return #mxt_rc
static int get_objects_addr(struct t37_ctx *ctx)
{
int t6_addr;
/* Obtain command processor's address */
t6_addr = mxt_get_object_address(ctx->mxt, GEN_COMMANDPROCESSOR_T6, 0);
if (t6_addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND;
/* T37 commands address */
ctx->diag_cmd_addr = t6_addr + MXT_T6_DIAGNOSTIC_OFFSET;
/* Obtain Debug Diagnostic object's address */
ctx->t37_addr = mxt_get_object_address(ctx->mxt, DEBUG_DIAGNOSTIC_T37, 0);
if (ctx->t37_addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND;
/* Obtain Debug Diagnostic object's size */
ctx->t37_size = mxt_get_object_size(ctx->mxt, DEBUG_DIAGNOSTIC_T37);
if (ctx->t37_size == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND;
ctx->t111_instances = mxt_get_object_instances(ctx->mxt,
SPT_SELFCAPCONFIG_T111);
ctx->t107_instances = mxt_get_object_instances(ctx->mxt,
PROCI_ACTIVESTYLUS_T107);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Retrieve a single page of diagnostic data
/// \return #mxt_rc
static int mxt_get_t37_page(struct t37_ctx *ctx)
{
int failures;
int ret;
uint8_t read_command = 1;
uint8_t page_up_cmd = PAGE_UP;
if (ctx->pass == 0 && ctx->page == 0) {
mxt_dbg(ctx->lc, "Writing mode command %02X", ctx->mode);
ret = mxt_write_register(ctx->mxt, &ctx->mode, ctx->diag_cmd_addr, 1);
if (ret)
return ret;
} else {
ret = mxt_write_register(ctx->mxt, &page_up_cmd, ctx->diag_cmd_addr, 1);
if (ret)
return ret;
}
/* Read back diagnostic register in T6 command processor until it has been
* cleared. This means that the chip has actioned the command */
failures = 0;
while (read_command) {
usleep(500);
ret = mxt_read_register(ctx->mxt, &read_command, ctx->diag_cmd_addr, 1);
if (ret) {
mxt_err(ctx->lc, "Failed to read the status of diagnostic mode command");
return ret;
}
if (read_command) {
failures++;
if (failures > 500) {
mxt_err(ctx->lc, "Timeout waiting for command to be actioned");
return MXT_ERROR_TIMEOUT;
}
}
}
ret = mxt_read_register(ctx->mxt, (uint8_t *)ctx->t37_buf,
ctx->t37_addr, ctx->t37_size);
if (ret) {
mxt_err(ctx->lc, "Failed to read page");
return ret;
}
if (ctx->t37_buf->mode != ctx->mode) {
mxt_err(ctx->lc, "Bad mode in diagnostic data read");
return MXT_ERROR_UNEXPECTED_DEVICE_STATE;
}
if (ctx->t37_buf->page != (ctx->pages_per_pass * ctx->pass + ctx->page)) {
mxt_err(ctx->lc, "Bad page in diagnostic data read");
return MXT_ERROR_UNEXPECTED_DEVICE_STATE;
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Output header to CSV file
/// \return #mxt_rc
static int mxt_generate_hawkeye_header(struct t37_ctx *ctx)
{
struct mxt_id_info *id = ctx->mxt->info.id;
int ret;
int x;
int y;
int pass;
ret = fprintf(ctx->hawkeye, "time,TIN,");
if (ret < 0)
return MXT_ERROR_IO;
if (ctx->self_cap) {
for (pass = 0; pass < ctx->passes; pass++) {
const char *set;
switch (pass) {
default:
case 0:
set = "touch";
break;
case 1:
set = (ctx->passes == 3) ? "hover" : "prox";
break;
case 2:
set = "prox";
break;
}
const char * mode;
switch (ctx->mode) {
default:
case SELF_CAP_DELTAS:
mode = "delta";
break;
case SELF_CAP_REFS:
mode = "ref";
break;
case SELF_CAP_SIGNALS:
mode = "sig";
break;
}
for (y = 0; y < ctx->y_size; y++) {
ret = fprintf(ctx->hawkeye, "Y%d_SC_%s_%s,", y, set, mode);
if (ret < 0)
return MXT_ERROR_IO;
}
for (x = 0; x < ctx->x_size; x++) {
int x_real;
if (id->matrix_x_size > ctx->y_size) {
x_real = x;
} else {
x_real = x * 2;
if (x_real >= ctx->x_size)
x_real -= ctx->x_size - 1;
}
ret = fprintf(ctx->hawkeye, "X%d_SC_%s_%s,", x_real, set, mode);
if (ret < 0)
return MXT_ERROR_IO;
}
}
} else if (ctx->active_stylus) {
for (pass = 0; pass < ctx->passes; pass++) {
const char *mode;
switch (ctx->mode) {
default:
case AST_DELTAS:
mode = "delta";
break;
case AST_REFS:
mode = "ref";
break;
}
for (y = 0; y < ctx->y_size; y++) {
int y_real;
const char* set;
if ( y < id->matrix_y_size) {
y_real = y;
set = "0";
} else {
y_real = y - id->matrix_y_size;
set = "1";
}
ret = fprintf(ctx->hawkeye, "AST_%s_Y%s_%d,", mode, set, y_real);
if (ret < 0)
return MXT_ERROR_IO;
}
for (x = 0; x < ctx->x_size; x++) {
int x_real;
const char* set;
if ( x < ctx->x_size/2) {
x_real = x;
set = "0";
} else {
x_real = x - ctx->x_size/2;
set = "1";
}
ret = fprintf(ctx->hawkeye, "AST_%s_X%s_%d,", mode, set, x_real);
if (ret < 0)
return MXT_ERROR_IO;
}
}
} else {
for (x = 0; x < ctx->x_size; x++) {
for (y = 0; y < ctx->y_size; y++) {
ret = fprintf(ctx->hawkeye, "X%dY%d_%s16,", x, y,
(ctx->mode == DELTAS_MODE) ? "Delta" : "Reference");
if (ret < 0)
return MXT_ERROR_IO;
}
}
}
ret = fprintf(ctx->hawkeye, "\n");
if (ret < 0)
return MXT_ERROR_IO;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Insert page of data into buffer at appropriate co-ordinates
/// \return #mxt_rc
static int mxt_debug_insert_data_self_cap(struct t37_ctx *ctx)
{
int i;
int ofs;
int pass_ofs = (ctx->y_size + ctx->x_size) * ctx->pass;
uint16_t val;
for (i = 0; i < ctx->page_size; i += 2) {
int data_pos = ctx->page * ctx->page_size/2 + i/2;
if (data_pos > (ctx->data_values/ctx->passes))
return MXT_SUCCESS;
ofs = pass_ofs + data_pos;
if (ofs > ctx->data_values)
return MXT_INTERNAL_ERROR;
val = (ctx->t37_buf->data[i+1] << 8) | ctx->t37_buf->data[i];
ctx->data_buf[ofs] = val;
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Insert page of data into buffer at appropriate co-ordinates
/// \return #mxt_rc
static int mxt_debug_insert_data(struct t37_ctx *ctx)
{
int i;
uint16_t value;
int ofs;
for (i = 0; i < ctx->page_size; i += 2) {
if (ctx->x_ptr > ctx->x_size) {
mxt_err(ctx->lc, "x pointer overrun");
return MXT_INTERNAL_ERROR;
}
value = (ctx->t37_buf->data[i+1] << 8) | ctx->t37_buf->data[i];
ofs = ctx->y_ptr + ctx->x_ptr * ctx->y_size;
/* The last page may overlap the end of the matrix */
if (ofs >= ctx->data_values)
return MXT_SUCCESS;
ctx->data_buf[ofs] = value;
ctx->y_ptr++;
if (ctx->y_ptr > ctx->stripe_endy) {
ctx->y_ptr = ctx->stripe_starty;
ctx->x_ptr++;
}
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Write data to file
/// \return #mxt_rc
static int mxt_hawkeye_output(struct t37_ctx *ctx)
{
int x;
int y;
int pass;
int ofs;
int32_t value;
int ret;
ret = mxt_print_timestamp(ctx->hawkeye, false);
if (ret)
return ret;
/* print frame number */
ret = fprintf(ctx->hawkeye, ",%u,", ctx->frame);
if (ret < 0)
return MXT_ERROR_IO;
if ((ctx->self_cap)||(ctx->active_stylus)) {
for (pass = 0; pass < ctx->passes; pass++) {
int pass_ofs = (ctx->y_size + ctx->x_size) * pass;
for (y = 0; y < ctx->y_size; y++) {
value = (int16_t)ctx->data_buf[pass_ofs + y];
ret = fprintf(ctx->hawkeye, "%d,",
(ctx->mode == SELF_CAP_DELTAS) ? (int16_t)value : value);
if (ret < 0)
return MXT_ERROR_IO;
}
for (x = 0; x < ctx->x_size; x++) {
value = (int16_t)ctx->data_buf[pass_ofs + ctx->y_size + x];
ret = fprintf(ctx->hawkeye, "%d,",
(ctx->mode == SELF_CAP_DELTAS) ? (int16_t)value : value);
if (ret < 0)
return MXT_ERROR_IO;
}
}
} else {
/* iterate through columns */
for (x = 0; x < ctx->x_size; x++) {
for (y = 0; y < ctx->y_size; y++) {
ofs = y + x * ctx->y_size;
value = ctx->data_buf[ofs];
ret = fprintf(ctx->hawkeye, "%d,",
(ctx->mode == DELTAS_MODE) ? (int16_t)value : value);
if (ret < 0)
return MXT_ERROR_IO;
}
}
}
ret = fprintf(ctx->hawkeye, "\n");
if (ret < 0)
return MXT_ERROR_IO;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Input number of frames
/// \return #mxt_rc
static int get_num_frames(uint16_t *frames)
{
printf("Number of frames: ");
if (scanf("%hu", frames) == EOF) {
fprintf(stderr, "Could not handle the input, exiting");
return MXT_ERROR_BAD_INPUT;
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Initialise parameters and allocate buffers
/// \return #mxt_rc
int mxt_debug_dump_initialise(struct t37_ctx *ctx)
{
struct mxt_id_info *id = ctx->mxt->info.id;
int ret;
ret = get_objects_addr(ctx);
if (ret) {
mxt_err(ctx->lc, "Failed to get object information");
return ret;
}
mxt_dbg(ctx->lc, "t37_size: %d", ctx->t37_size);
ctx->page_size = ctx->t37_size - 2;
mxt_dbg(ctx->lc, "page_size: %d", ctx->page_size);
switch (ctx->mode) {
case DELTAS_MODE:
case REFS_MODE:
ctx->self_cap = false;
if (id->family == 0xA0 && id->variant == 0x00) {
/* mXT1386 data is formatted into stripes */
ctx->x_size = 27;
ctx->y_size = id->matrix_y_size;
ctx->data_values = 27 * ctx->y_size;
ctx->passes = 3;
ctx->pages_per_pass = 8;
} else {
ctx->x_size = id->matrix_x_size;
ctx->y_size = id->matrix_y_size;
ctx->data_values = ctx->x_size * ctx->y_size;
ctx->passes = 1;
ctx->pages_per_pass = (ctx->data_values*2 + (ctx->page_size - 1)) /
ctx->page_size;
}
ctx->stripe_width = ctx->y_size / ctx->passes;
mxt_dbg(ctx->lc, "stripe_width: %d", ctx->stripe_width);
break;
case SELF_CAP_SIGNALS:
case SELF_CAP_DELTAS:
case SELF_CAP_REFS:
ctx->self_cap = true;
if (id->family != 164) {
mxt_err(ctx->lc, "Self cap data not available");
return MXT_ERROR_NOT_SUPPORTED;
}
if (ctx->t111_instances == 0) {
mxt_err(ctx->lc, "T111 not found");
return MXT_ERROR_OBJECT_NOT_FOUND;
}
// Read Ymax Y values, plus Ymax or 2Ymax X values
ctx->passes = ctx->t111_instances;
ctx->y_size = id->matrix_y_size;
ctx->x_size = ctx->y_size * ((id->matrix_x_size > ctx->y_size) ? 2 : 1);
ctx->data_values = (ctx->y_size + ctx->x_size) * ctx->passes;
ctx->pages_per_pass = ((ctx->y_size + ctx->x_size)*sizeof(uint16_t) +(ctx->page_size - 1)) /
ctx->page_size;
break;
case AST_DELTAS:
case AST_REFS:
ctx->self_cap = false;
ctx->active_stylus = true;
if (id->family != 164) {
mxt_err(ctx->lc, "active stylus data not available");
return MXT_ERROR_NOT_SUPPORTED;
}
if (ctx->t107_instances == 0) {
mxt_err(ctx->lc, "T107 not found");
return MXT_ERROR_OBJECT_NOT_FOUND;
}
// Read Ymax Y values, plus Ymax or 2Ymax X values
ctx->passes = ctx->t107_instances;
ctx->y_size = 2 * id->matrix_y_size; // Two scans per axis
ctx->x_size = ctx->y_size * ((id->matrix_x_size > ctx->y_size) ? 2 : 1);
ctx->data_values = (ctx->y_size + ctx->x_size) * ctx->passes;
ctx->pages_per_pass = ((ctx->y_size + ctx->x_size)*sizeof(uint16_t) +(ctx->page_size - 1)) /
ctx->page_size;
break;
default:
mxt_err(ctx->lc, "Unsupported mode %02X", ctx->mode);
return MXT_INTERNAL_ERROR;
}
mxt_dbg(ctx->lc, "passes: %d", ctx->passes);
mxt_dbg(ctx->lc, "pages_per_pass: %d", ctx->pages_per_pass);
mxt_dbg(ctx->lc, "x_size: %d", ctx->x_size);
mxt_dbg(ctx->lc, "y_size: %d", ctx->y_size);
mxt_dbg(ctx->lc, "data_values: %d", ctx->data_values);
/* allocate t37 buffers */
ctx->t37_buf = (struct t37_diagnostic_data *)calloc(1, ctx->t37_size);
if (!ctx->t37_buf) {
mxt_err(ctx->lc, "calloc failure");
return MXT_ERROR_NO_MEM;
}
/* allocate data buffer */
ctx->data_buf = (uint16_t *)calloc(ctx->data_values, sizeof(uint16_t));
if (!ctx->data_buf) {
mxt_err(ctx->lc, "calloc failure");
/* free other buffer in error path */
free(ctx->t37_buf);
ctx->t37_buf = NULL;
return MXT_ERROR_NO_MEM;
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Read one frame of diagnostic data
/// \return #mxt_rc
int mxt_read_diagnostic_data_frame(struct t37_ctx* ctx)
{
int ret;
/* iterate through stripes */
for (ctx->pass = 0; ctx->pass < ctx->passes; ctx->pass++) {
/* Calculate stripe parameters */
ctx->stripe_starty = ctx->stripe_width * ctx->pass;
ctx->stripe_endy = ctx->stripe_starty + ctx->stripe_width - 1;
ctx->x_ptr = 0;
ctx->y_ptr = ctx->stripe_starty;
for (ctx->page = 0; ctx->page < ctx->pages_per_pass; ctx->page++) {
mxt_dbg(ctx->lc, "Frame %d Pass %d Page %d", ctx->frame, ctx->pass,
ctx->page);
ret = mxt_get_t37_page(ctx);
if (ret)
return ret;
mxt_debug_insert_data(ctx);
}
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Read one frame of diagnostic data
/// \return #mxt_rc
static int mxt_read_diagnostic_data_self_cap(struct t37_ctx* ctx)
{
int ret;
for (ctx->pass = 0; ctx->pass < ctx->passes; ctx->pass++) {
for (ctx->page = 0; ctx->page < ctx->pages_per_pass; ctx->page++) {
mxt_dbg(ctx->lc, "Frame %d Pass %d Page %d", ctx->frame, ctx->pass,
ctx->page);
ret = mxt_get_t37_page(ctx);
if (ret)
return ret;
mxt_debug_insert_data_self_cap(ctx);
}
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Read one frame of diagnostic data
/// \return #mxt_rc
static int mxt_read_diagnostic_data_ast(struct t37_ctx* ctx)
{
return mxt_read_diagnostic_data_self_cap(ctx);
}
//******************************************************************************
/// \brief Retrieve data from the T37 Diagnostic Data object
/// \return #mxt_rc
int mxt_debug_dump(struct mxt_device *mxt, int mode, const char *csv_file,
uint16_t frames)
{
struct t37_ctx ctx;
time_t t1;
time_t t2;
int ret;
ctx.lc = mxt->ctx;
ctx.mxt = mxt;
ctx.mode = mode;
if (frames == 0) {
mxt_warn(ctx.lc, "Defaulting to 1 frame");
frames = 1;
}
ret = mxt_debug_dump_initialise(&ctx);
if (ret)
return ret;
/* Open Hawkeye output file */
ctx.hawkeye = fopen(csv_file,"w");
if (!ctx.hawkeye) {
mxt_err(ctx.lc, "Failed to open file!");
ret = MXT_ERROR_IO;
goto free;
}
ret = mxt_generate_hawkeye_header(&ctx);
if (ret)
goto close;
mxt_info(ctx.lc, "Reading %u frames", frames);
t1 = time(NULL);
for (ctx.frame = 1; ctx.frame <= frames; ctx.frame++) {
if (ctx.self_cap) {
ret = mxt_read_diagnostic_data_self_cap(&ctx);
} else if (ctx.active_stylus) {
ret = mxt_read_diagnostic_data_ast(&ctx);
} else {
ret = mxt_read_diagnostic_data_frame(&ctx);
}
if (ret)
goto close;
ret = mxt_hawkeye_output(&ctx);
if (ret)
goto close;
}
t2 = time(NULL);
mxt_info(ctx.lc, "%u frames in %d seconds", frames, (int)(t2-t1));
ret = MXT_SUCCESS;
close:
fclose(ctx.hawkeye);
free:
free(ctx.data_buf);
ctx.data_buf = NULL;
free(ctx.t37_buf);
ctx.t37_buf = NULL;
return ret;
}
//******************************************************************************
/// \brief Handle menu input for diagnostic data functions
static void mxt_dd_cmd(struct mxt_device *mxt, char selection, const char *csv_file)
{
uint16_t frames;
int ret;
switch (selection) {
case 'd':
case 'D':
ret = get_num_frames(&frames);
if (ret == MXT_SUCCESS)
mxt_debug_dump(mxt, DELTAS_MODE, csv_file, frames);
break;
case 'r':
case 'R':
ret = get_num_frames(&frames);
if (ret == MXT_SUCCESS)
mxt_debug_dump(mxt, REFS_MODE, csv_file, frames);
break;
default:
printf("Invalid menu option\n");
break;
}
}
//******************************************************************************
/// \brief Menu interface for diagonistic data functions
void mxt_dd_menu(struct mxt_device *mxt)
{
char menu_input;
char csv_file_in[MAX_FILENAME_LENGTH + 1];
while(true) {
printf("\nSelect one of the options:\n\n"
"Enter D: (D)elta dump\n"
"Enter R: (R)eference dump\n"
"Enter Q: (Q)uit\n");
if (scanf("%1s", &menu_input) == EOF) {
fprintf(stderr, "Could not handle the input, exiting");
return;
}
if ((menu_input == 'q') || (menu_input == 'Q')) {
printf("Quit\n");
return;
}
printf("\nFile name: ");
if (scanf("%255s", csv_file_in) == EOF) {
fprintf(stderr, "Could not handle the input, exiting");
return;
}
mxt_dd_cmd(mxt, menu_input, csv_file_in);
}
}
mxt-app-1.27/src/mxt-app/gr.c 0000664 0000000 0000000 00000014401 12706171405 0015765 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file gr.c
/// \brief T66 golden reference calibration
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2012 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include "libmaxtouch/libmaxtouch.h"
#include "libmaxtouch/info_block.h"
#include "libmaxtouch/utilfuncs.h"
#include "libmaxtouch/log.h"
#include "mxt_app.h"
#define GR_CTRL 0
#define GR_ENABLE (1 << 0)
#define GR_RPTEN (1 << 1)
#define GR_FCALCMD_PRIME (1 << 2)
#define GR_FCALCMD_GENERATE (1 << 3)
#define GR_FCALCMD_STORE (GR_FCALCMD_PRIME | GR_FCALCMD_GENERATE)
#define GR_FCALCMD_MASK GR_FCALCMD_STORE
#define GR_TESTONINIT (1 << 4)
#define GR_TESTONCAL (1 << 5)
#define GR_STATE_BADSTOREDATA (1 << 0)
#define GR_STATE_IDLE 0
#define GR_STATE_PRIMED (1 << 1)
#define GR_STATE_GENERATED (1 << 2)
#define GR_STATE_FCALSTATE_MASK (GR_STATE_PRIMED | GR_STATE_GENERATED)
#define GR_STATE_FCALSEQERR (1 << 3)
#define GR_STATE_FCALSEQTO (1 << 4)
#define GR_STATE_FCALSEQDONE (1 << 5)
#define GR_STATE_FCALPASS (1 << 6)
#define GR_STATE_FCALFAIL (1 << 7)
#define GR_TIMEOUT 30
//******************************************************************************
/// \brief Handle status messages from the T66 golden references object
static void mxt_gr_print_status(struct mxt_device *mxt, uint8_t status)
{
mxt_info(mxt->ctx,
"T66 state: %02X %s%s%s%s%s%s%s%s%s", status,
(status & GR_STATE_FCALFAIL) ? "FCALFAIL " : "",
(status & GR_STATE_FCALPASS) ? "FCALPASS " : "",
(status & GR_STATE_FCALSEQDONE) ? "FCALSEQDONE " : "",
(status & GR_STATE_FCALSEQTO) ? "FCALSEQTO " : "",
(status & GR_STATE_FCALSEQERR) ? "FCALSEQERR " : "",
((status & GR_STATE_FCALSTATE_MASK) == GR_STATE_IDLE) ? "Idle " : "",
((status & GR_STATE_FCALSTATE_MASK) == GR_STATE_GENERATED)?"Generated ":"",
((status & GR_STATE_FCALSTATE_MASK) == GR_STATE_PRIMED) ? "Primed " : "",
(status & GR_STATE_BADSTOREDATA) ? "BADSTOREDATA " : "");
}
//******************************************************************************
/// \brief Handle status messages from the T66 golden references object
static int mxt_gr_get_status(struct mxt_device *mxt, uint8_t *msg,
void *context, uint8_t size)
{
unsigned int object_type;
uint8_t *status = context;
object_type = mxt_report_id_to_type(mxt, msg[0]);
mxt_verb(mxt->ctx, "Received message from T%u", object_type);
if (object_type == SPT_GOLDENREFERENCES_T66) {
*status = msg[1];
mxt_gr_print_status(mxt, *status);
return MXT_SUCCESS;
} else if (object_type == GEN_COMMANDPROCESSOR_T6) {
print_t6_status(msg[1]);
return MXT_MSG_CONTINUE;
}
return MXT_MSG_CONTINUE;
}
//******************************************************************************
/// \brief Send command then check status
/// \return #mxt_rc
static int mxt_gr_run_command(struct mxt_device *mxt, uint16_t addr, uint8_t cmd,
uint8_t wanted_fcal_state, uint8_t wanted_statebit)
{
int ret;
uint8_t actual_state;
cmd |= GR_ENABLE | GR_RPTEN;
mxt_info(mxt->ctx, "Writing %u to ctrl register", cmd);
ret = mxt_write_register(mxt, &cmd, addr + GR_CTRL, 1);
if (ret)
return ret;
ret = mxt_read_messages_sigint(mxt, GR_TIMEOUT, &actual_state, mxt_gr_get_status);
if (ret)
return ret;
if (((actual_state & GR_STATE_FCALSTATE_MASK) == wanted_fcal_state)
&& (actual_state & wanted_statebit)) {
return MXT_SUCCESS;
} else {
mxt_err(mxt->ctx, "Failed to enter correct state");
return MXT_ERROR_UNEXPECTED_DEVICE_STATE;
}
}
//******************************************************************************
/// \brief Store golden reference calibration
int mxt_store_golden_refs(struct mxt_device *mxt)
{
uint16_t addr;
int ret;
ret = mxt_msg_reset(mxt);
if (ret)
return ret;
addr = mxt_get_object_address(mxt, SPT_GOLDENREFERENCES_T66, 0);
if (addr == OBJECT_NOT_FOUND)
return MXT_ERROR_OBJECT_NOT_FOUND;
mxt_info(mxt->ctx, "Priming");
ret = mxt_gr_run_command(mxt, addr, GR_FCALCMD_PRIME,
GR_STATE_PRIMED, GR_STATE_PRIMED);
if (ret)
return ret;
mxt_info(mxt->ctx, "Generating");
ret = mxt_gr_run_command(mxt, addr, GR_FCALCMD_GENERATE,
GR_STATE_GENERATED, GR_STATE_FCALPASS);
if (ret)
return ret;
mxt_info(mxt->ctx, "Storing");
ret = mxt_gr_run_command(mxt, addr, GR_FCALCMD_STORE,
GR_STATE_IDLE, GR_STATE_FCALSEQDONE);
if (ret)
return ret;
mxt_info(mxt->ctx, "Done");
return MXT_SUCCESS;
}
mxt-app-1.27/src/mxt-app/menu.c 0000664 0000000 0000000 00000024012 12706171405 0016320 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file menu.c
/// \brief Menu functions for mxt-app
/// \author Srivalli Ineni & Iiro Valkonen.
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#ifndef ANDROID
#include
#endif
#include
#include
#include
#include
#include
#include
#include "libmaxtouch/libmaxtouch.h"
#include "libmaxtouch/utilfuncs.h"
#include "libmaxtouch/info_block.h"
#include "mxt_app.h"
//******************************************************************************
/// \brief Load config from file
static void load_config(struct mxt_device *mxt)
{
char cfg_file[255];
/* Load config file */
printf("Give cfg file name: ");
if (scanf("%255s", cfg_file) != 1) {
printf("Input parse error\n");
return;
}
printf("Trying to open %s...\n", cfg_file);
if (mxt_load_config_file(mxt, cfg_file) == MXT_SUCCESS) {
printf("Successfully uploaded the configuration file\n");
} else {
printf("Failed to upload the configuration\n");
}
}
//******************************************************************************
/// \brief Save config to file
static void save_config(struct mxt_device *mxt)
{
char cfg_file[255];
/* Save config file */
printf("Give cfg file name: ");
if (scanf("%255s", cfg_file) != 1) {
printf("Input parse error\n");
return;
}
if (mxt_save_config_file(mxt, cfg_file) == MXT_SUCCESS) {
printf("Successfully saved configuration to file\n");
} else {
printf("Failed to save configuration\n");
}
}
//******************************************************************************
/// \brief Flash firmware to chip
static void flash_firmware_command(struct mxt_device *mxt)
{
char fw_file[255];
struct mxt_conn_info *conn = NULL;
/* Save config file */
printf("Give firmware .enc file name: ");
if (scanf("%255s", fw_file) != 1) {
printf("Input parse error\n");
return;
}
mxt_flash_firmware(mxt->ctx, mxt, fw_file, "", conn);
}
//******************************************************************************
/// \brief Read objects according to the input value
static void read_object_command(struct mxt_device *mxt)
{
uint16_t obj_num;
uint8_t instance = 0;
while(1) {
printf("Enter the object number to read or 0 to finish\n");
if (scanf("%" SCNu16, &obj_num) != 1) {
printf("Input parse error\n");
return;
};
if (obj_num == 0)
return;
if (MXT_INSTANCES(mxt->info.objects[obj_num]) > 1) {
printf("Enter object instance\n");
if (scanf("%" SCNu8, &instance) != 1) {
printf("Input parse error\n");
return;
}
}
mxt_read_object(mxt, obj_num, instance, 0, 0, true);
}
}
//******************************************************************************
/// \brief Menu function to write values to object
static void write_to_object(struct mxt_device *mxt, int obj_num, uint8_t instance)
{
uint8_t obj_tbl_num, i;
uint8_t *buffer;
uint16_t start_position;
int yn;
uint8_t value;
uint8_t size;
obj_tbl_num = mxt_get_object_table_num(mxt, obj_num);
if (obj_tbl_num == 255) {
printf("Object not found\n");
return;
}
buffer = (uint8_t *)calloc(MXT_SIZE(mxt->info.objects[obj_tbl_num]), sizeof(char));
if (buffer == NULL) {
mxt_err(mxt->ctx, "Memory error");
return;
}
const char *obj_name = mxt_get_object_name(mxt->info.objects[obj_tbl_num].type);
if (obj_name)
printf("%s:\n", obj_name);
else
printf("UNKNOWN_T%d:\n", mxt->info.objects[obj_tbl_num].type);
start_position = mxt_get_start_position(mxt->info.objects[obj_tbl_num], instance);
size = mxt_get_object_size(mxt, obj_num);
mxt_read_register(mxt, buffer, start_position, size);
for(i = 0; i < size; i++) {
printf("Object element %d =\t %d\n",i, *(buffer+i));
printf("Do you want to change this value? (1 for yes/2 for no)");
if (scanf("%d", &yn) != 1) {
printf("Input error\n");
return;
}
if (yn == 1) {
printf("Enter the value to be written to object element %d\t :", i);
if (scanf("%" SCNu8, &value) != 1) {
printf("Input error\n");
return;
}
*(buffer+i) = value;
printf("Wrote %d\n", value);
}
}
mxt_write_register(mxt, buffer, start_position, size);
}
//******************************************************************************
/// \brief Write objects
static void write_object_command(struct mxt_device *mxt)
{
uint16_t obj_num;
uint8_t instance = 0;
while(1) {
printf("Enter the object number to write or 0 to finish\n");
if (scanf("%" SCNu16, &obj_num) != 1) {
printf("Input parse error\n");
return;
}
if (obj_num == 0)
return;
if (MXT_INSTANCES(mxt->info.objects[obj_num]) > 1) {
printf("Enter object instance\n");
if (scanf("%" SCNu8, &instance) != 1) {
printf("Input parse error\n");
return;
}
}
write_to_object(mxt, obj_num, instance);
}
}
//******************************************************************************
/// \brief Print Messages
static void print_messages_command(struct mxt_device *mxt)
{
int msgs_timeout = MSG_CONTINUOUS;
char tmp_buf[8];
/* Flush stdin */
#ifndef ANDROID
__fpurge(stdin);
#else
fpurge(stdin);
#endif
printf("Enter the messages timeout period in seconds. [Default: Run continually]\n");
fgets(tmp_buf, sizeof(tmp_buf), stdin);
if (sscanf(tmp_buf, "%d", &msgs_timeout) == EOF)
printf("Please Press Ctrl-C to Return to Main Menu.\n");
print_raw_messages(mxt, msgs_timeout, 0);
}
//******************************************************************************
/// \brief Handle command
static bool mxt_app_command(struct mxt_device *mxt, char selection)
{
bool exit_loop = false;
switch(selection) {
case 'l':
load_config(mxt);
break;
case 's':
save_config(mxt);
case 'i':
/* Print info block */
printf("Reading info block.....\n");
mxt_print_info_block(mxt);
break;
case 'd':
read_object_command(mxt);
break;
case 'w':
write_object_command(mxt);
break;
case 'f':
flash_firmware_command(mxt);
break;
case 't':
/* Run the self-test */
self_test_menu(mxt);
break;
case 'b':
/* Backup the config data */
if (mxt_backup_config(mxt, BACKUPNV_COMMAND) == MXT_SUCCESS) {
printf("Settings successfully backed up to non-volatile memory\n");
} else {
printf("Failed to back up settings\n");
}
break;
case 'r':
/* Reset the chip */
if (mxt_reset_chip(mxt, false) == MXT_SUCCESS) {
printf("Successfully forced a reset of the device\n");
} else {
printf("Failed to force a reset\n");
}
break;
case 'c':
/* Calibrate the device*/
if (mxt_calibrate_chip(mxt) == MXT_SUCCESS) {
printf("Successfully performed a global recalibration on all channels\n");
} else {
printf("Failed to perform a global recalibration\n");
}
break;
case 'm':
/* Display raw messages */
print_messages_command(mxt);
break;
case 'u':
mxt_dd_menu(mxt);
break;
case 'q':
printf("Quit\n");
exit_loop = true;
break;
default:
printf("Invalid menu option\n");
exit_loop = true;
break;
}
return exit_loop;
}
//******************************************************************************
/// \brief Menu function for mxt-app
int mxt_menu(struct mxt_device *mxt)
{
unsigned char menu_input;
bool exit_loop = false;
int ret;
printf("Command line tool for Atmel maXTouch chips version: %s\n\n",
MXT_VERSION);
while(!exit_loop) {
printf("Select one of the options:\n\n"
"Enter L: (L)oad config file\n"
"Enter S: (S)ave config file\n"
"Enter I: Read (I)nfo block\n"
"Enter D: Rea(D) individual object config\n"
"Enter W: (W)rite individual object\n"
"Enter T: Run sel(T)-test\n"
"Enter F: (F)lash firmware to chip\n"
"Enter B: (B)ackup the config data to NVM\n"
"Enter R: (R)eset the maxtouch device\n"
"Enter C: (C)alibrate the maxtouch device\n"
"Enter M: Display raw (M)essages\n"
"Enter U: D(U)mp Diagnostic data\n"
"Enter Q: (Q)uit the application\n");
ret = scanf("%1s", &menu_input);
if (ret == 1) {
/* force lower case */
menu_input = tolower(menu_input);
exit_loop = mxt_app_command(mxt, menu_input);
} else if (ret == EOF) {
fprintf(stderr, "Error %s\n", strerror(errno));
return MXT_ERROR_BAD_INPUT;
}
}
return MXT_SUCCESS;
}
mxt-app-1.27/src/mxt-app/mxt_app.c 0000664 0000000 0000000 00000064675 12706171405 0017047 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file mxt_app.c
/// \brief Command line tool for Atmel maXTouch chips.
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "libmaxtouch/libmaxtouch.h"
#include "libmaxtouch/log.h"
#include "libmaxtouch/utilfuncs.h"
#include "libmaxtouch/info_block.h"
#include "mxt_app.h"
#define BUF_SIZE 1024
//******************************************************************************
/// \brief Initialize mXT device and read the info block
/// \return #mxt_rc
static int mxt_init_chip(struct libmaxtouch_ctx *ctx, struct mxt_device **mxt,
struct mxt_conn_info **conn)
{
int ret;
if (!*conn) {
ret = mxt_scan(ctx, conn, false);
if (ret == MXT_ERROR_NO_DEVICE) {
mxt_err(ctx, "Unable to find a device");
return ret;
} else if (ret) {
mxt_err(ctx, "Failed to find device");
return ret;
}
}
ret = mxt_new_device(ctx, *conn, mxt);
if (ret)
return ret;
#ifdef HAVE_LIBUSB
if ((*mxt)->conn->type == E_USB && usb_is_bootloader(*mxt)) {
mxt_free_device(*mxt);
mxt_err(ctx, "USB device in bootloader mode");
return MXT_ERROR_UNEXPECTED_DEVICE_STATE;
}
#endif
ret = mxt_get_info(*mxt);
if (ret)
return ret;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Print usage for mxt-app
static void print_usage(char *prog_name)
{
fprintf(stderr, "Command line tool for Atmel maXTouch chips version: %s\n\n"
"Usage: %s [command] [options]\n\n"
"When run with no options, access menu interface.\n\n"
"General commands:\n"
" -h [--help] : display this help and exit\n"
" -i [--info] : print device information\n"
" -M [--messages] [TIMEOUT] : print the messages (for TIMEOUT seconds)\n"
" -F [--msg-filter] TYPE : message filtering by object TYPE\n"
" --reset : reset device\n"
" --reset-bootloader : reset device in bootloader mode\n"
" --calibrate : send calibrate command\n"
" --backup[=COMMAND] : backup configuration to NVRAM\n"
" -g : store golden references\n"
" --self-cap-tune-config : tune self capacitance settings to config\n"
" --self-cap-tune-nvram : tune self capacitance settings to NVRAM\n"
" --version : print version\n"
" --block-size BLOCKSIZE : set the maximum block size used for i2c transfers (default %d)\n"
"\n"
"Configuration file commands:\n"
" --load FILE : upload cfg from FILE in .xcfg or OBP_RAW format\n"
" --save FILE : save cfg to FILE in .xcfg or OBP_RAW format\n"
" --checksum FILE : verify .xcfg or OBP_RAW file config checksum\n"
"\n"
"Register read/write commands:\n"
" -R [--read] : read from object\n"
" -W [--write] : write to object\n"
" -n [--count] COUNT : read/write COUNT registers\n"
" -f [--format] : format register output\n"
" -I [--instance] INSTANCE : select object INSTANCE\n"
" -r [--register] REGISTER : start at REGISTER (offset when used with TYPE)\n"
" -T [--type] TYPE : select object TYPE\n"
" --zero : zero all configuration settings\n"
"\n"
"TCP socket commands:\n"
" -C [--bridge-client] HOST : connect over TCP to HOST\n"
" -S [--bridge-server] : start TCP socket server\n"
" -p [--port] PORT : TCP port (default 4000)\n"
"\n"
"Bootloader commands:\n"
" --bootloader-version : query bootloader version\n"
" --flash FIRMWARE : send FIRMWARE to bootloader\n"
" --firmware-version VERSION : check firmware VERSION "
"before and after flash\n"
"\n"
"T68 Serial Data commands:\n"
" --t68-file FILE : upload FILE\n"
" --t68-datatype DATATYPE : select DATATYPE\n"
"\n"
"T25 Self Test commands:\n"
" -t [--test] : run all self tests\n"
" -tXX [--test=XX] : run individual test, write XX to CMD register\n"
"\n"
"T37 Diagnostic Data commands:\n"
" --debug-dump FILE : capture diagnostic data to FILE\n"
" --frames N : capture N frames of data\n"
" --references : capture references data\n"
" --self-cap-signals : capture self cap signals\n"
" --self-cap-deltas : capture self cap deltas\n"
" --self-cap-refs : capture self cap references\n"
" --active-stylus-deltas : capture active stylus deltas\n"
" --active-stylus-refs : capture active stylus references\n"
"\n"
"Device connection options:\n"
" -q [--query] : scan for devices\n"
" -d [--device] DEVICESTRING : DEVICESTRING as output by --query\n\n"
" Examples:\n"
" -d i2c-dev:ADAPTER:ADDRESS : raw i2c device, eg \"i2c-dev:2-004a\"\n"
#ifdef HAVE_LIBUSB
" -d usb:BUS-DEVICE : USB device, eg \"usb:001-003\"\n"
#endif
" -d sysfs:PATH : sysfs interface\n"
" -d hidraw:PATH : HIDRAW device, eg \"hidraw:/dev/hidraw0\"\n"
"\n"
"Debug options:\n"
" -v [--verbose] LEVEL : set debug level\n",
MXT_VERSION, prog_name, I2C_DEV_MAX_BLOCK);
}
//******************************************************************************
/// \brief Main function for mxt-app
int main (int argc, char *argv[])
{
int ret;
int c;
int msgs_timeout = MSG_CONTINUOUS;
bool msgs_enabled = false;
uint8_t backup_cmd = BACKUPNV_COMMAND;
unsigned char self_test_cmd = SELF_TEST_ALL;
uint16_t address = 0;
uint16_t count = 0;
struct mxt_conn_info *conn = NULL;
uint16_t object_type = 0;
uint16_t msg_filter_type = 0;
uint8_t instance = 0;
uint8_t verbose = 2;
uint16_t t37_frames = 1;
uint8_t t37_mode = DELTAS_MODE;
bool format = false;
uint16_t port = 4000;
int i2c_block_size = I2C_DEV_MAX_BLOCK;
uint8_t t68_datatype = 1;
unsigned char databuf;
char strbuf2[BUF_SIZE];
char strbuf[BUF_SIZE];
strbuf[0] = '\0';
strbuf2[0] = '\0';
mxt_app_cmd cmd = CMD_NONE;
while (1) {
int option_index = 0;
static struct option long_options[] = {
{"backup", optional_argument, 0, 0},
{"block-size", required_argument, 0, 0},
{"bootloader-version", no_argument, 0, 0},
{"bridge-client", required_argument, 0, 'C'},
{"calibrate", no_argument, 0, 0},
{"checksum", required_argument, 0, 0},
{"debug-dump", required_argument, 0, 0},
{"device", required_argument, 0, 'd'},
{"t68-file", required_argument, 0, 0},
{"t68-datatype", required_argument, 0, 0},
{"msg-filter", required_argument, 0, 'F'},
{"format", no_argument, 0, 'f'},
{"flash", required_argument, 0, 0},
{"firmware-version", required_argument, 0, 0},
{"frames", required_argument, 0, 0},
{"help", no_argument, 0, 'h'},
{"info", no_argument, 0, 'i'},
{"instance", required_argument, 0, 'I'},
{"load", required_argument, 0, 0},
{"save", required_argument, 0, 0},
{"messages", optional_argument, 0, 'M'},
{"count", required_argument, 0, 'n'},
{"port", required_argument, 0, 'p'},
{"query", no_argument, 0, 'q'},
{"read", no_argument, 0, 'R'},
{"reset", no_argument, 0, 0},
{"reset-bootloader", no_argument, 0, 0},
{"register", required_argument, 0, 'r'},
{"references", no_argument, 0, 0},
{"self-cap-tune-config", no_argument, 0, 0},
{"self-cap-tune-nvram", no_argument, 0, 0},
{"self-cap-signals", no_argument, 0, 0},
{"self-cap-deltas", no_argument, 0, 0},
{"self-cap-refs", no_argument, 0, 0},
{"active-stylus-deltas", no_argument, 0, 0},
{"active-stylus-refs", no_argument, 0, 0},
{"bridge-server", no_argument, 0, 'S'},
{"test", optional_argument, 0, 't'},
{"type", required_argument, 0, 'T'},
{"verbose", required_argument, 0, 'v'},
{"version", no_argument, 0, 0},
{"write", no_argument, 0, 'W'},
{"zero", no_argument, 0, 0},
{0, 0, 0, 0 }
};
c = getopt_long(argc, argv,
"C:d:D:fF:ghiI:M::m:n:p:qRr:St::T:v:W",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 0:
if (!strcmp(long_options[option_index].name, "t68-file")) {
if (cmd == CMD_NONE) {
cmd = CMD_SERIAL_DATA;
strncpy(strbuf, optarg, sizeof(strbuf));
strbuf[sizeof(strbuf) - 1] = '\0';
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
} else if (!strcmp(long_options[option_index].name, "t68-datatype")) {
t68_datatype = strtol(optarg, NULL, 0);
} else if (!strcmp(long_options[option_index].name, "flash")) {
if (cmd == CMD_NONE) {
cmd = CMD_FLASH;
strncpy(strbuf, optarg, sizeof(strbuf));
strbuf[sizeof(strbuf) - 1] = '\0';
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
} else if (!strcmp(long_options[option_index].name, "backup")) {
if (cmd == CMD_NONE) {
cmd = CMD_BACKUP;
if (optarg) {
ret = mxt_convert_hex(optarg, &databuf, &count, sizeof(databuf));
if (ret || count == 0) {
fprintf(stderr, "Hex convert error\n");
ret = MXT_ERROR_BAD_INPUT;
}
backup_cmd = databuf;
}
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
} else if (!strcmp(long_options[option_index].name, "calibrate")) {
if (cmd == CMD_NONE) {
cmd = CMD_CALIBRATE;
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
} else if (!strcmp(long_options[option_index].name, "debug-dump")) {
if (cmd == CMD_NONE) {
cmd = CMD_DEBUG_DUMP;
strncpy(strbuf, optarg, sizeof(strbuf));
strbuf[sizeof(strbuf) - 1] = '\0';
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
} else if (!strcmp(long_options[option_index].name, "reset")) {
if (cmd == CMD_NONE) {
cmd = CMD_RESET;
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
} else if (!strcmp(long_options[option_index].name, "self-cap-tune-config")) {
if (cmd == CMD_NONE) {
cmd = CMD_SELF_CAP_TUNE_CONFIG;
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
} else if (!strcmp(long_options[option_index].name, "self-cap-tune-nvram")) {
if (cmd == CMD_NONE) {
cmd = CMD_SELF_CAP_TUNE_NVRAM;
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
} else if (!strcmp(long_options[option_index].name, "load")) {
if (cmd == CMD_NONE) {
cmd = CMD_LOAD_CFG;
strncpy(strbuf, optarg, sizeof(strbuf));
strbuf[sizeof(strbuf) - 1] = '\0';
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
} else if (!strcmp(long_options[option_index].name, "save")) {
if (cmd == CMD_NONE) {
cmd = CMD_SAVE_CFG;
strncpy(strbuf, optarg, sizeof(strbuf));
strbuf[sizeof(strbuf) - 1] = '\0';
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
} else if (!strcmp(long_options[option_index].name, "reset-bootloader")) {
if (cmd == CMD_NONE) {
cmd = CMD_RESET_BOOTLOADER;
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
} else if (!strcmp(long_options[option_index].name, "bootloader-version")) {
if (cmd == CMD_NONE) {
cmd = CMD_BOOTLOADER_VERSION;
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
} else if (!strcmp(long_options[option_index].name, "checksum")) {
if (cmd == CMD_NONE) {
cmd = CMD_CRC_CHECK;
strncpy(strbuf, optarg, sizeof(strbuf));
strbuf[sizeof(strbuf) - 1] = '\0';
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
} else if (!strcmp(long_options[option_index].name, "zero")) {
if (cmd == CMD_NONE) {
cmd = CMD_ZERO_CFG;
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
} else if (!strcmp(long_options[option_index].name, "firmware-version")) {
strncpy(strbuf2, optarg, sizeof(strbuf2));
} else if (!strcmp(long_options[option_index].name, "frames")) {
t37_frames = strtol(optarg, NULL, 0);
} else if (!strcmp(long_options[option_index].name, "references")) {
t37_mode = REFS_MODE;
} else if (!strcmp(long_options[option_index].name, "self-cap-signals")) {
t37_mode = SELF_CAP_SIGNALS;
} else if (!strcmp(long_options[option_index].name, "self-cap-refs")) {
t37_mode = SELF_CAP_REFS;
} else if (!strcmp(long_options[option_index].name, "self-cap-deltas")) {
t37_mode = SELF_CAP_DELTAS;
} else if (!strcmp(long_options[option_index].name, "active-stylus-deltas")) {
t37_mode = AST_DELTAS;
} else if (!strcmp(long_options[option_index].name, "active-stylus-refs")) {
t37_mode = AST_REFS;
} else if (!strcmp(long_options[option_index].name, "block-size")) {
i2c_block_size = atoi(optarg);
} else if (!strcmp(long_options[option_index].name, "version")) {
printf("mxt-app %s%s\n", MXT_VERSION, ENABLE_DEBUG ? " DEBUG":"");
return MXT_SUCCESS;
} else {
fprintf(stderr, "Unknown option %s\n",
long_options[option_index].name);
}
break;
case 'd':
if (optarg) {
if (!strncmp(optarg, "i2c-dev:", 8)) {
ret = mxt_new_conn(&conn, E_I2C_DEV);
if (ret)
return ret;
if (sscanf(optarg, "i2c-dev:%d-%x",
&conn->i2c_dev.adapter, &conn->i2c_dev.address) != 2) {
fprintf(stderr, "Invalid device string %s\n", optarg);
conn = mxt_unref_conn(conn);
return MXT_ERROR_NO_MEM;
}
} else if (!strncmp(optarg, "sysfs:", 6)) {
ret = mxt_new_conn(&conn, E_SYSFS);
if (ret)
return ret;
conn->sysfs.path = (char *)calloc(strlen(optarg) + 1, sizeof(char));
if (!conn->sysfs.path) {
fprintf(stderr, "malloc failure\n");
conn = mxt_unref_conn(conn);
return MXT_ERROR_NO_MEM;
}
memcpy(conn->sysfs.path, optarg + 6, strlen(optarg) - 6);
}
#ifdef HAVE_LIBUSB
else if (!strncmp(optarg, "usb:", 4)) {
ret = mxt_new_conn(&conn, E_USB);
if (ret)
return ret;
if (sscanf(optarg, "usb:%d-%d", &conn->usb.bus, &conn->usb.device) != 2) {
fprintf(stderr, "Invalid device string %s\n", optarg);
conn = mxt_unref_conn(conn);
return MXT_ERROR_NO_MEM;
}
}
#endif
else if (!strncmp(optarg, "hidraw:", 7)) {
ret = mxt_new_conn(&conn, E_HIDRAW);
if (ret)
return ret;
conn->hidraw.report_id = HIDRAW_REPORT_ID;
if (sscanf(optarg, "hidraw:%s", conn->hidraw.node) != 1) {
fprintf(stderr, "Invalid device string %s\n", optarg);
conn = mxt_unref_conn(conn);
return MXT_ERROR_NO_MEM;
}
} else {
fprintf(stderr, "Invalid device string %s\n", optarg);
conn = mxt_unref_conn(conn);
return MXT_ERROR_BAD_INPUT;
}
}
break;
case 'C':
if (cmd == CMD_NONE) {
cmd = CMD_BRIDGE_CLIENT;
strncpy(strbuf, optarg, sizeof(strbuf));
strbuf[sizeof(strbuf) - 1] = '\0';
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
break;
case 'g':
if (cmd == CMD_NONE) {
cmd = CMD_GOLDEN_REFERENCES;
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
break;
case 'h':
print_usage(argv[0]);
return MXT_SUCCESS;
case 'f':
format = true;
break;
case 'I':
if (optarg) {
instance = strtol(optarg, NULL, 0);
}
break;
case 'M':
msgs_enabled = true;
if (cmd == CMD_NONE) {
cmd = CMD_MESSAGES;
}
if (optarg)
msgs_timeout = strtol(optarg, NULL, 0);
break;
case 'F':
if (optarg) {
msg_filter_type = strtol(optarg, NULL, 0);
}
break;
case 'n':
if (optarg) {
count = strtol(optarg, NULL, 0);
}
break;
case 'p':
if (optarg) {
port = strtol(optarg, NULL, 0);
}
break;
case 'q':
if (cmd == CMD_NONE) {
cmd = CMD_QUERY;
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
break;
case 'r':
if (optarg) {
address = strtol(optarg, NULL, 0);
}
break;
case 'R':
if (cmd == CMD_NONE) {
cmd = CMD_READ;
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
break;
case 'S':
if (cmd == CMD_NONE) {
cmd = CMD_BRIDGE_SERVER;
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
break;
case 'T':
if (optarg) {
object_type = strtol(optarg, NULL, 0);
}
break;
case 'i':
if (cmd == CMD_NONE) {
cmd = CMD_INFO;
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
break;
case 't':
if (cmd == CMD_NONE) {
if (optarg) {
ret = mxt_convert_hex(optarg, &databuf, &count, sizeof(databuf));
if (ret) {
fprintf(stderr, "Hex convert error\n");
ret = MXT_ERROR_BAD_INPUT;
} else {
self_test_cmd = databuf;
}
}
cmd = CMD_TEST;
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
break;
case 'v':
if (optarg) {
verbose = strtol(optarg, NULL, 0);
}
break;
case 'W':
if (cmd == CMD_NONE) {
cmd = CMD_WRITE;
} else {
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
break;
default:
/* Output newline to create space under getopt error output */
fprintf(stderr, "\n\n");
print_usage(argv[0]);
return MXT_ERROR_BAD_INPUT;
}
}
struct mxt_device *mxt = NULL;
struct libmaxtouch_ctx *ctx;
ret = mxt_new(&ctx);
if (ret) {
mxt_err(ctx, "Failed to init libmaxtouch");
return ret;
}
/* Set debug level */
mxt_set_log_level(ctx, verbose);
mxt_verb(ctx, "verbose:%u", verbose);
/* Debug does not work until mxt_set_verbose() is called */
mxt_info(ctx, "Version:%s", MXT_VERSION);
/* Update the i2c block size */
if (i2c_block_size != I2C_DEV_MAX_BLOCK) {
mxt_verb(ctx, "Setting i2c_block_size from %d to %d", ctx->i2c_block_size, i2c_block_size);
ctx->i2c_block_size = i2c_block_size;
}
if (cmd == CMD_WRITE || cmd == CMD_READ) {
mxt_verb(ctx, "instance:%u", instance);
mxt_verb(ctx, "count:%u", count);
mxt_verb(ctx, "address:%u", address);
mxt_verb(ctx, "object_type:%u", object_type);
mxt_verb(ctx, "format:%s", format ? "true" : "false");
}
if (cmd == CMD_QUERY) {
ret = mxt_scan(ctx, &conn, true);
goto free;
} else if (cmd != CMD_FLASH && cmd != CMD_BOOTLOADER_VERSION) {
ret = mxt_init_chip(ctx, &mxt, &conn);
if (ret && cmd != CMD_CRC_CHECK )
goto free;
if (mxt)
mxt_set_debug(mxt, true);
}
switch (cmd) {
case CMD_WRITE:
mxt_verb(ctx, "Write command");
ret = mxt_handle_write_cmd(mxt, object_type, count, instance, address,
argc, argv);
if (ret == MXT_ERROR_BAD_INPUT)
goto free;
break;
case CMD_READ:
mxt_verb(ctx, "Read command");
ret = mxt_read_object(mxt, object_type, instance, address, count, format);
break;
case CMD_INFO:
mxt_verb(ctx, "CMD_INFO");
mxt_print_info_block(mxt);
ret = MXT_SUCCESS;
break;
case CMD_GOLDEN_REFERENCES:
mxt_verb(ctx, "CMD_GOLDEN_REFERENCES");
ret = mxt_store_golden_refs(mxt);
break;
case CMD_BRIDGE_SERVER:
mxt_verb(ctx, "CMD_BRIDGE_SERVER");
mxt_verb(ctx, "port:%u", port);
ret = mxt_socket_server(mxt, port);
break;
case CMD_BRIDGE_CLIENT:
mxt_verb(ctx, "CMD_BRIDGE_CLIENT");
ret = mxt_socket_client(mxt, strbuf, port);
break;
case CMD_SERIAL_DATA:
mxt_verb(ctx, "CMD_SERIAL_DATA");
mxt_verb(ctx, "t68_datatype:%u", t68_datatype);
ret = mxt_serial_data_upload(mxt, strbuf, t68_datatype);
break;
case CMD_TEST:
mxt_verb(ctx, "CMD_TEST");
ret = run_self_tests(mxt, self_test_cmd);
break;
case CMD_FLASH:
mxt_verb(ctx, "CMD_FLASH");
ret = mxt_flash_firmware(ctx, mxt, strbuf, strbuf2, conn);
break;
case CMD_RESET:
mxt_verb(ctx, "CMD_RESET");
ret = mxt_reset_chip(mxt, false);
break;
case CMD_RESET_BOOTLOADER:
mxt_verb(ctx, "CMD_RESET_BOOTLOADER");
ret = mxt_reset_chip(mxt, true);
break;
case CMD_BOOTLOADER_VERSION:
mxt_verb(ctx, "CMD_RESET_BOOTLOADER");
ret = mxt_bootloader_version(ctx, mxt, conn);
break;
case CMD_MESSAGES:
// Messages handled after switch
break;
case CMD_BACKUP:
mxt_verb(ctx, "CMD_BACKUP");
ret = mxt_backup_config(mxt, backup_cmd);
break;
case CMD_CALIBRATE:
mxt_verb(ctx, "CMD_CALIBRATE");
ret = mxt_calibrate_chip(mxt);
break;
case CMD_DEBUG_DUMP:
mxt_verb(ctx, "CMD_DEBUG_DUMP");
mxt_verb(ctx, "mode:%u", t37_mode);
mxt_verb(ctx, "frames:%u", t37_frames);
ret = mxt_debug_dump(mxt, t37_mode, strbuf, t37_frames);
break;
case CMD_ZERO_CFG:
mxt_verb(ctx, "CMD_ZERO_CFG");
ret = mxt_zero_config(mxt);
if (ret)
mxt_err(ctx, "Error zeroing all configuration settings");
break;
case CMD_LOAD_CFG:
mxt_verb(ctx, "CMD_LOAD_CFG");
mxt_verb(ctx, "filename:%s", strbuf);
ret = mxt_load_config_file(mxt, strbuf);
if (ret) {
mxt_err(ctx, "Error loading the configuration");
} else {
mxt_info(ctx, "Configuration loaded");
ret = mxt_backup_config(mxt, backup_cmd);
if (ret) {
mxt_err(ctx, "Error backing up");
} else {
mxt_info(ctx, "Configuration backed up");
ret = mxt_reset_chip(mxt, false);
if (ret) {
mxt_err(ctx, "Error resetting");
} else {
mxt_info(ctx, "Chip reset");
}
}
}
break;
case CMD_SAVE_CFG:
mxt_verb(ctx, "CMD_SAVE_CFG");
mxt_verb(ctx, "filename:%s", strbuf);
ret = mxt_save_config_file(mxt, strbuf);
break;
case CMD_SELF_CAP_TUNE_CONFIG:
case CMD_SELF_CAP_TUNE_NVRAM:
mxt_verb(ctx, "CMD_SELF_CAP_TUNE");
ret = mxt_self_cap_tune(mxt, cmd);
break;
case CMD_CRC_CHECK:
mxt_verb(ctx, "CMD_CRC_CHECK");
mxt_verb(ctx, "filename:%s", strbuf);
ret = mxt_checkcrc(ctx, mxt, strbuf);
break;
case CMD_NONE:
default:
mxt_verb(ctx, "cmd: %d", cmd);
mxt_set_log_fn(ctx, mxt_log_stdout);
if (verbose <= 2)
mxt_set_log_level(ctx, 2);
ret = mxt_menu(mxt);
break;
}
if (cmd == CMD_MESSAGES || (msgs_enabled && ret == MXT_SUCCESS)) {
mxt_verb(ctx, "CMD_MESSAGES");
mxt_verb(ctx, "msgs_timeout:%d", msgs_timeout);
// Support message filtering with -T
if (cmd == CMD_MESSAGES && !msg_filter_type)
msg_filter_type = object_type;
ret = print_raw_messages(mxt, msgs_timeout, msg_filter_type);
}
if (cmd != CMD_FLASH && cmd != CMD_BOOTLOADER_VERSION && mxt) {
mxt_set_debug(mxt, false);
mxt_free_device(mxt);
mxt_unref_conn(conn);
}
free:
mxt_free(ctx);
return ret;
}
mxt-app-1.27/src/mxt-app/mxt_app.h 0000664 0000000 0000000 00000012441 12706171405 0017034 0 ustar 00root root 0000000 0000000 #pragma once
//------------------------------------------------------------------------------
/// \file mxt_app.h
/// \brief mxt-app header file
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2012 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#define MIN(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
/* T6 Debug Diagnostics Commands */
#define PAGE_UP 0x01
#define PAGE_DOWN 0x02
#define DELTAS_MODE 0x10
#define REFS_MODE 0x11
#define SELF_CAP_SIGNALS 0xF5
#define SELF_CAP_DELTAS 0xF7
#define SELF_CAP_REFS 0xF8
#define AST_DELTAS 0xFB
#define AST_REFS 0xFC
/* T25 Self Test Commands */
#define SELF_TEST_ANALOG 0x01
#define SELF_TEST_PIN_FAULT 0x11
#define SELF_TEST_PIN_FAULT_2 0x12
#define SELF_TEST_AND_GATE 0x13
#define SELF_TEST_SIGNAL_LIMIT 0x17
#define SELF_TEST_GAIN 0x20
#define SELF_TEST_OFFSET 0x21
#define SELF_TEST_ALL 0xFE
#define SELF_TEST_INVALID 0xFD
#define SELF_TEST_TIMEOUT 0xFC
/* Message Timeout Options */
#define MSG_NO_WAIT 0
#define MSG_CONTINUOUS -1
//******************************************************************************
/// \brief Commands for mxt-app
typedef enum mxt_app_cmd_t {
CMD_NONE,
CMD_QUERY,
CMD_INFO,
CMD_TEST,
CMD_WRITE,
CMD_READ,
CMD_GOLDEN_REFERENCES,
CMD_BRIDGE_CLIENT,
CMD_BRIDGE_SERVER,
CMD_SERIAL_DATA,
CMD_FLASH,
CMD_RESET,
CMD_RESET_BOOTLOADER,
CMD_BOOTLOADER_VERSION,
CMD_BACKUP,
CMD_CALIBRATE,
CMD_DEBUG_DUMP,
CMD_LOAD_CFG,
CMD_SAVE_CFG,
CMD_MESSAGES,
CMD_SELF_CAP_TUNE_CONFIG,
CMD_SELF_CAP_TUNE_NVRAM,
CMD_ZERO_CFG,
CMD_CRC_CHECK,
} mxt_app_cmd;
//******************************************************************************
/// \brief Signal handler semaphore
volatile sig_atomic_t mxt_sigint_rx;
struct t37_diagnostic_data;
//******************************************************************************
/// \brief T37 Diagnostic Data context object
struct t37_ctx {
struct mxt_device *mxt;
struct libmaxtouch_ctx *lc;
bool self_cap;
bool active_stylus;
int x_size;
int y_size;
int data_values;
int passes;
int pages_per_pass;
int stripe_width;
int stripe_starty;
int stripe_endy;
uint8_t page_size;
uint8_t mode;
int diag_cmd_addr;
int t37_addr;
int t37_size;
uint8_t t111_instances;
uint8_t t107_instances;
uint16_t frame;
int pass;
int page;
int x_ptr;
int y_ptr;
struct t37_diagnostic_data *t37_buf;
uint16_t *data_buf;
FILE *hawkeye;
};
int mxt_flash_firmware(struct libmaxtouch_ctx *ctx, struct mxt_device *mxt, const char *filename, const char *new_version, struct mxt_conn_info *conn);
int mxt_socket_server(struct mxt_device *mxt, uint16_t port);
int mxt_socket_client(struct mxt_device *mxt, char *ip_address, uint16_t port);
int mxt_debug_dump(struct mxt_device *mxt, int mode, const char *csv_file, uint16_t frames);
void mxt_dd_menu(struct mxt_device *mxt);
int mxt_store_golden_refs(struct mxt_device *mxt);
int mxt_menu(struct mxt_device *mxt);
uint8_t self_test_menu(struct mxt_device *mxt);
int run_self_tests(struct mxt_device *mxt, uint8_t cmd);
int mxt_serial_data_upload(struct mxt_device *mxt, const char *filename, uint16_t datatype);
int print_raw_messages(struct mxt_device *mxt, int timeout, uint16_t object_type);
int print_raw_messages_t44(struct mxt_device *mxt);
void print_t6_status(uint8_t status);
int mxt_self_cap_tune(struct mxt_device *mxt, mxt_app_cmd cmd);
int mxt_read_diagnostic_data_frame(struct t37_ctx *ctx);
int mxt_debug_dump_initialise(struct t37_ctx *ctx);
sig_atomic_t mxt_get_sigint_flag(void);
int mxt_read_messages_sigint(struct mxt_device *mxt, int timeout_seconds, void *context, int (*msg_func)(struct mxt_device *mxt, uint8_t *msg, void *context, uint8_t size));
int mxt_bootloader_version(struct libmaxtouch_ctx *ctx, struct mxt_device *mxt, struct mxt_conn_info *conn);
mxt-app-1.27/src/mxt-app/self_cap.c 0000664 0000000 0000000 00000012050 12706171405 0017127 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file self_cap.c
/// \brief Self Capacitance functions
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2014 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include
#include "libmaxtouch/libmaxtouch.h"
#include "libmaxtouch/info_block.h"
#include "libmaxtouch/utilfuncs.h"
#include "libmaxtouch/log.h"
#include "libmaxtouch/msg.h"
#include "mxt_app.h"
#define T109_TIMEOUT 30
#define T109_CMD_OFFSET 3
#define T109_CMD_TUNE 1
#define T109_CMD_STORE_TO_NVM 2
#define T109_CMD_STORE_TO_CONFIG_RAM 4
//******************************************************************************
/// \brief Check status of previously sent command
/// \return #mxt_rc
static int mxt_self_cap_command(struct mxt_device *mxt, uint8_t *msg,
void *context, uint8_t size)
{
unsigned int object_type = mxt_report_id_to_type(mxt, msg[0]);
uint8_t *cmd = context;
mxt_verb(mxt->ctx, "Received message from T%u", object_type);
if (object_type == SPT_SELFCAPGLOBALCONFIG_T109) {
if (msg[1] == *cmd) {
switch (msg[2]) {
case 0:
return MXT_SUCCESS;
case 1:
return MXT_ERROR_SELFCAP_TUNE;
}
}
} else if (object_type == GEN_COMMANDPROCESSOR_T6) {
print_t6_status(msg[1]);
}
return MXT_MSG_CONTINUE;
}
//******************************************************************************
/// \brief Run self cap tuning procedure without updating the config
/// checksum
/// \return #mxt_rc
int mxt_self_cap_tune(struct mxt_device *mxt, mxt_app_cmd cmd)
{
int ret;
uint16_t t6_addr;
uint16_t t109_addr;
uint8_t backupnv_value;
uint8_t t109_command;
mxt_msg_reset(mxt);
// Enable self test object & reporting
t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0);
if (t6_addr == OBJECT_NOT_FOUND)
return MXT_ERROR_OBJECT_NOT_FOUND;
t109_addr = mxt_get_object_address(mxt, SPT_SELFCAPGLOBALCONFIG_T109, 0);
if (t109_addr == OBJECT_NOT_FOUND)
return MXT_ERROR_OBJECT_NOT_FOUND;
mxt_info(mxt->ctx, "Stopping T70");
backupnv_value = 0x33;
ret = mxt_write_register(mxt, &backupnv_value, t6_addr + MXT_T6_BACKUPNV_OFFSET, 1);
if (ret)
return ret;
// Wait for backup operation to complete (otherwise T109 report may be missed)
mxt_msg_wait(mxt, 100);
mxt_info(mxt->ctx, "Tuning");
t109_command = T109_CMD_TUNE;
mxt_info(mxt->ctx, "Writing %u to T109 CMD register", cmd);
ret = mxt_write_register(mxt, &t109_command, t109_addr + T109_CMD_OFFSET, 1);
if (ret)
return ret;
ret = mxt_read_messages(mxt, T109_TIMEOUT, &t109_command, mxt_self_cap_command, (int *)&mxt_sigint_rx);
if (ret)
return ret;
switch (cmd) {
case CMD_SELF_CAP_TUNE_CONFIG:
mxt_info(mxt->ctx, "Store to Config");
t109_command = T109_CMD_STORE_TO_CONFIG_RAM;
break;
default:
case CMD_SELF_CAP_TUNE_NVRAM:
mxt_info(mxt->ctx, "Store to NVRAM");
t109_command = T109_CMD_STORE_TO_NVM;
break;
}
mxt_info(mxt->ctx, "Writing %u to T109 CMD register", cmd);
ret = mxt_write_register(mxt, &t109_command, t109_addr + T109_CMD_OFFSET, 1);
if (ret)
return ret;
ret = mxt_read_messages(mxt, 100, (void *) &t109_command, mxt_self_cap_command, (int *)&mxt_sigint_rx);
if (ret)
return ret;
mxt_info(mxt->ctx, "Saving configuration");
ret = mxt_backup_config(mxt, BACKUPNV_COMMAND);
if (ret)
return ret;
ret = mxt_reset_chip(mxt, false);
if (ret)
return ret;
return MXT_SUCCESS;
}
mxt-app-1.27/src/mxt-app/self_test.c 0000664 0000000 0000000 00000024040 12706171405 0017345 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file self_test.c
/// \brief T25 Self Test functions
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2012 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include
#include "libmaxtouch/libmaxtouch.h"
#include "libmaxtouch/info_block.h"
#include "libmaxtouch/utilfuncs.h"
#include "libmaxtouch/log.h"
#include "mxt_app.h"
#define T25_TIMEOUT 10
//******************************************************************************
/// \brief Handle messages from the self test object
/// \return #mxt_rc
static int self_test_handle_messages(struct mxt_device *mxt, uint8_t *msg,
void *context, uint8_t size)
{
unsigned int object_type = mxt_report_id_to_type(mxt, msg[0]);
int ret;
mxt_verb(mxt->ctx, "Received message from T%u", object_type);
if (object_type == SPT_SELFTEST_T25) {
switch (msg[1]) {
case SELF_TEST_ALL:
mxt_info(mxt->ctx, "PASS: All tests passed");
ret = MXT_SUCCESS;
break;
case SELF_TEST_INVALID:
mxt_err(mxt->ctx, "FAIL: Invalid or unsupported test command");
ret = MXT_ERROR_NOT_SUPPORTED;
break;
case SELF_TEST_TIMEOUT:
mxt_err(mxt->ctx, "FAIL: Test timeout");
ret = MXT_ERROR_TIMEOUT;
break;
case SELF_TEST_ANALOG:
mxt_err(mxt->ctx, "FAIL: AVdd Analog power is not present");
ret = MXT_ERROR_SELF_TEST_ANALOG;
break;
case SELF_TEST_PIN_FAULT:
mxt_err(mxt->ctx, "FAIL: Pin fault");
ret = MXT_ERROR_SELF_TEST_PIN_FAULT;
break;
case SELF_TEST_PIN_FAULT_2:
if (msg[3] == 0 && msg[4] == 0)
mxt_err(mxt->ctx, "FAIL: Pin fault SEQ_NUM=%d driven shield line failed");
else if (msg[3] > 0)
mxt_err(mxt->ctx, "FAIL: Pin fault SEQ_NUM=%d X%d", msg[2], msg[3] - 1);
else if (msg[4] > 0)
mxt_err(mxt->ctx, "FAIL: Pin fault SEQ_NUM=%d Y%d", msg[2], msg[4] - 1);
ret = MXT_ERROR_SELF_TEST_PIN_FAULT;
break;
case SELF_TEST_AND_GATE:
mxt_err(mxt->ctx, "FAIL: AND Gate Fault");
ret = MXT_ERROR_SELF_TEST_AND_GATE;
break;
case SELF_TEST_SIGNAL_LIMIT:
mxt_err(mxt->ctx, "FAIL: Signal limit fault in T%d[%d]", msg[2], msg[3]);
ret = MXT_ERROR_SELF_TEST_SIGNAL_LIMIT;
break;
case SELF_TEST_GAIN:
mxt_err(mxt->ctx, "FAIL: Gain error");
ret = MXT_ERROR_SELF_TEST_GAIN;
break;
default:
mxt_err(mxt->ctx, "FAIL: status %02X", msg[1]);
ret = MXT_ERROR_UNEXPECTED_DEVICE_STATE;
break;
}
} else {
ret = MXT_MSG_CONTINUE;
}
return ret;
}
//******************************************************************************
/// \brief Print T25 limits for enabled touch object instances
static int print_touch_object_limits(struct mxt_device *mxt, uint16_t t25_addr,
uint16_t object_type, int *touch_object)
{
uint8_t buf[4];
uint16_t upsiglim;
uint16_t losiglim;
bool enabled;
int instance;
int ret;
for (instance = 0; (instance < mxt_get_object_instances(mxt, object_type));
instance++) {
ret = mxt_read_register(mxt, (uint8_t *)&buf,
mxt_get_object_address(mxt, object_type, instance), 1);
if (ret)
return ret;
enabled = buf[0] & 0x01;
mxt_info(mxt->ctx, "%s[%d] %s",
mxt_get_object_name(object_type),
instance,
enabled ? "enabled":"disabled");
if (enabled) {
ret = mxt_read_register(mxt, (uint8_t *)&buf,
t25_addr + 2 + *touch_object * 4, 4);
if (ret)
return ret;
upsiglim = (uint16_t)((buf[1] << 8u) | buf[0]);
losiglim = (uint16_t)((buf[3] << 8u) | buf[2]);
mxt_info(mxt->ctx, " UPSIGLIM:%d", upsiglim);
mxt_info(mxt->ctx, " LOSIGLIM:%d", losiglim);
}
(*touch_object)++;
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Print T25 limits for each enabled touch object
static int print_t25_limits(struct mxt_device *mxt, uint16_t t25_addr)
{
int touch_object = 0;
int ret;
ret = print_touch_object_limits(mxt, t25_addr, TOUCH_MULTITOUCHSCREEN_T9,
&touch_object);
if (ret)
return ret;
ret = print_touch_object_limits(mxt, t25_addr, TOUCH_MULTITOUCHSCREEN_T100,
&touch_object);
if (ret)
return ret;
ret = print_touch_object_limits(mxt, t25_addr, TOUCH_PROXKEY_T52,
&touch_object);
if (ret)
return ret;
ret = print_touch_object_limits(mxt, t25_addr, TOUCH_KEYARRAY_T15,
&touch_object);
if (ret)
return ret;
ret = print_touch_object_limits(mxt, t25_addr, TOUCH_PROXIMITY_T23,
&touch_object);
if (ret)
return ret;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Disable noise suppression objects
static void disable_noise_suppression(struct mxt_device *mxt)
{
uint16_t addr;
uint8_t disable = 0;
addr = mxt_get_object_address(mxt, PROCG_NOISESUPPRESSION_T22, 0);
if (addr != OBJECT_NOT_FOUND) {
mxt_write_register(mxt, &disable, addr, 1);
}
addr = mxt_get_object_address(mxt, PROCG_NOISESUPPRESSION_T48, 0);
if (addr != OBJECT_NOT_FOUND) {
mxt_write_register(mxt, &disable, addr, 1);
}
addr = mxt_get_object_address(mxt, PROCG_NOISESUPPRESSION_T54, 0);
if (addr != OBJECT_NOT_FOUND) {
mxt_write_register(mxt, &disable, addr, 1);
}
addr = mxt_get_object_address(mxt, PROCG_NOISESUPPRESSION_T62, 0);
if (addr != OBJECT_NOT_FOUND) {
mxt_write_register(mxt, &disable, addr, 1);
}
}
//******************************************************************************
/// \brief Run self test
int run_self_tests(struct mxt_device *mxt, uint8_t cmd)
{
uint16_t t25_addr;
uint8_t enable = 3;
int ret;
mxt_msg_reset(mxt);
// Enable self test object & reporting
t25_addr = mxt_get_object_address(mxt, SPT_SELFTEST_T25, 0);
mxt_info(mxt->ctx, "Enabling self test object");
mxt_write_register(mxt, &enable, t25_addr, 1);
mxt_info(mxt->ctx, "Disabling noise suppression");
disable_noise_suppression(mxt);
ret = print_t25_limits(mxt, t25_addr);
if (ret)
return ret;
switch (cmd) {
case SELF_TEST_ANALOG:
mxt_info(mxt->ctx, "Running Analog power test");
break;
case SELF_TEST_PIN_FAULT:
mxt_info(mxt->ctx, "Running Pin fault test");
break;
case SELF_TEST_PIN_FAULT_2:
mxt_info(mxt->ctx, "Running Pin fault 2 test");
break;
case SELF_TEST_AND_GATE:
mxt_info(mxt->ctx, "Running AND Gate test");
break;
case SELF_TEST_SIGNAL_LIMIT:
mxt_info(mxt->ctx, "Running Signal Limit test");
break;
case SELF_TEST_GAIN:
mxt_info(mxt->ctx, "Running Gain test");
break;
case SELF_TEST_OFFSET:
mxt_info(mxt->ctx, "Running Offset test");
break;
case SELF_TEST_ALL:
mxt_info(mxt->ctx, "Running all tests");
break;
default:
mxt_info(mxt->ctx, "Writing %02X to CMD register", cmd);
break;
}
mxt_write_register(mxt, &cmd, t25_addr + 1, 1);
return mxt_read_messages_sigint(mxt, T25_TIMEOUT, NULL, self_test_handle_messages);
}
//******************************************************************************
/// \brief Run self test
uint8_t self_test_menu(struct mxt_device *mxt)
{
int self_test;
uint8_t cmd;
while (1) {
cmd = 0;
printf("Self-test menu:\n\
Enter 1 for running Analog power test\n\
Enter 2 for running Pin fault test\n\
Enter 3 for running Pin fault 2 test\n\
Enter 4 for running AND Gate test\n\
Enter 5 for running Signal Limit test\n\
Enter 6 for running Gain test\n\
Enter 7 for running all the above tests\n\
Enter 255 to get out of the self-test menu\n");
if (scanf("%d", &self_test) != 1) {
printf("Input error\n");
return MXT_ERROR_BAD_INPUT;
}
switch(self_test) {
case 1:
cmd = SELF_TEST_ANALOG;
break;
case 2:
cmd = SELF_TEST_PIN_FAULT;
break;
case 3:
cmd = SELF_TEST_PIN_FAULT_2;
break;
case 4:
cmd = SELF_TEST_AND_GATE;
break;
case 5:
cmd = SELF_TEST_SIGNAL_LIMIT;
break;
case 6:
cmd = SELF_TEST_GAIN;
break;
case 7:
cmd = SELF_TEST_ALL;
break;
case 255:
return MXT_SUCCESS;
break;
default:
printf("Invalid option\n");
break;
}
if (cmd)
run_self_tests(mxt, cmd);
}
return MXT_SUCCESS;
}
mxt-app-1.27/src/mxt-app/serial_data.c 0000664 0000000 0000000 00000030534 12706171405 0017632 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file serial_data.c
/// \brief T68 Serial Data Command support
/// \author Nick Dyer
//------------------------------------------------------------------------------
// Copyright 2012 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include
#include "libmaxtouch/libmaxtouch.h"
#include "libmaxtouch/info_block.h"
#include "libmaxtouch/utilfuncs.h"
#include "libmaxtouch/log.h"
#include "mxt_app.h"
#include "buffer.h"
#define T68_CTRL 0
#define T68_CTRL_ENABLE (1 << 0)
#define T68_CTRL_RPTEN (1 << 1)
#define T68_DATATYPE 3
#define T68_CMD_NONE 0
#define T68_CMD_START 1
#define T68_CMD_CONTINUE 2
#define T68_CMD_END 3
#define T68_LENGTH 5
#define T68_DATA 6
#define T68_TIMEOUT 30
//******************************************************************************
/// \brief T68 Serial Data Command Context object
struct t68_ctx {
struct mxt_device *mxt;
struct libmaxtouch_ctx *lc;
const char *filename;
struct mxt_buffer buf;
uint16_t t68_addr;
uint8_t t68_size;
uint16_t t68_cmd_addr;
uint16_t t68_data_size;
uint16_t t68_datatype;
};
//******************************************************************************
/// \brief Print T68 status messages
static void mxt_t68_print_status(struct t68_ctx *ctx, uint8_t status)
{
mxt_info(ctx->lc, "T68 status: %02X %s%s%s%s%s%s%s",
status,
(status == 0x00) ? "Success/No error" : "",
(status == 0x01) ? "Command supplied in CMD.COMMAND is out of sequence" : "",
(status == 0x02) ? "Supplied DATATYPE value is not supported" : "",
(status == 0x03) ? "Supplied LENGTH value exceeds length of DATA[] array" : "",
(status == 0x04) ? "More bytes supplied than can be accommodated by this data type" : "",
(status == 0x05) ? "Data content is invalid" : "",
(status == 0x0F) ? "The action could not be completed due to an error outside of this object" : "");
}
//******************************************************************************
/// \brief Handle status messages from the T68 Serial Data Command object
/// \return #mxt_rc
static int mxt_t68_get_status(struct mxt_device *mxt, uint8_t *msg,
void *context, uint8_t size)
{
struct t68_ctx *ctx = context;
unsigned int object_type = mxt_report_id_to_type(mxt, msg[0]);
uint8_t status;
mxt_verb(mxt->ctx, "Received message from T%u", object_type);
if (object_type == SERIAL_DATA_COMMAND_T68) {
/* mask off reserved bits */
status = msg[1] & 0x0F;
mxt_t68_print_status(ctx, status);
return (status == 0) ? MXT_SUCCESS : MXT_ERROR_SERIAL_DATA_FAILURE;
} else if (object_type == GEN_COMMANDPROCESSOR_T6) {
print_t6_status(msg[1]);
}
return MXT_MSG_CONTINUE;
}
//******************************************************************************
/// \brief Send command then check status
/// \return #mxt_rc
static int mxt_t68_command(struct t68_ctx *ctx, uint8_t cmd)
{
int ret;
mxt_verb(ctx->lc, "Writing %u to CMD register", cmd);
ret = mxt_write_register(ctx->mxt, &cmd, ctx->t68_cmd_addr, 1);
if (ret)
return ret;
return mxt_read_messages_sigint(ctx->mxt, T68_TIMEOUT, ctx, mxt_t68_get_status);
}
//******************************************************************************
/// \brief Enable T68
/// \return #mxt_rc
static int mxt_t68_enable(struct t68_ctx *ctx)
{
int ret;
uint8_t cmd = T68_CTRL_RPTEN | T68_CTRL_ENABLE;
mxt_dbg(ctx->lc, "Enabling T68 object");
mxt_verb(ctx->lc, "Writing %u to ctrl register", cmd);
ret = mxt_write_register(ctx->mxt, &cmd, ctx->t68_addr + T68_CTRL, 1);
if (ret)
return ret;
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Read hex encoded data from file
/// \return #mxt_rc
static int mxt_t68_load_file(struct t68_ctx *ctx)
{
int ret;
uint8_t value = 0;
FILE *fp;
bool file_read = false;
char buf[256];
uint16_t hexcount;
int c;
/* open file */
fp = fopen(ctx->filename, "r");
if (fp == NULL) {
mxt_err(ctx->lc, "Error opening %s", ctx->filename);
return mxt_errno_to_rc(errno);
}
ret = mxt_buf_init(&ctx->buf);
if (ret) {
mxt_err(ctx->lc, "Error initialising buffer");
goto close;
}
while (!file_read) {
/* Read next value from file */
c = getc(fp);
if (c == EOF) {
break;
}
/* skip spaces, newlines, commas*/
else if (c == 0x20 || c == '\r' || c == '\n' || c == ',') {
continue;
}
/* Ignore comment lines */
else if (c == '[') {
// Grab comment key
if (fscanf(fp, "%255[^]]", buf) != 1) {
ret = MXT_ERROR_FILE_FORMAT;
goto fail;
}
mxt_verb(ctx->lc, "[%s]", buf);
if (!strncasecmp(buf, "datatype=", 9)) {
if (sscanf(buf + 9, "%d", &c) != 1) {
mxt_warn(ctx->lc, "Unable to parse datatype");
} else {
ctx->t68_datatype = c;
mxt_info(ctx->lc, "DATATYPE set to %u by file", ctx->t68_datatype);
}
}
// Read until end of line
while (c != '\n') {
c = getc(fp);
}
continue;
}
/* A value looks like "0xABu," */
else if (c == '0') {
if (fscanf(fp, "x%2su", (char *)&buf) != 1) {
mxt_err(ctx->lc, "Parse error");
ret = MXT_ERROR_FILE_FORMAT;
goto fail;
}
ret = mxt_convert_hex(buf, &value, &hexcount, 3);
if (ret)
goto fail;
ret = mxt_buf_add(&ctx->buf, value);
if (ret)
goto fail;
} else {
mxt_err(ctx->lc, "Unexpected character \"%c\"", c);
ret = MXT_ERROR_FILE_FORMAT;
goto fail;
}
}
mxt_info(ctx->lc, "Loaded file %s, %zu bytes", ctx->filename, ctx->buf.size);
return MXT_SUCCESS;
fail:
mxt_buf_free(&ctx->buf);
close:
fclose(fp);
return ret;
}
//******************************************************************************
/// \brief Write LENGTH
/// \return #mxt_rc
static int mxt_t68_write_length(struct t68_ctx *ctx, uint8_t length)
{
mxt_dbg(ctx->lc, "Writing LENGTH=%u", length);
return mxt_write_register(ctx->mxt, &length, ctx->t68_addr + T68_LENGTH, 1);
}
//******************************************************************************
/// \brief Zero entire T68 object
/// \return #mxt_rc
static int mxt_t68_zero_data(struct t68_ctx *ctx)
{
uint8_t zeros[ctx->t68_data_size];
mxt_dbg(ctx->lc, "Zeroing DATA");
memset(&zeros, 0, sizeof(zeros));
return mxt_write_register(ctx->mxt, zeros,
ctx->t68_addr + T68_DATA,
sizeof(zeros));
}
//******************************************************************************
/// \brief Send frames of T68 data to chip
/// \return #mxt_rc
static int mxt_t68_send_frames(struct t68_ctx *ctx)
{
int ret;
size_t offset = 0;
uint16_t frame_size;
int frame = 1;
uint8_t cmd;
while (offset < ctx->buf.size) {
frame_size = MIN(ctx->buf.size - offset, ctx->t68_data_size);
mxt_info(ctx->lc, "Writing frame %u, %u bytes", frame, frame_size);
if (frame_size > UCHAR_MAX) {
mxt_err(ctx->lc, "Serial data frame size miscalculation");
return MXT_INTERNAL_ERROR;
}
ret = mxt_write_register(ctx->mxt, ctx->buf.data + offset,
ctx->t68_addr + T68_DATA,
frame_size);
if (ret)
return ret;
ret = mxt_t68_write_length(ctx, frame_size);
if (ret)
return ret;
offset += frame_size;
if (frame == 1)
cmd = T68_CMD_START;
else if (offset >= ctx->buf.size)
cmd = T68_CMD_END;
else
cmd = T68_CMD_CONTINUE;
ret = mxt_t68_command(ctx, cmd);
if (ret)
return ret;
frame++;
}
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Write DATATYPE
/// \return #mxt_rc
static int mxt_t68_write_datatype(struct t68_ctx *ctx)
{
uint8_t buf[2];
buf[0] = (ctx->t68_datatype & 0xFF);
buf[1] = (ctx->t68_datatype & 0xFF00) >> 8;
mxt_info(ctx->lc, "Writing %u to DATATYPE register", ctx->t68_datatype);
return mxt_write_register(ctx->mxt, &buf[0], ctx->t68_addr + T68_DATATYPE, sizeof(buf));
}
//******************************************************************************
/// \brief Check chip is not in deep sleep
/// \return #mxt_rc
static int mxt_t68_check_power_cfg(struct t68_ctx *ctx)
{
uint16_t t7_addr;
uint8_t buf[2];
int ret;
/* Skip if object not present */
t7_addr = mxt_get_object_address(ctx->mxt, GEN_POWERCONFIG_T7, 0);
if (t7_addr == OBJECT_NOT_FOUND)
return MXT_SUCCESS;
ret = mxt_read_register(ctx->mxt, &buf[0], t7_addr, sizeof(buf));
if (ret)
return ret;
mxt_verb(ctx->lc, "T7 IDLEACQINT=%u ACTVACQINT=%u", buf[0], buf[1]);
if ((buf[0] == 0) || (buf[1] == 0)) {
mxt_err(ctx->lc, "Warning: The T7 power configuration object shows that the chip "
"is in deep sleep, and so will not process T68 serial data "
"commands. Please set the T7 power configuration idle acquisition "
"interval to a non-zero value and try again.");
return MXT_ERROR_UNEXPECTED_DEVICE_STATE;
} else {
return MXT_SUCCESS;
}
}
//******************************************************************************
/// \brief Upload file to T68 Serial Data Object
/// \return #mxt_rc
int mxt_serial_data_upload(struct mxt_device *mxt, const char *filename, uint16_t datatype)
{
int ret;
struct t68_ctx ctx;
ctx.mxt = mxt;
ctx.lc = mxt->ctx;
ret = mxt_msg_reset(mxt);
if (ret)
return ret;
mxt_info(ctx.lc, "Checking T7 Power Config");
ret = mxt_t68_check_power_cfg(&ctx);
if (ret)
return ret;
/* Check for existence of T68 object */
ctx.t68_addr = mxt_get_object_address(mxt, SERIAL_DATA_COMMAND_T68, 0);
if (ctx.t68_addr == OBJECT_NOT_FOUND)
return MXT_ERROR_OBJECT_NOT_FOUND;
/* Calculate position of CMD register */
ctx.t68_size = mxt_get_object_size(mxt, SERIAL_DATA_COMMAND_T68);
ctx.t68_cmd_addr = ctx.t68_addr + ctx.t68_size - 3;
/* Calculate frame size */
ctx.t68_data_size = ctx.t68_size - 9;
/* Set datatype from command line */
ctx.t68_datatype = datatype;
/* Read input file */
ctx.filename = filename;
ret = mxt_t68_load_file(&ctx);
if (ret)
return ret;
ret = mxt_t68_enable(&ctx);
if (ret)
goto release;
ret = mxt_t68_zero_data(&ctx);
if (ret)
goto release;
ret = mxt_t68_write_length(&ctx, 0);
if (ret)
goto release;
mxt_info(ctx.lc, "Configuring T68");
ret = mxt_t68_write_datatype(&ctx);
if (ret)
goto release;
mxt_info(ctx.lc, "Sending data");
ret = mxt_t68_send_frames(&ctx);
if (ret) {
mxt_err(ctx.lc, "Error sending data");
goto release;
}
mxt_info(ctx.lc, "Done");
ret = MXT_SUCCESS;
release:
mxt_buf_free(&ctx.buf);
return ret;
}
mxt-app-1.27/src/mxt-app/signal.c 0000664 0000000 0000000 00000010635 12706171405 0016637 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file signal.c
/// \brief Signal handling functionality for mxt-app
/// \author Steven Swann
//------------------------------------------------------------------------------
// Copyright 2014 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include
#include "libmaxtouch/libmaxtouch.h"
#include "libmaxtouch/info_block.h"
#include "libmaxtouch/utilfuncs.h"
#include "libmaxtouch/log.h"
#include "libmaxtouch/msg.h"
#include "mxt_app.h"
//******************************************************************************
/// \brief Signal handler semaphore
volatile sig_atomic_t mxt_sigint_rx = 0;
//******************************************************************************
/// \brief Signal handler to catch SIGINT (Ctrl-C) when viewing continuous msgs
static void mxt_signal_handler(int signal_num)
{
if (signal_num == SIGINT) {
mxt_sigint_rx = 1;
}
}
//******************************************************************************
/// \brief Handles SIGINT signal
static void mxt_init_sigint_handler(struct mxt_device *mxt, struct sigaction *sa)
{
sa->sa_handler = mxt_signal_handler;
sigemptyset(&sa->sa_mask);
sa->sa_flags = SA_RESTART;
if (sigaction(SIGINT, sa, NULL) == -1)
mxt_err(mxt->ctx, "Can't catch SIGINT");
}
//******************************************************************************
/// \brief Sets default function for SIGINT signal
static void mxt_release_sigint_handler(struct mxt_device *mxt, struct sigaction *sa)
{
sa->sa_handler = SIG_DFL;
if (sigaction(SIGINT, sa, NULL) == -1)
mxt_err(mxt->ctx, "Can't return SIGINT to default handler");
mxt_sigint_rx = 0;
}
//******************************************************************************
/// \brief Get internal sigint flag
sig_atomic_t mxt_get_sigint_flag(void)
{
return mxt_sigint_rx;
}
//******************************************************************************
/// \brief Get messages from device and display to user, with Ctrl-C signal
/// \param timeout_seconds Represent the time in seconds to continuously
/// display messages to the user. By setting timeout_seconds to 0, or
/// MSG_NO_WAIT the T5 object is read only once. By setting timeout_seconds to
/// -1, or MSG_CONTINUOUS the T5 object is continually read until the user
/// presses Ctrl-C.
/// \param mxt Maxtouch Device
/// \param context Additional context required by msg_func
/// \param msg_func Pointer to function to read object status
/// \return #mxt_rc
int mxt_read_messages_sigint(struct mxt_device *mxt, int timeout_seconds, void *context,
int (*msg_func)(struct mxt_device *mxt, uint8_t *msg,
void *context, uint8_t size))
{
int ret;
struct sigaction sa;
mxt_init_sigint_handler(mxt, &sa);
ret = mxt_read_messages(mxt, timeout_seconds, context, (msg_func), (int *)&mxt_sigint_rx);
mxt_release_sigint_handler(mxt, &sa);
return ret;
}
mxt-app-1.27/src/mxt-app/touch_app.c 0000664 0000000 0000000 00000006757 12706171405 0017356 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file touch_app.c
/// \brief Utility functions for mxt-app
/// \author Iiro Valkonen
//------------------------------------------------------------------------------
// Copyright 2011 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "libmaxtouch/libmaxtouch.h"
#include "libmaxtouch/info_block.h"
#include "libmaxtouch/log.h"
#include "mxt_app.h"
//******************************************************************************
/// \brief Print message as hex
/// \return #mxt_rc
static int print_message_hex(struct mxt_device *mxt, uint8_t *msg,
void *context, uint8_t size)
{
const uint16_t object_type = *((uint16_t*)context);
int j;
int len;
if (object_type == 0 || object_type == mxt_report_id_to_type(mxt, msg[0])) {
len = snprintf(mxt->msg_string, sizeof(mxt->msg_string), MSG_PREFIX);
for (j = 0; j < size; j++) {
len += snprintf(mxt->msg_string + len, sizeof(mxt->msg_string) - len,
"%02X ", msg[j]);
}
printf("%s\n", mxt->msg_string);
fflush(stdout);
}
return MXT_MSG_CONTINUE;
}
//******************************************************************************
/// \brief Print messages
/// \return #mxt_rc
int print_raw_messages(struct mxt_device *mxt, int timeout, uint16_t object_type)
{
mxt_msg_reset(mxt);
mxt_read_messages_sigint(mxt, timeout, &object_type, print_message_hex);
return MXT_SUCCESS;
}
//******************************************************************************
/// \brief Handle status messages from the T6 command processor object
void print_t6_status(uint8_t status)
{
printf("T6 status: %s%s%s%s%s%s%s\n",
(status == 0) ? "OK":"",
(status & 0x04) ? "COMSERR ":"",
(status & 0x08) ? "CFGERR ":"",
(status & 0x10) ? "CAL ":"",
(status & 0x20) ? "SIGERR ":"",
(status & 0x40) ? "OFL ":"",
(status & 0x80) ? "RESET ":"");
}
mxt-app-1.27/src/test/ 0000775 0000000 0000000 00000000000 12706171405 0014602 5 ustar 00root root 0000000 0000000 mxt-app-1.27/src/test/run_unit_tests.c 0000664 0000000 0000000 00000003637 12706171405 0020044 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file run_tests.c
/// \brief Test suite for mxt-app.
/// \author Steven Swann
//------------------------------------------------------------------------------
// Copyright 2016 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include "run_unit_tests.h"
int main(int argc, char *argv[])
{
/* Test suite */
const struct CMUnitTest tests[] = {
unit_test(mxt_convert_hex_test),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}
mxt-app-1.27/src/test/run_unit_tests.h 0000664 0000000 0000000 00000003235 12706171405 0020043 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file run_tests.h
/// \brief Test suite for mxt-app.
/// \author Steven Swann
//------------------------------------------------------------------------------
// Copyright 2016 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
void mxt_convert_hex_test(void **state);
mxt-app-1.27/src/test/test_utilfuncs.c 0000664 0000000 0000000 00000005767 12706171405 0020040 0 ustar 00root root 0000000 0000000 //------------------------------------------------------------------------------
/// \file test_utilfuncs.c
/// \brief Tests against libmaxtouch/utilfuncs.h
/// \author Steven Swann
//------------------------------------------------------------------------------
// Copyright 2016 Atmel Corporation. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include "libmaxtouch/libmaxtouch.h"
#include "libmaxtouch/utilfuncs.h"
#include "run_unit_tests.h"
void mxt_convert_hex_test(void **state)
{
/* test setup */
uint8_t databuf[5] = {0};
char hex[4];
uint16_t count;
int ret;
/* perform tests */
strcpy(hex, "09");
mxt_convert_hex(hex, databuf, &count, sizeof(databuf)),
assert_int_equal(ret, MXT_SUCCESS);
assert_int_equal(databuf[0], 9);
assert_int_equal(count, 1);
strcpy(hex, "0F");
ret = mxt_convert_hex(hex, databuf, &count, sizeof(databuf));
assert_int_equal(ret, MXT_SUCCESS);
assert_int_equal(databuf[0], 0x0F);
assert_int_equal(count, 1);
strcpy(hex, "0FAB");
ret = mxt_convert_hex(hex, databuf, &count, sizeof(databuf));
assert_int_equal(ret, MXT_SUCCESS);
assert_true(databuf[0] == 0x0F);
assert_true(databuf[1] == 0xAB);
assert_int_equal(count, 2);
/* test error conditions */
strcpy(hex, "F");
ret = mxt_convert_hex(hex, databuf, &count, sizeof(databuf));
assert_int_equal(ret, MXT_ERROR_BAD_INPUT);
strcpy(hex, "0FAB");
ret = mxt_convert_hex(hex, databuf, &count, 1);
assert_int_equal(ret, MXT_ERROR_NO_MEM);
strcpy(hex, "0xA5");
ret = mxt_convert_hex(hex, databuf, &count, sizeof(databuf));
assert_int_equal(ret, MXT_ERROR_BAD_INPUT);
}