├── LICENSE ├── README.md ├── adafruit-pi-chroot ├── adafruit-pitft-chroot-install ├── adafruit-pitft-helper ├── adafruit-pitft-helper2.sh └── adafruit-pitft-touch-cal /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Adafruit Industries 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Adafruit-PiTFT-Helper 2 | 3 | ### This script/repository is deprecated, as trying to do kernel updates on the fast-moving Raspberry Pi wasn't sustainable! We're now using a simpler device-tree-only script, available at https://github.com/adafruit/Raspberry-Pi-Installer-Scripts/blob/main/adafruit-pitft.py 4 | 5 | We'll keep this repo public but archived for the curious. 6 | 7 | --------------------------------- 8 | 9 | A (deprecated) script for configuring Adafruit's PiTFT displays on a Raspberry Pi. 10 | 11 | ## Attention RETROPIE Users: 12 | 13 | Do not use the adafruit-pitft-helper script with RetroPie. Instead, follow the directions on this page: 14 | https://learn.adafruit.com/running-opengl-based-games-and-emulators-on-adafruit-pitft-displays/pitft-setup 15 | 16 | ## PiTFT Documentation 17 | 18 | Products: 19 | 20 | - [PiTFT - Assembled 320x240 2.8" TFT+Touchscreen for Raspberry Pi](https://www.adafruit.com/product/1601) 21 | - [PiTFT - Assembled 480x320 3.5" TFT+Touchscreen for Raspberry Pi](https://www.adafruit.com/product/2097) 22 | - [Adafruit PiTFT 2.2" HAT Mini Kit - 320x240 2.2" TFT - No Touch](https://www.adafruit.com/product/2315) 23 | 24 | Detailed installation guides: 25 | 26 | - [Guide: Adafruit PiTFT - 2.8" Touchscreen Display for Raspberry Pi](https://learn.adafruit.com/adafruit-pitft-28-inch-resistive-touchscreen-display-raspberry-pi/overview) 27 | - [Guide: Adafruit PiTFT 3.5" Touch Screen for Raspberry Pi](https://learn.adafruit.com/adafruit-pitft-3-dot-5-touch-screen-for-raspberry-pi/overview) 28 | - [Guide: Adafruit 2.2" PiTFT HAT - 320x240 Display](https://learn.adafruit.com/adafruit-2-2-pitft-hat-320-240-primary-display-for-raspberry-pi/overview) 29 | - [Running OpenGL-based Games & Emulators on Adafruit PiTFT Displays](https://learn.adafruit.com/running-opengl-based-games-and-emulators-on-adafruit-pitft-displays/overview) 30 | 31 | ## Getting Started: Kernel & Helper Script Installation 32 | 33 | First, add [Adafruit's Occidentalis package repository][o] to your system. 34 | Occidentalis is a growing collection of useful packages and configuration 35 | defaults for installation on Raspbian systems. 36 | 37 | If you want to bootstrap the full version of Occidentalis on a fresh, unused Pi 38 | from another computer, we offer an easy graphical tool called the [Pi Finder][p]. 39 | Once bootstrapped, you can open a terminal on your Pi and run: 40 | 41 | ```sh 42 | sudo apt-get install raspberrypi-bootloader 43 | sudo apt-get install adafruit-pitft-helper 44 | ``` 45 | 46 | ...which first installs a custom kernel with PiTFT support, and then the helper 47 | script itself. If you _just_ want to install the kernel and helper without 48 | pulling down any other extra packages, you can run the following from the 49 | command line of a working Pi: 50 | 51 | ```sh 52 | curl -SLs https://apt.adafruit.com/add | sudo bash 53 | sudo apt-get install raspberrypi-bootloader 54 | sudo apt-get install adafruit-pitft-helper 55 | ``` 56 | 57 | This can take a surprisingly long time to finish, especially if you're using a 58 | slower SD card, so be patient. 59 | 60 | **Please be careful!** Installing a new kernel always has the potential to 61 | leave your Raspberry Pi unbootable. You should make a backup copy of your SD 62 | card before trying this, or (even better!) start with a fresh card. 63 | 64 | ## Using adafruit-pitft-helper 65 | 66 | `adafruit-pitft-helper` must be run with root privileges, and takes a parameter 67 | specifying the type of PiTFT to configure. Invoke it like so: 68 | 69 | ```sh 70 | sudo adafruit-pitft-helper -t 28r 71 | ``` 72 | 73 | For a full list of available options, check the help: 74 | 75 | ```sh 76 | adafruit-pitft-helper -h 77 | ``` 78 | 79 | ## Installing PiTFT support in a Raspbian image file (experimental!) 80 | 81 | This repository includes a [small wrapper script][c] for installing the custom 82 | kernel and PiTFT configuration in a Rasbpian image file. In order to use it, 83 | you can download and unzip a recent Raspbian image on a Raspberry Pi, then do 84 | something like the following in a terminal: 85 | 86 | ```sh 87 | curl -SLs https://apt.adafruit.com/add | sudo bash 88 | sudo apt-get install adafruit-pitft-helper 89 | sudo adafruit-pitft-chroot-install -t 28r -i ~/2015-02-16-raspbian-wheezy.img 90 | ``` 91 | 92 | ...where `-t` specifies the type of PiTFT just like the same option to 93 | `adafruit-pitft-helper`, and `-i` specifies the path to an image file. 94 | 95 | You can also use [`adafruit-pi-chroot`][pi-chroot] to run a `chroot`ed shell 96 | inside of a Raspbian ISO image. Like the install wrapper, this relies on 97 | `kpartx`. 98 | 99 | These are the scripts we use to produce the Easy Install images offered in 100 | Adafruit product documentation. They may be a bit rough around the edges. 101 | 102 | ## Older Versions 103 | 104 | For the version supporting Raspbian Wheezy, check out the `wheezy` branch 105 | on this repository. 106 | 107 | [o]: https://github.com/adafruit/Adafruit-Occidentalis 108 | [p]: https://github.com/adafruit/Adafruit-Pi-Finder 109 | [c]: https://github.com/adafruit/Adafruit-PiTFT-Helper/blob/master/adafruit-pitft-chroot-install 110 | [pi-chroot]: https://github.com/adafruit/Adafruit-PiTFT-Helper/blob/master/adafruit-pi-chroot 111 | -------------------------------------------------------------------------------- /adafruit-pi-chroot: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | function print_help() { 6 | echo "$0: get a chroot shell inside of a Raspbian ISO" 7 | echo "Usage: $0 target.img" 8 | echo " -h Print this help" 9 | echo " -i [target] Specify an ISO to chroot to (probably a Pi Foundation Raspbian)" 10 | exit 1 11 | } 12 | 13 | args=$(getopt -uo 'ht:i:' -- $*) 14 | [ $? != 0 ] && print_help 15 | set -- $args 16 | 17 | for i 18 | do 19 | case "$i" 20 | in 21 | -h) 22 | print_help 23 | ;; 24 | -i) 25 | target_image="$2" 26 | echo "Image = ${2}" 27 | shift 28 | shift 29 | ;; 30 | esac 31 | done 32 | 33 | if [[ $EUID -ne 0 ]]; then 34 | echo "$0 must be run as root. try: sudo $0" 35 | exit 1 36 | fi 37 | 38 | target_mnt="/media/raspbian-target" 39 | 40 | # assemble a mostly-legit filesystem by mounting / and /boot from the target 41 | # iso, plus /dev from the host pi (/dev/(u)random seems to be required by 42 | # recent versions of GPG): 43 | echo "Mounting $target_image on $target_mnt" 44 | kpartx -av $target_image 45 | mkdir -p $target_mnt 46 | mount /dev/dm-1 $target_mnt 47 | mount /dev/dm-0 $target_mnt/boot 48 | mkdir -p $target_mnt/dev 49 | mount --bind /dev $target_mnt/dev 50 | 51 | echo "Dropping you into Bash - image will be unmounted after exit" 52 | chroot $target_mnt sudo /bin/bash 53 | 54 | echo "Unmounting $target_image" 55 | umount $target_mnt/boot 56 | umount $target_mnt/dev 57 | umount $target_mnt 58 | kpartx -d $target_image 59 | -------------------------------------------------------------------------------- /adafruit-pitft-chroot-install: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | function print_help() { 4 | echo "Usage: $0 -t [pitfttype] -i target.img" 5 | echo " -h Print this help" 6 | echo " -t [type] Specify the type of PiTFT: '28r' (PID 1601) or '28c' (PID 1983) or '35r' or '22'" 7 | echo " -i [target] Specify an ISO to perform install on (a recent Pi Foundation Raspbian)" 8 | echo 9 | echo "You must specify a type of display." 10 | exit 1 11 | } 12 | 13 | args=$(getopt -uo 'ht:i:' -- $*) 14 | [ $? != 0 ] && print_help 15 | set -- $args 16 | 17 | for i 18 | do 19 | case "$i" 20 | in 21 | -h) 22 | print_help 23 | ;; 24 | -t) 25 | pitfttype="$2" 26 | echo "Type = ${2}" 27 | shift 28 | shift 29 | ;; 30 | -i) 31 | target_image="$2" 32 | echo "Image = ${2}" 33 | shift 34 | shift 35 | ;; 36 | esac 37 | done 38 | 39 | if [[ $EUID -ne 0 ]]; then 40 | echo "$0 must be run as root. try: sudo $0" 41 | exit 1 42 | fi 43 | 44 | if [ "${pitfttype}" != "28r" ] && [ "${pitfttype}" != "28c" ] && [ "${pitfttype}" != "35r" ] && [ "${pitfttype}" != "22" ] 45 | then 46 | echo "Type must be '28r' (2.8\" resistive, PID 1601) or '28c' (2.8\" capacitive, PID 1983) or '35r' (3.5\" Resistive) or '22' (2.2\" no touch)" 47 | print_help 48 | fi 49 | 50 | target_mnt="/media/raspbian-target" 51 | 52 | # assemble a mostly-legit filesystem by mounting / and /boot from the target 53 | # iso, plus /dev from the host pi (/dev/(u)random seems to be required by 54 | # recent versions of GPG): 55 | echo "Mounting $target_image on $target_mnt" 56 | kpartx -av $target_image 57 | mkdir -p $target_mnt 58 | mount /dev/dm-1 $target_mnt 59 | mount /dev/dm-0 $target_mnt/boot 60 | mkdir -p $target_mnt/dev 61 | mount --bind /dev $target_mnt/dev 62 | 63 | echo "Dropping you into Bash before install" 64 | chroot $target_mnt sudo /bin/bash 65 | 66 | echo "Adding apt.adafruit.com to sources.list" 67 | curl -SLs https://apt.adafruit.com/add | chroot $target_mnt /bin/bash 68 | 69 | # pin apt.adafruit.com origin for anything installed there: 70 | echo -e "Package: *\nPin: origin \"apt.adafruit.com\"\nPin-Priority: 1001" | chroot $target_mnt bash -c "cat > /etc/apt/preferences.d/adafruit" 71 | 72 | echo "Installing kernel and adafruit-pitft-helper" 73 | chroot $target_mnt sudo apt-get install raspberrypi-bootloader 74 | chroot $target_mnt sudo apt-get install adafruit-pitft-helper 75 | 76 | echo "Running adafruit-pitft-helper" 77 | chroot $target_mnt sudo adafruit-pitft-helper -t $pitfttype 78 | 79 | echo "Dropping you into Bash after install" 80 | chroot $target_mnt sudo /bin/bash 81 | 82 | echo "Unmounting $target_image" 83 | umount $target_mnt/boot 84 | umount $target_mnt/dev 85 | umount $target_mnt 86 | kpartx -d $target_image 87 | -------------------------------------------------------------------------------- /adafruit-pitft-helper: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | function print_version() { 6 | echo "Adafruit PiTFT Helper v0.8.0" 7 | exit 1 8 | } 9 | 10 | function print_help() { 11 | echo "Usage: $0 -t [pitfttype]" 12 | echo " -h Print this help" 13 | echo " -v Print version information" 14 | echo " -u [homedir] Specify path of primary user's home directory (defaults to /home/pi)" 15 | echo " -t [type] Specify the type of PiTFT: '28r' (PID 1601) or '28c' (PID 1983) or '35r' or '22'" 16 | echo 17 | echo "You must specify a type of display." 18 | exit 1 19 | } 20 | 21 | group=ADAFRUIT 22 | function info() { 23 | system="$1" 24 | group="${system}" 25 | shift 26 | FG="1;32m" 27 | BG="40m" 28 | echo -e "[\033[${FG}\033[${BG}${system}\033[0m] $*" 29 | } 30 | 31 | function bail() { 32 | FG="1;31m" 33 | BG="40m" 34 | echo -en "[\033[${FG}\033[${BG}${group}\033[0m] " 35 | if [ -z "$1" ]; then 36 | echo "Exiting due to error" 37 | else 38 | echo "Exiting due to error: $*" 39 | fi 40 | exit 1 41 | } 42 | 43 | function ask() { 44 | # http://djm.me/ask 45 | while true; do 46 | 47 | if [ "${2:-}" = "Y" ]; then 48 | prompt="Y/n" 49 | default=Y 50 | elif [ "${2:-}" = "N" ]; then 51 | prompt="y/N" 52 | default=N 53 | else 54 | prompt="y/n" 55 | default= 56 | fi 57 | 58 | # Ask the question 59 | read -p "$1 [$prompt] " REPLY 60 | 61 | # Default? 62 | if [ -z "$REPLY" ]; then 63 | REPLY=$default 64 | fi 65 | 66 | # Check if the reply is valid 67 | case "$REPLY" in 68 | Y*|y*) return 0 ;; 69 | N*|n*) return 1 ;; 70 | esac 71 | done 72 | } 73 | 74 | # update /boot/config.txt with appropriate values 75 | function update_configtxt() { 76 | 77 | if grep -q "adafruit-pitft-helper" "/boot/config.txt"; then 78 | echo "Already have an adafruit-pitft-helper section in /boot/config.txt." 79 | echo "Adding new section, but please run:" 80 | echo "sudo nano /boot/config.txt" 81 | echo "...and remove any duplicate sections." 82 | fi 83 | 84 | if [ "${pitfttype}" == "22" ]; then 85 | # formerly: options fbtft_device name=adafruit22a gpios=dc:25 rotate=270 frequency=32000000 86 | overlay="dtoverlay=pitft22,rotate=270,speed=32000000,fps=20" 87 | fi 88 | 89 | if [ "${pitfttype}" == "28r" ]; then 90 | overlay="dtoverlay=pitft28-resistive,rotate=90,speed=32000000,fps=20" 91 | fi 92 | 93 | if [ "${pitfttype}" == "28c" ]; then 94 | overlay="dtoverlay=pitft28c,rotate=90,speed=32000000,fps=20" 95 | fi 96 | 97 | if [ "${pitfttype}" == "35r" ]; then 98 | overlay="dtoverlay=pitft35-resistive,rotate=270,speed=25000000,fps=20" 99 | fi 100 | 101 | date=`date` 102 | 103 | cat >> /boot/config.txt < /etc/X11/xorg.conf.d/99-fbdev.conf < /etc/X11/xorg.conf.d/99-calibration.conf < /etc/X11/xorg.conf.d/99-calibration.conf < /etc/X11/xorg.conf.d/99-calibration.conf <> "${target_homedir}/.profile" < /etc/pointercal < /etc/pointercal < /etc/pointercal < /etc/udev/rules.d/95-stmpe.rules < /etc/udev/rules.d/95-ft6206.rules < /etc/rc.local </dev/tty0" 249 | 250 | exit 0 251 | EOF 252 | } 253 | 254 | function uninstall_console() { 255 | sed -i 's/rootwait fbcon=map:10 fbcon=font:VGA8x8/rootwait/g' "/boot/cmdline.txt" 256 | sed -i 's/BLANK_TIME=0/BLANK_TIME=10/g' "/etc/kbd/config" 257 | echo "Screen blanking time reset to 10 minutes" 258 | cat > /etc/rc.local <> /etc/modules 296 | fi 297 | } 298 | 299 | function install_onoffbutton() { 300 | echo "Adding rpi_power_switch to /etc/modules" 301 | if grep -xq "rpi_power_switch" "${chr}/etc/modules"; then 302 | echo "Already had rpi_power_switch" 303 | else 304 | echo "Adding rpi_power_switch" 305 | cat >> /etc/modules <> /etc/modprobe.d/adafruit.conf <\/dev\/tty1 2>&1/1:2345:respawn:\/sbin\/getty --noclear 38400 tty1/" 330 | fi 331 | fi 332 | } 333 | 334 | # MAIN 335 | 336 | target_homedir="/home/pi" 337 | 338 | args=$(getopt -uo 'hvri:t:o:b:u:' -- $*) 339 | [ $? != 0 ] && print_help 340 | set -- $args 341 | 342 | for i 343 | do 344 | case "$i" 345 | in 346 | -h) 347 | print_help 348 | ;; 349 | -v) 350 | print_version 351 | ;; 352 | -u) 353 | target_homedir="$2" 354 | echo "Homedir = ${2}" 355 | shift 356 | shift 357 | ;; 358 | -t) 359 | pitfttype="$2" 360 | echo "Type = ${2}" 361 | shift 362 | shift 363 | ;; 364 | esac 365 | done 366 | 367 | if [[ $EUID -ne 0 ]]; then 368 | bail "adafruit-pitft-helper must be run as root. try: sudo adadfruit-pitft-helper" 369 | fi 370 | 371 | # check init system (technique borrowed from raspi-config): 372 | info PITFT 'Checking init system...' 373 | if command -v systemctl > /dev/null && systemctl | grep -q '\-\.mount'; then 374 | echo "Found systemd" 375 | SYSTEMD=1 376 | elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then 377 | echo "Found sysvinit" 378 | SYSTEMD=0 379 | else 380 | bail "Unrecognised init system" 381 | fi 382 | 383 | if grep -q boot /proc/mounts; then 384 | echo "/boot is mounted" 385 | else 386 | echo "/boot must be mounted. if you think it's not, quit here and try: sudo mount /dev/mmcblk0p1 /boot" 387 | if ask "Continue?"; then 388 | echo "Proceeding." 389 | else 390 | bail "Aborting." 391 | fi 392 | fi 393 | 394 | if [[ ! -e "$target_homedir" || ! -d "$target_homedir" ]]; then 395 | bail "$target_homedir must be an existing directory (use -u /home/foo to specify)" 396 | fi 397 | 398 | if [ "${pitfttype}" != "28r" ] && [ "${pitfttype}" != "28c" ] && [ "${pitfttype}" != "35r" ] && [ "${pitfttype}" != "22" ]; then 399 | echo "Type must be one of:" 400 | echo " '28r' (2.8\" resistive, PID 1601)" 401 | echo " '28c' (2.8\" capacitive, PID 1983)" 402 | echo " '35r' (3.5\" Resistive)" 403 | echo " '22' (2.2\" no touch)" 404 | echo 405 | print_help 406 | fi 407 | 408 | info PITFT "Updating X11 default calibration..." 409 | update_xorg || bail "Unable to update /etc/X11/xorg.conf.d/99-calibration.conf" 410 | 411 | info PITFT "Updating X11 setup tweaks..." 412 | update_x11profile || bail "Unable to update X11 setup" 413 | 414 | info PITFT "Updating TSLib default calibration..." 415 | update_pointercal || bail "Unable to update /etc/pointercal" 416 | 417 | info PITFT "Updating SysFS rules for Touchscreen..." 418 | update_udev || bail "Unable to update /etc/udev/rules.d" 419 | 420 | # ask for console access 421 | if ask "Would you like the console to appear on the PiTFT display?"; then 422 | info PITFT "Updating console to PiTFT..." 423 | install_console || bail "Unable to configure console" 424 | else 425 | info PITFT "Making sure console doesn't use PiTFT" 426 | uninstall_console || bail "Unable to configure console" 427 | fi 428 | 429 | info PITFT "Updating /etc/modules..." 430 | update_etcmodules || bail "Unable to update /etc/modules" 431 | 432 | if [ "${pitfttype}" != "35r" ]; then 433 | # ask for 'on/off' button 434 | if ask "Would you like GPIO #23 to act as a on/off button?"; then 435 | info PITFT "Adding GPIO #23 on/off to PiTFT..." 436 | install_onoffbutton || bail "Unable to add on/off button" 437 | fi 438 | fi 439 | 440 | # update_bootprefs || bail "Unable to set boot preferences" 441 | 442 | info PITFT "Updating /boot/config.txt..." 443 | update_configtxt || bail "Unable to update /boot/config.txt" 444 | 445 | info PITFT "Success!" 446 | info PITFT "Notes:" 447 | echo "Please don't run rpi-update, or you'll have to re-install a kernel" 448 | echo "with PiTFT support. For more info, see:" 449 | echo "https://learn.adafruit.com/adafruit-pitft-28-inch-resistive-touchscreen-display-raspberry-pi/faq" 450 | -------------------------------------------------------------------------------- /adafruit-pitft-helper2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "This script has been updated and now lives at https://github.com/adafruit/Raspberry-Pi-Installer-Scripts/blob/master/adafruit-pitft.sh" 4 | echo "please run:" 5 | echo "-----------" 6 | echo "# wget https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/adafruit-pitft.sh" 7 | echo "# chmod +x adafruit-pitft.sh" 8 | echo "# sudo ./adafruit-pitft.sh" -------------------------------------------------------------------------------- /adafruit-pitft-touch-cal: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Script to automatically update Raspberry Pi PiTFT touchscreen calibration 4 | # based on the current rotation of the screen. 5 | 6 | # Copyright (c) 2014 Adafruit Industries 7 | # Author: Tony DiCola 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | import argparse 27 | import os 28 | import subprocess 29 | import sys 30 | 31 | 32 | # Calibration configuration default values. 33 | CAL_CONFIG = {} 34 | 35 | # 2.8" resisitive touch calibration values. 36 | CAL_CONFIG['28r'] = {} 37 | CAL_CONFIG['28r']['pointercal'] = {} 38 | CAL_CONFIG['28r']['pointercal']['0'] = '4315 -49 -889068 18 5873 -1043172 6553636' 39 | CAL_CONFIG['28r']['pointercal']['90'] = '-30 -5902 22077792 4360 -105 -1038814 65536' 40 | CAL_CONFIG['28r']['pointercal']['180'] = '-4228 73 16353030 -60 -5888 22004262 65536' 41 | CAL_CONFIG['28r']['pointercal']['270'] = '-69 5859 -829540 -4306 3 16564590 6553636' 42 | CAL_CONFIG['28r']['xorg'] = {} 43 | CAL_CONFIG['28r']['xorg']['0'] = """ 44 | Section "InputClass" 45 | Identifier "calibration" 46 | MatchProduct "stmpe-ts" 47 | Option "Calibration" "252 3861 180 3745" 48 | Option "SwapAxes" "0" 49 | EndSection 50 | """ 51 | CAL_CONFIG['28r']['xorg']['90'] = """ 52 | Section "InputClass" 53 | Identifier "calibration" 54 | MatchProduct "stmpe-ts" 55 | Option "Calibration" "3807 174 244 3872" 56 | Option "SwapAxes" "1" 57 | EndSection 58 | """ 59 | CAL_CONFIG['28r']['xorg']['180'] = """ 60 | Section "InputClass" 61 | Identifier "calibration" 62 | MatchProduct "stmpe-ts" 63 | Option "Calibration" "3868 264 3789 237" 64 | Option "SwapAxes" "0" 65 | EndSection 66 | """ 67 | CAL_CONFIG['28r']['xorg']['270'] = """ 68 | Section "InputClass" 69 | Identifier "calibration" 70 | MatchProduct "stmpe-ts" 71 | Option "Calibration" "287 3739 3817 207" 72 | Option "SwapAxes" "1" 73 | EndSection 74 | """ 75 | 76 | # 2.8" capacitive touch calibration values. 77 | CAL_CONFIG['28c'] = {} 78 | CAL_CONFIG['28c']['pointercal'] = {} 79 | CAL_CONFIG['28c']['pointercal']['0'] = '-65536 0 15728640 -320 -65536 20971520 65536' 80 | CAL_CONFIG['28c']['pointercal']['90'] = '320 65536 0 -65536 0 15728640 65536' 81 | CAL_CONFIG['28c']['pointercal']['180'] = '65536 0 -655360 0 65536 -655360 65536' 82 | CAL_CONFIG['28c']['pointercal']['270'] = '0 -65536 20971520 65536 0 -65536 65536' 83 | CAL_CONFIG['28c']['xorg'] = {} 84 | CAL_CONFIG['28c']['xorg']['0'] = """ 85 | Section "InputClass" 86 | Identifier "captouch" 87 | MatchProduct "ft6x06_ts" 88 | Option "SwapAxes" "0" 89 | Option "InvertY" "1" 90 | Option "InvertX" "1" 91 | Option "Calibration" "0 240 0 320" 92 | EndSection 93 | """ 94 | CAL_CONFIG['28c']['xorg']['90'] = """ 95 | Section "InputClass" 96 | Identifier "captouch" 97 | MatchProduct "ft6x06_ts" 98 | Option "SwapAxes" "1" 99 | Option "InvertY" "1" 100 | Option "Calibration" "0 320 0 240" 101 | EndSection 102 | """ 103 | CAL_CONFIG['28c']['xorg']['180'] = """ 104 | Section "InputClass" 105 | Identifier "captouch" 106 | MatchProduct "ft6x06_ts" 107 | Option "SwapAxes" "0" 108 | Option "InvertY" "0" 109 | Option "Calibration" "0 240 0 320" 110 | EndSection 111 | """ 112 | CAL_CONFIG['28c']['xorg']['270'] = """ 113 | Section "InputClass" 114 | Identifier "captouch" 115 | MatchProduct "ft6x06_ts" 116 | Option "SwapAxes" "1" 117 | Option "InvertY" "0" 118 | Option "InvertX" "1" 119 | Option "Calibration" "0 320 0 240" 120 | EndSection 121 | """ 122 | 123 | # 3.5" resisitive touch calibration values. 124 | CAL_CONFIG['35r'] = {} 125 | CAL_CONFIG['35r']['pointercal'] = {} 126 | CAL_CONFIG['35r']['pointercal']['0'] = '5835 56 -1810410 22 8426 -1062652 65536' 127 | CAL_CONFIG['35r']['pointercal']['90'] = '-16 -8501 33169914 5735 45 -1425640 65536' 128 | CAL_CONFIG['35r']['pointercal']['180'] = '-5853 8 22390770 -59 -8353 32810368 65536' 129 | CAL_CONFIG['35r']['pointercal']['270'] = '-95 8395 -908648 -5849 164 22156762 65536' 130 | CAL_CONFIG['35r']['xorg'] = {} 131 | CAL_CONFIG['35r']['xorg']['0'] = """ 132 | Section "InputClass" 133 | Identifier "calibration" 134 | MatchProduct "stmpe-ts" 135 | Option "Calibration" "291 3847 141 3889" 136 | Option "SwapAxes" "0" 137 | EndSection 138 | """ 139 | CAL_CONFIG['35r']['xorg']['90'] = """ 140 | Section "InputClass" 141 | Identifier "calibration" 142 | MatchProduct "stmpe-ts" 143 | Option "Calibration" "150 3912 3843 255" 144 | Option "SwapAxes" "1" 145 | Option "InvertX" "1" 146 | Option "InvertY" "1" 147 | EndSection 148 | """ 149 | CAL_CONFIG['35r']['xorg']['180'] = """ 150 | Section "InputClass" 151 | Identifier "calibration" 152 | MatchProduct "stmpe-ts" 153 | Option "Calibration" "291 3847 141 3889" 154 | Option "SwapAxes" "0" 155 | Option "InvertX" "1" 156 | Option "InvertY" "1" 157 | EndSection 158 | """ 159 | CAL_CONFIG['35r']['xorg']['270'] = """ 160 | Section "InputClass" 161 | Identifier "calibration" 162 | MatchProduct "stmpe-ts" 163 | Option "Calibration" "150 3912 3843 255" 164 | Option "SwapAxes" "1" 165 | Option "InvertX" "0" 166 | Option "InvertY" "0" 167 | EndSection 168 | """ 169 | 170 | # Other configuration. 171 | POINTERCAL_FILE = '/etc/pointercal' 172 | XORGCAL_FILE = '/etc/X11/xorg.conf.d/99-calibration.conf' 173 | ALLOWED_TYPES = CAL_CONFIG.keys() 174 | ALLOWED_ROTATIONS = ['0', '90', '180', '270'] 175 | 176 | 177 | def read_file(filename): 178 | """Read specified file contents and return them, or None if file isn't 179 | readable. 180 | """ 181 | try: 182 | with open(filename, 'r') as infile: 183 | return infile.read() 184 | except IOError: 185 | return None 186 | 187 | def write_file(filename, data): 188 | """Write specified data to file. Returns True if data was written.""" 189 | try: 190 | # Check if path to file exists. Create path if necessary. 191 | directory = os.path.dirname(filename) 192 | if not os.path.exists(directory): 193 | os.makedirs(directory) 194 | # Open file and write data. 195 | with open(filename, 'w') as outfile: 196 | outfile.write(data) 197 | return True 198 | except IOError, OSError: 199 | return False 200 | 201 | def determine_rotation(): 202 | """Determine the rotation of the PiTFT screen by examining 203 | /sys/class/graphics/fb1/rotate config. 204 | """ 205 | return read_file('/sys/class/graphics/fb1/rotate') 206 | 207 | def determine_type(): 208 | """Determine the type of display by examining loaded kernel modules. 209 | """ 210 | # Call lsmod to list kernel modules. 211 | output = subprocess.check_output('lsmod') 212 | # Parse out module names from lsmod response (grab first word of each line 213 | # after the first line). 214 | modules = map(lambda x: x.split()[0], output.splitlines()[1:]) 215 | # Check for display type based on loaded modules. 216 | if 'stmpe_ts' in modules and 'fb_ili9340' in modules: 217 | return '28r' 218 | elif 'ft6x06_ts' in modules and 'fb_ili9340' in modules: 219 | return '28c' 220 | elif 'stmpe_ts' in modules and 'fb_hx8357d' in modules: 221 | return '35r' 222 | else: 223 | return None 224 | 225 | 226 | # Parse command line arguments. 227 | parser = argparse.ArgumentParser(description='Automatically set the PiTFT touchscreen calibration for both /etc/pointercal and X.Org based on the current screen rotation.') 228 | parser.add_argument('-t', '--type', 229 | choices=ALLOWED_TYPES, 230 | required=False, 231 | dest='type', 232 | help='set display type') 233 | parser.add_argument('-r', '--rotation', 234 | choices=ALLOWED_ROTATIONS, 235 | required=False, 236 | dest='rotation', 237 | help='set calibration for specified screen rotation') 238 | parser.add_argument('-f', '--force', 239 | required=False, 240 | action='store_const', 241 | const=True, 242 | default=False, 243 | dest='force', 244 | help='update calibration without prompting for confirmation') 245 | args = parser.parse_args() 246 | 247 | # Check that you're running as root. 248 | if os.geteuid() != 0: 249 | print 'Must be run as root so calibration files can be updated!' 250 | print 'Try running with sudo, for example: sudo ./pitft_touch_cal.py' 251 | sys.exit(1) 252 | 253 | # Determine display type if not specified in parameters. 254 | display_type = args.type 255 | if display_type is None: 256 | display_type = determine_type() 257 | if display_type is None: 258 | print 'Could not detect display type!' 259 | print '' 260 | print 'Make sure PiTFT software is configured and run again.' 261 | print 'Alternatively, run with the --type parameter to' 262 | print 'specify an explicit display type value.' 263 | print '' 264 | parser.print_help() 265 | sys.exit(1) 266 | 267 | # Check display type is allowed value. 268 | if display_type not in ALLOWED_TYPES: 269 | print 'Unsupported display type: {0}'.format(display_type) 270 | parser.print_help() 271 | sys.exit(1) 272 | 273 | # Determine rotation if not specified in parameters. 274 | rotation = args.rotation 275 | if rotation is None: 276 | rotation = determine_rotation() 277 | if rotation is None: 278 | # Error if rotation couldn't be determined. 279 | print 'Could not detect screen rotation!' 280 | print '' 281 | print 'Make sure PiTFT software is configured and run again.' 282 | print 'Alternatively, run with the --rotation parameter to' 283 | print 'specify an explicit rotation value.' 284 | print '' 285 | parser.print_help() 286 | sys.exit(1) 287 | 288 | # Check rotation is allowed value. 289 | rotation = rotation.strip() 290 | if rotation not in ALLOWED_ROTATIONS: 291 | print 'Unsupported rotation value: {0}'.format(rotation) 292 | parser.print_help() 293 | sys.exit(1) 294 | 295 | print '---------------------------------' 296 | print 'USING DISPLAY: {0}'.format(display_type) 297 | print '' 298 | print '---------------------------------' 299 | print 'USING ROTATION: {0}'.format(rotation) 300 | print '' 301 | 302 | # Print current calibration values. 303 | print '---------------------------------' 304 | print 'CURRENT CONFIGURATION' 305 | print '' 306 | for cal_file in [POINTERCAL_FILE, XORGCAL_FILE]: 307 | cal = read_file(cal_file) 308 | if cal is None: 309 | print 'Could not determine {0} configuration.'.format(cal_file) 310 | else: 311 | print 'Current {0} configuration:'.format(cal_file) 312 | print cal.strip() 313 | print '' 314 | 315 | # Determine new calibration values. 316 | new_pointercal = CAL_CONFIG[display_type]['pointercal'][rotation] 317 | new_xorgcal = CAL_CONFIG[display_type]['xorg'][rotation] 318 | 319 | # Print new calibration values. 320 | print '---------------------------------' 321 | print 'NEW CONFIGURATION' 322 | print '' 323 | for cal, filename in [(new_pointercal, POINTERCAL_FILE), 324 | (new_xorgcal, XORGCAL_FILE)]: 325 | print 'New {0} configuration:'.format(filename) 326 | print cal.strip() 327 | print '' 328 | 329 | # Confirm calibration change with user. 330 | if not args.force: 331 | confirm = raw_input('Update current configuration to new configuration? [y/N]: ') 332 | print '---------------------------------' 333 | print '' 334 | if confirm.lower() not in ['y', 'yes']: 335 | print 'Exiting without updating configuration.' 336 | sys.exit(0) 337 | 338 | # Change calibration. 339 | status = 0 340 | for cal, filename in [(new_pointercal, POINTERCAL_FILE), 341 | (new_xorgcal, XORGCAL_FILE)]: 342 | if not write_file(filename, cal): 343 | print 'Failed to update {0}'.format(filename) 344 | status = 1 345 | else: 346 | print 'Updated {0}'.format(filename) 347 | sys.exit(status) 348 | --------------------------------------------------------------------------------