From e93e87474883e6cfac374cf7d1878a6e47b46ad2 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Sun, 12 Apr 2020 13:10:49 +0200 Subject: [PATCH] =?UTF-8?q?Initial:=20=C3=9Cbertrag=20der=20Tools/Scripte?= =?UTF-8?q?=20aus=20SVN?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- imgFileUrlList.txt | 6 + readme.txt | 23 + script/googledl.sh | 15 + script/googliser.sh | 2110 ++++++++++++++++++++++++++++++++++++++++ script/master.sh | 5 + script/wetterbilder.sh | 35 + src/RAIO8870.c | 342 +++++++ src/RAIO8870.h | 337 +++++++ src/ST7789.c | 194 ++++ src/ST7789.h | 187 ++++ src/bildercycle.c | 147 +++ src/bildercycle.h | 0 src/bmp.c | 206 ++++ src/bmp.h | 70 ++ src/examples.c | 71 ++ src/examples.h | 59 ++ src/makefile | 20 + src/tft.c | 193 ++++ src/tft.h | 111 +++ src/tft_string.c | 98 ++ src/tft_test.c | 86 ++ 21 files changed, 4315 insertions(+) create mode 100644 imgFileUrlList.txt create mode 100644 readme.txt create mode 100644 script/googledl.sh create mode 100644 script/googliser.sh create mode 100644 script/master.sh create mode 100644 script/wetterbilder.sh create mode 100644 src/RAIO8870.c create mode 100644 src/RAIO8870.h create mode 100644 src/ST7789.c create mode 100644 src/ST7789.h create mode 100644 src/bildercycle.c create mode 100644 src/bildercycle.h create mode 100644 src/bmp.c create mode 100644 src/bmp.h create mode 100644 src/examples.c create mode 100644 src/examples.h create mode 100644 src/makefile create mode 100644 src/tft.c create mode 100644 src/tft.h create mode 100644 src/tft_string.c create mode 100644 src/tft_test.c diff --git a/imgFileUrlList.txt b/imgFileUrlList.txt new file mode 100644 index 0000000..6132ce3 --- /dev/null +++ b/imgFileUrlList.txt @@ -0,0 +1,6 @@ +https://www.dwd.de/DWD/warnungen/warnapp_gemeinden/json/warnungen_gemeinde_map_baw.png +https://www.dwd.de/DWD/wetter/aktuell/deutschland/bilder/wx_baw_akt.jpg +https://www.dwd.de/DWD/wetter/aktuell/deutschland/bilder/wx_shh_akt.jpg +https://www.dwd.de/DWD/wetter/aktuell/deutschland/bilder/wx_brd_akt.jpg +https://www.dwd.de/DWD/warnungen/warnapp_gemeinden/json/warnungen_gemeinde_map_de.png +https://www.dwd.de/DWD/wetter/radar/rad_baw_akt.jpg \ No newline at end of file diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..18a793a --- /dev/null +++ b/readme.txt @@ -0,0 +1,23 @@ +Erster Idee: + +Wir zeigen lediglich an BMP's aus einem Verzeichnis an, die bereits passend vorbereitet sind (hochkant gedreht, 240x320, 24bpp). +Diese werden "durchgeschaltet", irgendwann vielleicht auch mal gedreht. +CTRL-C / Beenden sollte abgefangen werden, damit das Display wieder zurückgesetzt werden kann (dunkel). + +Datenquelle: Wetter Service URL's des DWD: +Warnkarte BW: +https://www.dwd.de/DWD/warnungen/warnapp_gemeinden/json/warnungen_gemeinde_map_baw.png +https://www.dwd.de/DWD/wetter/aktuell/deutschland/bilder/wx_baw_akt.jpg +https://www.dwd.de/DWD/wetter/aktuell/deutschland/bilder/wx_shh_akt.jpg +https://www.dwd.de/DWD/wetter/aktuell/deutschland/bilder/wx_brd_akt.jpg +https://www.dwd.de/DWD/warnungen/warnapp_gemeinden/json/warnungen_gemeinde_map_de.png +https://www.dwd.de/DWD/wetter/radar/rad_baw_akt.jpg + +Weitere Hirngespinste: +- Fading / Übergangseffekt +- Wetteranzeige als Textdarstellung (selbst gezeichnet) +- andere Informationen (S-Bahn, RSS,..) + +Zweite (auch umgesetzte Idee): +- Anzeige zufälliger Google Bilder. Das geht gut mit dem googlizer, einem passenden bash Script und +dem ebenfalls sehr mächtigen convert Tool von ImageMagick \ No newline at end of file diff --git a/script/googledl.sh b/script/googledl.sh new file mode 100644 index 0000000..101f571 --- /dev/null +++ b/script/googledl.sh @@ -0,0 +1,15 @@ +#! /bin/bash +OUTDIR="/home/pi/StatusBerry/img/" +DLDIR="/home/pi/StatusBerry/download/" +query=$(shuf -n1 /usr/share/dict/words) +rm -f $OUTDIR/* +rm -f $DLDIR/* +/home/pi/StatusBerry/script/googliser.sh -p $query -a tall -u 80000 -n 20 --no-gallery --output $DLDIR +for FILENAME in $DLDIR*; do + # BASEFILENAME="${FILENAME%.*}" + BASEFILENAME=$(basename "$FILENAME" | cut -d. -f1) + # image resize, rotate, draw text und so weiter :) + # CBerry ist etwas empfindlich was die BMP Parameter angeht! (exakte Größe, BMP3, 24bit) + # echo $BASEFILENAME + convert $FILENAME -resize 240x320! -gravity NorthEast -pointsize 18 -draw "text 0,4 '$query'" -rotate 90 -depth 24 -compress None -type truecolor -units PixelsPerInch -density 72 "BMP3:$OUTDIR$BASEFILENAME.bmp" +done \ No newline at end of file diff --git a/script/googliser.sh b/script/googliser.sh new file mode 100644 index 0000000..b4c344b --- /dev/null +++ b/script/googliser.sh @@ -0,0 +1,2110 @@ +#!/usr/bin/env bash + +############################################################################### +# googliser.sh +# +# (C)opyright 2016-2017 Teracow Software +# +# If you find this script useful, please send me an email to let me know. :) +# teracow@gmail.com +# +# The latest copy can be found here [https://github.com/teracow/googliser] +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see http://www.gnu.org/licenses/. +############################################################################### + +# return values ($?): +# 0 completed successfully +# 1 required program unavailable (wget, montage, convert) +# 2 required parameter unspecified or wrong +# 3 could not create output directory for 'phrase' +# 4 could not get a list of search results from Google +# 5 image download aborted as failure limit was reached or ran out of images +# 6 thumbnail gallery build failed +# 7 unable to create a temporary build directory + +# debug log first character notation: +# > script entry +# < script exit +# \ function entry +# / function exit +# ? variable value +# = evaluation +# ~ variable had boundary issues so was set within bounds +# $ success +# ! failure +# T elapsed time + +case "$OSTYPE" in + "darwin"*) + CMD_READLINK='greadlink' + CMD_HEAD='ghead' + CMD_SED='gsed' + CMD_DU='gdu' + CMD_LS='gls' + ;; + *) + CMD_READLINK='readlink' + CMD_HEAD='head' + CMD_SED='sed' + CMD_DU='du' + CMD_LS='ls' + ;; +esac + +user_parameters=$(getopt -o h,N,D,s,q,c,C,S,z,L,T:,a:,i:,l:,u:,m:,r:,t:,P:,f:,n:,p:,o: -l help,no-gallery,condensed,debug,delete-after,save-links,quiet,colour,skip-no-size,lightning,links-only,title:,input:,lower-size:,upper-size:,retries:,timeout:,parallel:,failures:,number:,phrase:,minimum-pixels:,aspect-ratio:,type:,output:,dimensions: -n $($CMD_READLINK -f -- "$0") -- "$@") +user_parameters_result=$? +user_parameters_raw="$@" + +Init() + { + + local script_date='2017-12-17' + script_file='googliser.sh' + script_name="${script_file%.*}" + local script_details_colour="$(ColourTextBrightWhite "$script_file") - $script_date PID:[$$]" + local script_details_plain="$script_file - $script_date PID:[$$]" + + # parameter defaults + images_required_default=25 + parallel_limit_default=10 + fail_limit_default=40 + upper_size_limit_default=0 + lower_size_limit_default=1000 + timeout_default=8 + retries_default=3 + max_results_required=$images_required_default + fail_limit=$fail_limit_default + + # limits + google_max=1000 + parallel_max=40 + timeout_max=600 + retries_max=100 + + # internals + local script_starttime=$(date) + script_startseconds=$(date +%s) + server='www.google.com' + useragent='Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0' + target_path_created=false + show_help_only=false + exitcode=0 + + # user changable parameters + user_query='' + images_required=$images_required_default + user_fail_limit=$fail_limit + parallel_limit=$parallel_limit_default + timeout=$timeout_default + retries=$retries_default + upper_size_limit=$upper_size_limit_default + lower_size_limit=$lower_size_limit_default + create_gallery=true + gallery_title='' + condensed_gallery=false + save_links=false + colour=false + verbose=true + debug=false + skip_no_size=false + remove_after=false + lightning=false + min_pixels='' + aspect_ratio='' + image_type='' + input_pathfile='' + output_path='' + links_only=false + dimensions='' + + BuildWorkPaths + WhatAreMyOptions + + DebugThis '> started' "$script_starttime" + DebugThis '? $script_details' "$script_details_plain" + DebugThis '? $user_parameters_raw' "$user_parameters_raw" + + if [[ $verbose = true ]]; then + if [[ $colour = true ]]; then + echo " $script_details_colour" + else + echo " $script_details_plain" + fi + fi + + if [[ $show_help_only = true ]]; then + DisplayHelp + return 1 + else + ValidateParameters + fi + + DebugThis '= environment' '*** parameters after validation and adjustment ***' + DebugThis '? $user_query' "$user_query" + DebugThis '? $images_required' "$images_required" + DebugThis '? $fail_limit' "$fail_limit" + DebugThis '? $parallel_limit' "$parallel_limit" + DebugThis '? $timeout' "$timeout" + DebugThis '? $retries' "$retries" + DebugThis '? $upper_size_limit' "$upper_size_limit" + DebugThis '? $lower_size_limit' "$lower_size_limit" + DebugThis '? $create_gallery' "$create_gallery" + DebugThis '? $gallery_title' "$gallery_title" + DebugThis '? $condensed_gallery' "$condensed_gallery" + DebugThis '? $save_links' "$save_links" + DebugThis '? $colour' "$colour" + DebugThis '? $verbose' "$verbose" + DebugThis '? $debug' "$debug" + DebugThis '? $skip_no_size' "$skip_no_size" + DebugThis '? $remove_after' "$remove_after" + DebugThis '? $lightning' "$lightning" + DebugThis '? $min_pixels' "$min_pixels" + DebugThis '? $aspect_ratio' "$aspect_ratio" + DebugThis '? $image_type' "$image_type" + DebugThis '? $input_pathfile' "$input_pathfile" + DebugThis '? $output_path' "$output_path" + DebugThis '? $links_only' "$links_only" + DebugThis '? $dimensions' "$dimensions" + DebugThis '= environment' '*** internal parameters ***' + DebugThis '? $google_max' "$google_max" + DebugThis '? $temp_path' "$temp_path" + + IsReqProgAvail 'wget' || { exitcode=1; return 1 ;} + + if [[ $create_gallery = true ]] && [[ $show_help_only = false ]]; then + IsReqProgAvail 'montage' || { exitcode=1; return 1 ;} + IsReqProgAvail 'convert' || { exitcode=1; return 1 ;} + fi + + IsOptProgAvail 'identify' && ident=true || ident=false + + trap CTRL_C_Captured INT + + return 0 + + } + +BuildWorkPaths() + { + + Flee() + { + + echo "! Unable to create a temporary build directory! Exiting."; exit 7 + + } + + image_file_prefix='google-image' + test_file='test-image' # this is used during size testing + imagelinks_file='download.links.list' + debug_file='debug.log' + gallery_name='googliser-gallery' + current_path="$PWD" + + temp_path=$(mktemp -d "/tmp/${script_name}.$$.XXX") || Flee + + results_run_count_path="${temp_path}/results.running.count" + mkdir -p "$results_run_count_path" || Flee + + results_success_count_path="${temp_path}/results.success.count" + mkdir -p "$results_success_count_path" || Flee + + results_fail_count_path="${temp_path}/results.fail.count" + mkdir -p "$results_fail_count_path" || Flee + + download_run_count_path="${temp_path}/download.running.count" + mkdir -p "$download_run_count_path" || Flee + + download_success_count_path="${temp_path}/download.success.count" + mkdir -p "$download_success_count_path" || Flee + + download_fail_count_path="${temp_path}/download.fail.count" + mkdir -p "$download_fail_count_path" || Flee + + testimage_pathfile="${temp_path}/${test_file}" + results_pathfile="${temp_path}/results.page.html" + gallery_title_pathfile="${temp_path}/gallery.title.png" + gallery_thumbnails_pathfile="${temp_path}/gallery.thumbnails.png" + gallery_background_pathfile="${temp_path}/gallery.background.png" + imagelinks_pathfile="${temp_path}/${imagelinks_file}" + debug_pathfile="${temp_path}/${debug_file}" + + unset -f Flee + + } + +WhatAreMyOptions() + { + + [[ $user_parameters_result -ne 0 ]] && { echo; exitcode=2; return 1 ;} + [[ $user_parameters = ' --' ]] && { show_help_only=true; exitcode=2; return 1 ;} + + eval set -- "$user_parameters" + + while true; do + case "$1" in + -n|--number) + images_required="$2" + shift 2 + ;; + -f|--failures) + user_fail_limit="$2" + shift 2 + ;; + -p|--phrase) + user_query="$2" + shift 2 + ;; + -P|--parallel) + parallel_limit="$2" + shift 2 + ;; + -t|--timeout) + timeout="$2" + shift 2 + ;; + -r|--retries) + retries="$2" + shift 2 + ;; + -u|--upper-size) + upper_size_limit="$2" + shift 2 + ;; + -l|--lower-size) + lower_size_limit="$2" + shift 2 + ;; + -T|--title) + gallery_title="$2" + shift 2 + ;; + -o|--output) + output_path="$2" + shift 2 + ;; + -i|--input) + input_pathfile="$2" + shift 2 + ;; + #--dimensions) + # dimensions="$2" + # shift 2 + # ;; + -S|--skip-no-size) + skip_no_size=true + shift + ;; + -s|--save-links) + save_links=true + shift + ;; + -D|--delete-after) + remove_after=true + shift + ;; + -z|--lightning) + lightning=true + shift + ;; + -h|--help) + show_help_only=true + exitcode=2 + return 1 + ;; + -c|--colour) + colour=true + shift + ;; + -N|--no-gallery) + create_gallery=false + shift + ;; + -C|--condensed) + condensed_gallery=true + shift + ;; + -q|--quiet) + verbose=false + shift + ;; + --debug) + debug=true + shift + ;; + -L|--links-only) + links_only=true + shift + ;; + -m|--minimum-pixels) + min_pixels="$2" + shift 2 + ;; + -a|--aspect-ratio) + aspect_ratio="$2" + shift 2 + ;; + --type) + image_type="$2" + shift 2 + ;; + --) + shift # shift to next parameter in $1 + break + ;; + *) + break # there are no more matching parameters + ;; + esac + done + + return 0 + + } + +DisplayHelp() + { + + DebugThis "\ [${FUNCNAME[0]}]" 'entry' + + local sample_user_query='cows' + + echo + if [[ $colour = true ]]; then + echo " Usage: $(ColourTextBrightWhite "./$script_file") [PARAMETERS] ..." + message="$(ShowGoogle) $(ColourTextBrightBlue "images")" + else + echo " Usage: ./$script_file [PARAMETERS] ..." + message='Google images' + fi + + echo + echo " search '$message', download from each of the image URLs, then create a gallery image using ImageMagick." + echo + echo " External requirements: Wget" + echo " and optionally: identify, montage & convert (from ImageMagick)" + echo + echo " Questions or comments? teracow@gmail.com" + echo + echo " Mandatory arguments for long options are mandatory for short options too. Defaults values are shown in [ ]" + echo + + if [[ $colour = true ]]; then + echo " $(ColourTextBrightOrange "* Required *")" + else + echo " * Required *" + fi + + HelpParameterFormat "p" "phrase" "Phrase to search for. Enclose whitespace in quotes. A sub-directory is created with this name unless '--output' is specified." + echo + echo " Optional" + HelpParameterFormat "a" "aspect-ratio" "Image aspect ratio. Specify like '-a square'. Presets are:" + HelpParameterFormat "" "" "'tall'" + HelpParameterFormat "" "" "'square'" + HelpParameterFormat "" "" "'wide'" + HelpParameterFormat "" "" "'panoramic'" + HelpParameterFormat "c" "colour" "Display with ANSI coloured text." + HelpParameterFormat "C" "condensed" "Create a condensed thumbnail gallery. All square images with no tile padding." + HelpParameterFormat "" "debug" "Save the debug file [$debug_file] into the output directory." + #HelpParameterFormat "d" "dimensions" "Specify exact image dimensions to download." + HelpParameterFormat "D" "delete-after" "Remove all downloaded images afterwards." + HelpParameterFormat "f" "failures" "Total number of download failures allowed before aborting. [$fail_limit_default] Use 0 for unlimited ($google_max)." + HelpParameterFormat "h" "help" "Display this help then exit." + HelpParameterFormat "i" "input" "A text file containing a list of phrases to download. One phrase per line." + HelpParameterFormat "l" "lower-size" "Only download images that are larger than this many bytes. [$lower_size_limit_default]" + HelpParameterFormat "L" "links-only" "Only get image file URLs. Don't download any images." + HelpParameterFormat "m" "minimum-pixels" "Images must contain at least this many pixels. Specify like '-m 8mp'. Presets are:" + HelpParameterFormat "" "" "'qsvga' (400 x 300)" + HelpParameterFormat "" "" "'vga' (640 x 480)" + HelpParameterFormat "" "" "'svga' (800 x 600)" + HelpParameterFormat "" "" "'xga' (1024 x 768)" + HelpParameterFormat "" "" "'2mp' (1600 x 1200)" + HelpParameterFormat "" "" "'4mp' (2272 x 1704)" + HelpParameterFormat "" "" "'6mp' (2816 x 2112)" + HelpParameterFormat "" "" "'8mp' (3264 x 2448)" + HelpParameterFormat "" "" "'10mp' (3648 x 2736)" + HelpParameterFormat "" "" "'12mp' (4096 x 3072)" + HelpParameterFormat "" "" "'15mp' (4480 x 3360)" + HelpParameterFormat "" "" "'20mp' (5120 x 3840)" + HelpParameterFormat "" "" "'40mp' (7216 x 5412)" + HelpParameterFormat "" "" "'70mp' (9600 x 7200)" + HelpParameterFormat "" "" "'large'" + HelpParameterFormat "" "" "'medium'" + HelpParameterFormat "" "" "'icon'" + HelpParameterFormat "n" "number" "Number of images to download. [$images_required_default] Maximum of $google_max." + HelpParameterFormat "N" "no-gallery" "Don't create thumbnail gallery." + HelpParameterFormat "o" "output" "The image output directory. [phrase]" + HelpParameterFormat "P" "parallel" "How many parallel image downloads? [$parallel_limit_default] Maximum of $parallel_max. Use wisely!" + HelpParameterFormat "q" "quiet" "Suppress standard output. Errors are still shown." + HelpParameterFormat "r" "retries" "Retry image download this many times. [$retries_default] Maximum of $retries_max." + HelpParameterFormat "s" "save-links" "Save URL list to file [$imagelinks_file] into the output directory." + HelpParameterFormat "S" "skip-no-size" "Don't download any image if its size cannot be determined." + HelpParameterFormat "t" "timeout" "Number of seconds before aborting each image download. [$timeout_default] Maximum of $timeout_max." + HelpParameterFormat "T" "title" "Title for thumbnail gallery image. Enclose whitespace in quotes. [phrase]" + HelpParameterFormat "u" "upper-size" "Only download images that are smaller than this many bytes. [$upper_size_limit_default] Use 0 for unlimited." + #HelpParameterFormat "?" "random" "Download a single random image only" + HelpParameterFormat "" "type" "Image type. Specify like '--type clipart'. Presets are:" + HelpParameterFormat "" "" "'face'" + HelpParameterFormat "" "" "'photo'" + HelpParameterFormat "" "" "'clipart'" + HelpParameterFormat "" "" "'lineart'" + HelpParameterFormat "" "" "'animated'" + HelpParameterFormat "z" "lightning" "Download images even faster by using an optimized set of parameters. For those who really can't wait!" + echo + echo " Example:" + + if [[ $colour = true ]]; then + echo "$(ColourTextBrightWhite " $ ./$script_file -p '$sample_user_query'")" + else + echo " $ ./$script_file -p '$sample_user_query'" + fi + + echo + echo " This will download the first $images_required_default available images for the phrase '$sample_user_query' and build them into a gallery image." + + DebugThis "/ [${FUNCNAME[0]}]" 'exit' + + } + +ValidateParameters() + { + + DebugThis "\ [${FUNCNAME[0]}]" "entry" + + if [[ $create_gallery = false ]] && [[ $remove_after = true ]] && [[ $links_only = false ]]; then + echo + echo " Hmmm, so you've requested:" + echo " 1. don't create a gallery," + echo " 2. delete the images after downloading," + echo " 3. don't save the links file." + echo " Might be time to (R)ead-(T)he-(M)anual. ;)" + exitcode=2 + return 1 + fi + + if [[ $lightning = true ]]; then + # Yeah! + timeout=1 + retries=0 + skip_no_size=true + parallel_limit=16 + links_only=false + create_gallery=false + user_fail_limit=0 + fi + + if [[ $links_only = true ]]; then + create_gallery=false + save_links=true + user_fail_limit=0 + fi + + if [[ $condensed_gallery = true ]]; then + create_gallery=true + fi + + case ${images_required#[-+]} in + *[!0-9]*) + DebugThis '! specified $images_required' 'invalid' + echo + echo "$(ShowAsFailed " !! number specified after (-n, --number) must be a valid integer")" + exitcode=2 + return 1 + ;; + *) + if [[ $images_required -lt 1 ]]; then + images_required=1 + DebugThis '~ $images_required too low so set sensible minimum' "$images_required" + fi + + if [[ $images_required -gt $google_max ]]; then + images_required=$google_max + DebugThis '~ $images_required too high so set as $google_max' "$images_required" + fi + ;; + esac + + if [[ -n $input_pathfile ]]; then + if [[ ! -e $input_pathfile ]]; then + DebugThis '! $input_pathfile' 'not found' + echo + echo "$(ShowAsFailed ' !! input file (-i, --input) was not found')" + exitcode=2 + return 1 + fi + fi + + case ${user_fail_limit#[-+]} in + *[!0-9]*) + DebugThis '! specified $user_fail_limit' 'invalid' + echo + echo "$(ShowAsFailed ' !! number specified after (-f, --failures) must be a valid integer')" + exitcode=2 + return 1 + ;; + *) + if [[ $user_fail_limit -le 0 ]]; then + user_fail_limit=$google_max + DebugThis '~ $user_fail_limit too low so set as $google_max' "$user_fail_limit" + fi + + if [[ $user_fail_limit -gt $google_max ]]; then + user_fail_limit=$google_max + DebugThis '~ $user_fail_limit too high so set as $google_max' "$user_fail_limit" + fi + ;; + esac + + case ${parallel_limit#[-+]} in + *[!0-9]*) + DebugThis '! specified $parallel_limit' 'invalid' + echo + echo "$(ShowAsFailed ' !! number specified after (-P, --parallel) must be a valid integer')" + exitcode=2 + return 1 + ;; + *) + if [[ $parallel_limit -lt 1 ]]; then + parallel_limit=1 + DebugThis '~ $parallel_limit too low so set as' "$parallel_limit" + fi + + if [[ $parallel_limit -gt $parallel_max ]]; then + parallel_limit=$parallel_max + DebugThis '~ $parallel_limit too high so set as' "$parallel_limit" + fi + ;; + esac + + case ${timeout#[-+]} in + *[!0-9]*) + DebugThis '! specified $timeout' 'invalid' + echo + echo "$(ShowAsFailed ' !! number specified after (-t, --timeout) must be a valid integer')" + exitcode=2 + return 1 + ;; + *) + if [[ $timeout -lt 1 ]]; then + timeout=1 + DebugThis '~ $timeout too low so set as' "$timeout" + fi + + if [[ $timeout -gt $timeout_max ]]; then + timeout=$timeout_max + DebugThis '~ $timeout too high so set as' "$timeout" + fi + ;; + esac + + case ${retries#[-+]} in + *[!0-9]*) + DebugThis '! specified $retries' 'invalid' + echo + echo "$(ShowAsFailed ' !! number specified after (-r, --retries) must be a valid integer')" + exitcode=2 + return 1 + ;; + *) + if [[ $retries -lt 1 ]]; then + retries=1 + DebugThis '~ $retries too low so set as' "$retries" + fi + + if [[ $retries -gt $retries_max ]]; then + retries=$retries_max + DebugThis '~ $retries too high so set as' "$retries" + fi + ;; + esac + + case ${upper_size_limit#[-+]} in + *[!0-9]*) + DebugThis '! specified $upper_size_limit' 'invalid' + echo + echo "$(ShowAsFailed ' !! number specified after (-u, --upper-size) must be a valid integer')" + exitcode=2 + return 1 + ;; + *) + if [[ $upper_size_limit -lt 0 ]]; then + upper_size_limit=0 + DebugThis '~ $upper_size_limit too small so set as' "$upper_size_limit (unlimited)" + fi + ;; + esac + + case ${lower_size_limit#[-+]} in + *[!0-9]*) + DebugThis '! specified $lower_size_limit' 'invalid' + echo + echo "$(ShowAsFailed ' !! number specified after (-l, --lower-size) must be a valid integer')" + exitcode=2 + return 1 + ;; + *) + if [[ $lower_size_limit -lt 0 ]]; then + lower_size_limit=0 + DebugThis '~ $lower_size_limit too small so set as' "$lower_size_limit" + fi + + if [[ $upper_size_limit -gt 0 ]] && [[ $lower_size_limit -gt $upper_size_limit ]]; then + lower_size_limit=$(($upper_size_limit-1)) + DebugThis "~ \$lower_size_limit larger than \$upper_size_limit ($upper_size_limit) so set as" "$lower_size_limit" + fi + ;; + esac + + if [[ $max_results_required -lt $(($images_required+$user_fail_limit)) ]]; then + max_results_required=$(($images_required+$user_fail_limit)) + DebugThis '~ $max_results_required too low so set as $images_required + $user_fail_limit' "$max_results_required" + fi + + dimensions_search='' + if [[ -n $dimensions ]]; then + # parse dimensions strings like '1920x1080' or '1920' or 'x1080' + echo "dimensions: [$dimensions]" + + if grep -q 'x' <<< $dimensions; then + echo "found a separator" + image_width=${dimensions%x*} + image_height=${dimensions#*x} + else + image_width=$dimensions + fi + + [[ $image_width =~ ^-?[0-9]+$ ]] && echo "image_width is a number" || echo "image_width is NOT a number" + [[ $image_height =~ ^-?[0-9]+$ ]] && echo "image_height is a number" || echo "image_height is NOT a number" + + echo "image_width: [$image_width]" + echo "image_height: [$image_height]" + echo "dimensions_search: [$dimensions_search]" + + # only while debugging - remove for release + exitcode=2 + return 1 + fi + + if [[ -n $dimensions ]] && [[ -n $min_pixels ]]; then + min_pixels='' + DebugThis '~ $dimensions was specified so cleared $min_pixels' + fi + + min_pixels_search='' + if [[ -n $min_pixels ]]; then + case "$min_pixels" in + qsvga|vga|svga|xga|2mp|4mp|6mp|8mp|10mp|12mp|15mp|20mp|40mp|70mp) + min_pixels_search="isz:lt,islt:${min_pixels}" + ;; + large) + min_pixels_search='isz:l' + ;; + medium) + min_pixels_search='isz:m' + ;; + icon) + min_pixels_search='isz:i' + ;; + *) + echo + echo "$(ShowAsFailed ' !! (-m, --minimum-pixels) preset invalid')" + exitcode=2 + return 1 + ;; + esac + fi + + aspect_ratio_search='' + if [[ -n $aspect_ratio ]]; then + case "$aspect_ratio" in + tall) + ar_type='t' + ;; + square) + ar_type='s' + ;; + wide) + ar_type='w' + ;; + panoramic) + ar_type='xw' + ;; + *) + echo + echo "$(ShowAsFailed ' !! (-a, --aspect-ratio) preset invalid')" + exitcode=2 + return 1 + ;; + esac + [[ -n $ar_type ]] && aspect_ratio_search="iar:${ar_type}" + fi + + image_type_search='' + if [[ -n $image_type ]]; then + case "$image_type" in + face|photo|clipart|lineart|animated) + image_type_search="itp:${image_type}" + ;; + *) + echo + echo "$(ShowAsFailed ' !! (--type) preset invalid')" + exitcode=2 + return 1 + ;; + esac + fi + + if [[ -n $min_pixels_search ]] || [[ -n $aspect_ratio_search ]] || [[ -n $image_type_search ]]; then + advanced_search="&tbs=${min_pixels_search},${aspect_ratio_search},${image_type_search}" + fi + + DebugThis "/ [${FUNCNAME[0]}]" 'exit' + + return 0 + + } + +ProcessQuery() + { + + echo + + # some last-minute parameter validation - needed when reading phrases from text file + if [[ ! $user_query ]]; then + DebugThis '! $user_query' 'unspecified' + echo "$(ShowAsFailed ' !! search phrase (-p, --phrase) was unspecified')" + exitcode=2 + return 1 + fi + + echo " -> processing query: \"$user_query\"" + search_phrase="&q=$(echo $user_query | tr ' ' '+')" # replace whitepace with '+' to suit curl/wget + safe_query="$(echo $user_query | tr ' ' '_')" # replace whitepace with '_' so less issues later on! + DebugThis '? $safe_query' "$safe_query" + + if [[ -z $output_path ]]; then + target_path="${current_path}/${safe_query}" + else + safe_path="$(echo $output_path | tr ' ' '_')" # replace whitepace with '_' so less issues later on! + DebugThis '? $safe_path' "$safe_path" + if [[ ! -z $input_pathfile ]]; then + target_path="${safe_path}/${safe_query}" + else + target_path="$safe_path" + fi + fi + + DebugThis '? $target_path' "$target_path" + + if [[ $exitcode -eq 0 ]] && [[ ! $gallery_title ]]; then + gallery_title=$user_query + DebugThis '~ $gallery_title was unspecified so set as' "$gallery_title" + fi + + # create directory for search phrase + if [[ -e $target_path ]]; then + if [[ $($CMD_LS -1 $target_path | wc -l) -gt 0 ]]; then + #DebugThis "! create ouput directory [$target_path]" "failed! Directory already exists!" + echo + #echo "$(ShowAsFailed " !! output directory [$target_path] already exists")" + #exitcode=3 + #return 1 + fi + else + mkdir -p "$target_path" + result=$? + if [[ $result -gt 0 ]]; then + DebugThis "! create output directory [$target_path]" "failed! mkdir returned: ($result)" + echo + echo "$(ShowAsFailed " !! couldn't create output directory [$target_path]")" + exitcode=3 + return 1 + else + DebugThis "$ create output directory [$target_path]" "success!" + target_path_created=true + fi + fi + + # download search results pages + DownloadResultGroups + if [[ $? -gt 0 ]]; then + echo "$(ShowAsFailed " !! couldn't download Google search results")" + exitcode=4 + return 1 + else + fail_limit=$user_fail_limit + if [[ $fail_limit -gt $result_count ]]; then + fail_limit=$result_count + DebugThis '~ $fail_limit too high so set as $result_count' "$fail_limit" + fi + + if [[ $images_required -gt $result_count ]]; then + images_required=$result_count + DebugThis '~ $images_required too high so set as $result_count' "$result_count" + fi + fi + + if [[ $result_count -eq 0 ]]; then + DebugThis '= zero results returned?' 'Oops...' + exitcode=4 + return 1 + fi + + # download images + if [[ $exitcode -eq 0 ]]; then + if [[ $links_only = false ]]; then + DownloadImages + [[ $? -gt 0 ]] && exitcode=5 + fi + fi + + # build thumbnail gallery even if fail_limit was reached + if [[ $exitcode -eq 0 ]] || [[ $exitcode -eq 5 ]]; then + if [[ $create_gallery = true ]]; then + BuildGallery + if [[ $? -gt 0 ]]; then + echo + echo "$(ShowAsFailed ' !! unable to build thumbnail gallery')" + exitcode=6 + else + if [[ $remove_after = true ]]; then + rm -f "${target_path}/${image_file_prefix}"* + DebugThis '= remove all downloaded images from' "[$target_path]" + fi + fi + fi + fi + + # copy links file into target directory if possible. If not, then copy to current directory. + if [[ $exitcode -eq 0 ]]; then + if [[ $save_links = true ]]; then + if [[ $target_path_created = true ]]; then + cp -f "$imagelinks_pathfile" "${target_path}/${imagelinks_file}" + else + cp -f "$imagelinks_pathfile" "${current_path}/${imagelinks_file}" + fi + fi + fi + + return 0 + + } + +DownloadResultGroups() + { + + DebugThis "\ [${FUNCNAME[0]}]" 'entry' + + local func_startseconds=$(date +%s) + local groups_max=$(($google_max/100)) + local pointer=0 + local parallel_count=0 + local success_count=0 + local fail_count=0 + + InitProgress + InitResultsCounts + + if [[ $verbose = true ]]; then + if [[ $colour = true ]]; then + echo -n " -> searching $(ShowGoogle): " + else + echo -n " -> searching Google: " + fi + fi + + for ((group=1; group<=$groups_max; group++)); do + # wait here until a download slot becomes available + while [[ $parallel_count -eq $parallel_limit ]]; do + sleep 0.5 + + RefreshResultsCounts + ShowResultDownloadProgress + done + + pointer=$((($group-1)*100)) + link_index=$(printf "%02d" $(($group-1))) + + # create run file here as it takes too long to happen in background function + touch "$results_run_count_path/$link_index" + { DownloadResultGroup_auto "$(($group-1))" "$pointer" "$link_index" & } 2>/dev/null + + RefreshResultsCounts + ShowResultDownloadProgress + + [[ $(($group*100)) -gt $max_results_required ]] && break + done + + # wait here while all running downloads finish + wait 2>/dev/null + + RefreshResultsCounts + ShowResultDownloadProgress + + # build all groups into a single file + cat ${results_pathfile}.* > "$results_pathfile" + + ParseResults + + [[ $fail_count -gt 0 ]] && result=1 || result=0 + + DebugThis "T [${FUNCNAME[0]}] elapsed time" "$(ConvertSecs "$(($(date +%s)-$func_startseconds))")" + DebugThis "/ [${FUNCNAME[0]}]" 'exit' + + return $result + + } + +DownloadResultGroup_auto() + { + + # *** This function runs as a background process *** + # $1 = page group to load: (0, 1, 2, 3, etc...) + # $2 = pointer starts at result: (0, 100, 200, 300, etc...) + # $3 = debug index identifier e.g. "02" + + local result=0 + local search_group="&ijn=$1" + local search_start="&start=$2" + local response='' + local link_index="$3" + + # ------------- assumptions regarding Google's URL parameters --------------------------------------------------- + local search_type='&tbm=isch' # search for images + local search_language='&hl=en' # language + local search_style='&site=imghp' # result layout style + local search_match_type='&nfpr=1' # perform exact string search - does not show most likely match results or suggested search. + + local run_pathfile="$results_run_count_path/$link_index" + local success_pathfile="$results_success_count_path/$link_index" + local fail_pathfile="$results_fail_count_path/$link_index" + + DebugThis "- result group ($link_index) download" 'start' + + local downloader_results_get_cmd="wget --quiet --timeout=5 --tries=3 \"https://${server}/search?${search_type}${search_match_type}${search_phrase}${search_language}${search_style}${search_group}${search_start}${advanced_search}\" --user-agent '$useragent' --output-document \"${results_pathfile}.$1\"" + + DebugThis "? result group ($link_index) \$downloader_results_get_cmd" "$downloader_results_get_cmd" + + response=$(eval "$downloader_results_get_cmd") + result=$? + + if [[ $result -eq 0 ]]; then + DebugThis "$ result group ($link_index) download" 'success!' + mv "$run_pathfile" "$success_pathfile" + else + DebugThis "! result group ($link_index) download" "failed! downloader returned: ($result - $(WgetReturnCodes "$result"))" + mv "$run_pathfile" "$fail_pathfile" + fi + + return 0 + + } + +DownloadImages() + { + + DebugThis "\ [${FUNCNAME[0]}]" 'entry' + + local func_startseconds=$(date +%s) + local result_index=0 + local message='' + local result=0 + local parallel_count=0 + local success_count=0 + local fail_count=0 + local imagelink='' + + [[ $verbose = true ]] && echo -n " -> acquiring images: " + + InitProgress + InitDownloadsCounts + + while read imagelink; do + while true; do + RefreshDownloadCounts + ShowImageDownloadProgress + + # abort downloading if too many failures + if [[ $fail_count -ge $fail_limit ]]; then + result=1 + + wait 2>/dev/null + + break 2 + fi + + # wait here until a download slot becomes available + while [[ $parallel_count -eq $parallel_limit ]]; do + sleep 0.5 + + RefreshDownloadCounts + done + + # have enough images now so exit loop + [[ $success_count -eq $images_required ]] && break 2 + + if [[ $(($success_count+$parallel_count)) -lt $images_required ]]; then + ((result_index++)) + local link_index=$(printf "%04d" $result_index) + + # create run file here as it takes too long to happen in background function + touch "${download_run_count_path}/${link_index}" + { DownloadImage_auto "$imagelink" "$link_index" & } 2>/dev/null + + break + fi + done + done < "$imagelinks_pathfile" + + wait 2>/dev/null + + RefreshDownloadCounts + ShowImageDownloadProgress + + if [[ $fail_count -gt 0 ]]; then + # derived from: http://stackoverflow.com/questions/24284460/calculating-rounded-percentage-in-shell-script-without-using-bc + percent="$((200*($fail_count)/($success_count+$fail_count) % 2 + 100*($fail_count)/($success_count+$fail_count)))%" + + if [[ $colour = true ]]; then + echo -n "($(ColourTextBrightRed "$percent")) " + else + echo -n "($percent) " + fi + fi + + if [[ $result -eq 1 ]]; then + DebugThis "! failure limit reached" "${fail_count}/${fail_limit}" + + if [[ $colour = true ]]; then + echo "$(ColourTextBrightRed 'Too many failures!')" + else + echo "Too many failures!" + fi + else + if [[ $result_index -eq $result_count ]]; then + DebugThis "! ran out of images to download!" "${result_index}/${result_count}" + + if [[ $colour = true ]]; then + echo "$(ColourTextBrightRed 'Ran out of images to download!')" + else + echo "Ran out of images to download!" + fi + + result=1 + else + [[ $verbose = true ]] && echo + fi + fi + + if [[ $result -ne 1 ]]; then + download_bytes="$($CMD_DU "${target_path}/${image_file_prefix}"* -cb | tail -n1 | cut -f1)" + DebugThis '= downloaded bytes' "$(DisplayThousands "$download_bytes")" + + download_seconds="$(($(date +%s )-$func_startseconds))" + DebugThis '= download seconds' "$(DisplayThousands "$download_seconds")" + + avg_download_speed="$(DisplayISO "$(($download_bytes/$download_seconds))")" + DebugThis '= average download speed' "${avg_download_speed}B/s" + fi + + DebugThis '? $success_count' "$success_count" + DebugThis '? $fail_count' "$fail_count" + DebugThis "T [${FUNCNAME[0]}] elapsed time" "$(ConvertSecs "$(($(date +%s )-$func_startseconds))")" + DebugThis "/ [${FUNCNAME[0]}]" 'exit' + + return $result + + } + +DownloadImage_auto() + { + + # *** This function runs as a background process *** + # $1 = URL to download + # $2 = debug index identifier e.g. "0026" + + local result=0 + local size_ok=true + local get_download=true + local response='' + local link_index="$2" + + local run_pathfile="$download_run_count_path/$link_index" + local success_pathfile="$download_success_count_path/$link_index" + local fail_pathfile="$download_fail_count_path/$link_index" + + DebugThis "- link ($link_index) download" 'start' + + # extract file extension by checking only last 5 characters of URL (to handle .jpeg as worst case) + local ext=$(echo ${1:(-5)} | $CMD_SED "s/.*\(\.[^\.]*\)$/\1/") + + [[ ! "$ext" =~ '.' ]] && ext='.jpg' # if URL did not have a file extension then choose jpg as default + + local testimage_pathfileext="${testimage_pathfile}($link_index)${ext}" + local targetimage_pathfile="${target_path}/${image_file_prefix}" + local targetimage_pathfileext="${targetimage_pathfile}($link_index)${ext}" + + # are file size limits going to be applied before download? + if [[ $upper_size_limit -gt 0 ]] || [[ $lower_size_limit -gt 0 ]]; then + # try to get file size from server + local downloader_server_response_cmd="wget --spider --server-response --max-redirect 0 --timeout=$timeout --tries=$retries --user-agent \"$useragent\" --output-document \"$testimage_pathfileext\" \"$1\" 2>&1" + DebugThis "? link ($link_index) \$downloader_server_response_cmd" "$downloader_server_response_cmd" + + response=$(eval "$downloader_server_response_cmd") + result=$? + + if [[ $result -eq 0 ]]; then + estimated_size=$(grep 'Content-Length:' <<< "$response" | $CMD_SED 's|^.*: ||' ) + + if [[ -z $estimated_size ]] || [[ $estimated_size = unspecified ]]; then + estimated_size='unknown' + fi + + DebugThis "? link ($link_index) \$estimated_size" "$estimated_size bytes" + + if [[ $estimated_size != unknown ]]; then + if [[ $estimated_size -lt $lower_size_limit ]]; then + DebugThis "! link ($link_index) (before download) is too small!" "$estimated_size bytes < $lower_size_limit bytes" + size_ok=false + get_download=false + fi + + if [[ $upper_size_limit -gt 0 ]] && [[ $estimated_size -gt $upper_size_limit ]]; then + DebugThis "! link ($link_index) (before download) is too large!" "$estimated_size bytes > $upper_size_limit bytes" + size_ok=false + get_download=false + fi + else + if [[ $skip_no_size = true ]]; then + DebugThis "! link ($link_index) unknown image size so" 'failed!' + get_download=false + fi + fi + else + DebugThis "! link ($link_index) (before download) server-response" 'failed!' + estimated_size='unknown' + fi + fi + + # perform actual image download + if [[ $get_download = true ]]; then + local downloader_get_cmd="wget --max-redirect 0 --timeout=$timeout --tries=$retries --user-agent \"$useragent\" --output-document \"$targetimage_pathfileext\" \"$1\" 2>&1" + DebugThis "? link ($link_index) \$downloader_get_cmd" "$downloader_get_cmd" + + response=$(eval "$downloader_get_cmd") + result=$? + + if [[ $result -eq 0 ]]; then + # http://stackoverflow.com/questions/36249714/parse-download-speed-from-wget-output-in-terminal + download_speed=$(grep -o '\([0-9.]\+ [KM]B/s\)' <<< "$response") + + if [[ -e $targetimage_pathfileext ]]; then + actual_size=$(wc -c < "$targetimage_pathfileext") + + if [[ $actual_size = $estimated_size ]]; then + DebugThis "? link ($link_index) \$actual_size" "$actual_size bytes (estimate was correct)" + else + DebugThis "? link ($link_index) \$actual_size" "$actual_size bytes (estimate of $estimated_size bytes was incorrect)" + fi + + if [[ $actual_size -lt $lower_size_limit ]]; then + DebugThis "! link ($link_index) \$actual_size (after download) is too small!" "$actual_size bytes < $lower_size_limit bytes" + rm -f "$targetimage_pathfileext" + size_ok=false + fi + + if [[ $upper_size_limit -gt 0 ]] && [[ $actual_size -gt $upper_size_limit ]]; then + DebugThis "! link ($link_index) \$actual_size (after download) is too large!" "$actual_size bytes > $upper_size_limit bytes" + rm -f "$targetimage_pathfileext" + size_ok=false + fi + else + # file does not exist + size_ok=false + fi + + if [[ $size_ok = true ]]; then + RenameExtAsType "$targetimage_pathfileext" + + if [[ $? -eq 0 ]]; then + mv "$run_pathfile" "$success_pathfile" + DebugThis "$ link ($link_index) image type validation" 'success!' + DebugThis "$ link ($link_index) download" 'success!' + DebugThis "? link ($link_index) \$download_speed" "$download_speed" + else + DebugThis "! link ($link_index) image type validation" 'failed!' + fi + else + # files that were outside size limits still count as failures + mv "$run_pathfile" "$fail_pathfile" + fi + else + mv "$run_pathfile" "$fail_pathfile" + DebugThis "! link ($link_index) download" "failed! downloader returned $result ($(WgetReturnCodes "$result"))" + + # delete temp file if one was created + [[ -e $targetimage_pathfileext ]] && rm -f "$targetimage_pathfileext" + fi + else + mv "$run_pathfile" "$fail_pathfile" + fi + + return 0 + + } + +ParseResults() + { + + DebugThis "\ [${FUNCNAME[0]}]" 'entry' + + result_count=0 + + PageScraper + + if [[ -e $imagelinks_pathfile ]]; then + # check against allowable file types + while read imagelink; do + AllowableFileType "$imagelink" + [[ $? -eq 0 ]] && echo "$imagelink" >> ${imagelinks_pathfile}.tmp + done < "$imagelinks_pathfile" + + [[ -e ${imagelinks_pathfile}.tmp ]] && mv ${imagelinks_pathfile}.tmp "$imagelinks_pathfile" + + # get link count + result_count=$(wc -l < "$imagelinks_pathfile") + + # if too many results then trim + if [[ $result_count -gt $max_results_required ]]; then + DebugThis '! received more results than required' "$result_count/$max_results_required" + + $CMD_HEAD --lines "$max_results_required" --quiet "$imagelinks_pathfile" > "$imagelinks_pathfile".tmp + mv "$imagelinks_pathfile".tmp "$imagelinks_pathfile" + result_count=$max_results_required + + DebugThis '~ trimmed results back to $max_results_required' "$max_results_required" + fi + fi + + if [[ $verbose = true ]]; then + if [[ $result_count -gt 0 ]]; then + if [[ $colour = true ]]; then + if [[ $result_count -ge $(($max_results_required)) ]]; then + echo "$(ColourTextBrightGreen "$result_count") results!" + fi + + if [[ $result_count -ge $images_required ]] && [[ $result_count -lt $(($max_results_required)) ]]; then + echo "$(ColourTextBrightOrange "$result_count") results!" + fi + + if [[ $result_count -lt $images_required ]]; then + echo "$(ColourTextBrightRed "$result_count") results!" + fi + else + echo "$result_count results!" + fi + else + if [[ $colour = true ]]; then + echo "$(ColourTextBrightRed 'No results!')" + else + echo "No results!" + fi + fi + fi + + DebugThis '? $result_count' "$result_count" + DebugThis "/ [${FUNCNAME[0]}]" 'exit' + + } + +BuildGallery() + { + + DebugThis "\ [${FUNCNAME[0]}]" 'entry' + + local thumbnail_dimensions='400x400' + local func_startseconds=$(date +%s) + + InitProgress + + if [[ $verbose = true ]]; then + echo -n " -> building gallery: " + + if [[ $colour = true ]]; then + progress_message="$(ColourTextBrightOrange 'stage 1/4')" + else + progress_message='stage 1/4' + fi + + progress_message+=' (construct thumbnails)' + ProgressUpdater "$progress_message" + fi + + if [[ $condensed_gallery = true ]]; then + build_foreground_cmd="convert \"${target_path}/*[0]\" -define jpeg:size=$thumbnail_dimensions -thumbnail ${thumbnail_dimensions}^ -gravity center -extent $thumbnail_dimensions miff:- | montage - -background none -geometry +0+0 miff:- | convert - -background none -gravity north -splice 0x140 -bordercolor none -border 30 \"$gallery_thumbnails_pathfile\"" + else + build_foreground_cmd="montage \"${target_path}/*[0]\" -background none -shadow -geometry $thumbnail_dimensions miff:- | convert - -background none -gravity north -splice 0x140 -bordercolor none -border 30 \"$gallery_thumbnails_pathfile\"" + fi + + DebugThis '? $build_foreground_cmd' "$build_foreground_cmd" + + eval $build_foreground_cmd 2> /dev/null + result=$? + + if [[ $result -eq 0 ]]; then + DebugThis '$ $build_foreground_cmd' 'success!' + else + DebugThis '! $build_foreground_cmd' "failed! montage returned: ($result)" + fi + + if [[ $result -eq 0 ]]; then + if [[ $verbose = true ]]; then + if [[ $colour = true ]]; then + progress_message="$(ColourTextBrightOrange 'stage 2/4')" + else + progress_message='stage 2/4' + fi + + progress_message+=' (draw background pattern)' + ProgressUpdater "$progress_message" + fi + + # get image dimensions + read -r width height <<< $(convert -ping "$gallery_thumbnails_pathfile" -format "%w %h" info:) + + # create a dark image with light sphere in centre + build_background_cmd="convert -size ${width}x${height} radial-gradient:WhiteSmoke-gray10 \"$gallery_background_pathfile\"" + + DebugThis '? $build_background_cmd' "$build_background_cmd" + + eval $build_background_cmd 2> /dev/null + result=$? + + if [[ $result -eq 0 ]]; then + DebugThis '$ $build_background_cmd' 'success!' + else + DebugThis '! $build_background_cmd' "failed! convert returned: ($result)" + fi + fi + + if [[ $result -eq 0 ]]; then + if [[ $verbose = true ]]; then + if [[ $colour = true ]]; then + progress_message="$(ColourTextBrightOrange 'stage 3/4')" + else + progress_message='stage 3/4' + fi + + progress_message+=' (draw title text image)' + ProgressUpdater "$progress_message" + fi + + # create title image + # let's try a fixed height of 100 pixels + build_title_cmd="convert -size x100 -font $(FirstPreferredFont) -background none -stroke black -strokewidth 10 label:\"\\ \\ $gallery_title\\ \" -blur 0x5 -fill goldenrod1 -stroke none label:\"\\ \\ $gallery_title\\ \" -flatten \"$gallery_title_pathfile\"" + + DebugThis '? $build_title_cmd' "$build_title_cmd" + + eval $build_title_cmd 2> /dev/null + result=$? + + if [[ $result -eq 0 ]]; then + DebugThis '$ $build_title_cmd' 'success!' + else + DebugThis '! $build_title_cmd' "failed! convert returned: ($result)" + fi + fi + + if [[ $result -eq 0 ]]; then + if [[ $verbose = true ]]; then + if [[ $colour = true ]]; then + progress_message="$(ColourTextBrightOrange 'stage 4/4')" + else + progress_message='stage 4/4' + fi + + progress_message+=' (compile all images)' + ProgressUpdater "$progress_message" + fi + + # compose thumbnails image on background image, then title image on top + build_compose_cmd="convert \"$gallery_background_pathfile\" \"$gallery_thumbnails_pathfile\" -gravity center -composite \"$gallery_title_pathfile\" -gravity north -geometry +0+40 -composite \"${target_path}/${gallery_name}-($safe_query).png\"" + + DebugThis '? $build_compose_cmd' "$build_compose_cmd" + + eval $build_compose_cmd 2> /dev/null + result=$? + + if [[ $result -eq 0 ]]; then + DebugThis '$ $build_compose_cmd' 'success!' + else + DebugThis '! $build_compose_cmd' "failed! convert returned: ($result)" + fi + fi + + [[ -e $gallery_title_pathfile ]] && rm -f "$gallery_title_pathfile" + [[ -e $gallery_thumbnails_pathfile ]] && rm -f "$gallery_thumbnails_pathfile" + [[ -e $gallery_background_pathfile ]] && rm -f "$gallery_background_pathfile" + + if [[ $result -eq 0 ]]; then + DebugThis "$ [${FUNCNAME[0]}]" 'success!' + if [[ $verbose = true ]]; then + if [[ $colour = true ]]; then + ProgressUpdater "$(ColourTextBrightGreen 'done!')" + else + ProgressUpdater 'done!' + fi + fi + else + DebugThis "! [${FUNCNAME[0]}]" "failed! See previous!" + + if [[ $colour = true ]]; then + ProgressUpdater "$(ColourTextBrightRed 'failed!')" + else + ProgressUpdater 'failed!' + fi + fi + + [[ $verbose = true ]] && echo + + DebugThis "T [${FUNCNAME[0]}] elapsed time" "$(ConvertSecs "$(($(date +%s)-$func_startseconds))")" + DebugThis "/ [${FUNCNAME[0]}]" 'exit' + + return $result + + } + +Finish() + { + + # write results into debug file + DebugThis "T [$script_file] elapsed time" "$(ConvertSecs "$(($(date +%s)-$script_startseconds))")" + DebugThis "< finished" "$(date)" + + # copy debug file into target directory if possible. If not, then copy to current directory. + if [[ $debug = true ]]; then + if [[ $target_path_created = true ]]; then + [[ -e ${target_path}/${debug_file} ]] && echo "" >> "${target_path}/${debug_file}" + cp -f "$debug_pathfile" "${target_path}/${debug_file}" + else + # append to current path debug file (if it exists) + [[ -e ${current_path}/${debug_file} ]] && echo "" >> "${current_path}/${debug_file}" + cat "$debug_pathfile" >> "${current_path}/${debug_file}" + fi + fi + + # display end + if [[ $verbose = true ]]; then + case $exitcode in + 0) + echo + echo " -> $(ShowAsSucceed 'All done!')" + ;; + [1-2]) + if [[ $show_help_only != true ]]; then + echo + echo " use '-h' or '--help' to display parameter list." + fi + ;; + [3-6]) + echo + echo " -> $(ShowAsFailed 'All done! (with errors)')" + ;; + *) + ;; + esac + fi + + [[ $show_help_only = true ]] && exitcode=0 + + } + +InitProgress() + { + + # needs to be called prior to first call of ProgressUpdater + + progress_message='' + previous_length=0 + previous_msg='' + + } + +ProgressUpdater() + { + + # $1 = message to display + + if [[ $1 != $previous_msg ]]; then + temp=$(RemoveColourCodes "$1") + current_length=$((${#temp}+1)) + + if [[ $current_length -lt $previous_length ]]; then + appended_length=$(($current_length-$previous_length)) + # backspace to start of previous msg, print new msg, add additional spaces, then backspace to end of msg + printf "%${previous_length}s" | tr ' ' '\b' ; echo -n "$1 " ; printf "%${appended_length}s" ; printf "%${appended_length}s" | tr ' ' '\b' + else + # backspace to start of previous msg, print new msg + printf "%${previous_length}s" | tr ' ' '\b' ; echo -n "$1 " + fi + + previous_length=$current_length + previous_msg="$1" + fi + + } + +InitResultsCounts() + { + + # clears the paths used to count the search result pages + + [[ -d $results_run_count_path ]] && rm -f ${results_run_count_path}/* + [[ -d $results_success_count_path ]] && rm -f ${results_success_count_path}/* + [[ -d $results_fail_count_path ]] && rm -f ${results_fail_count_path}/* + + } + +InitDownloadsCounts() + { + + # clears the paths used to count the downloaded images + + [[ -d $download_run_count_path ]] && rm -f ${download_run_count_path}/* + [[ -d $download_success_count_path ]] && rm -f ${download_success_count_path}/* + [[ -d $dowload_fail_count_path ]] && rm -f ${download_fail_count_path}/* + + } + +RefreshResultsCounts() + { + + parallel_count=$($CMD_LS -1 "$results_run_count_path" | wc -l) + success_count=$($CMD_LS -1 "$results_success_count_path" | wc -l) + fail_count=$($CMD_LS -1 "$results_fail_count_path" | wc -l) + + } + +ShowResultDownloadProgress() + { + + if [[ $verbose = true ]]; then + if [[ $colour = true ]]; then + if [[ $success_count -eq $groups_max ]]; then + progress_message="$(ColourTextBrightGreen "${success_count}/${groups_max}")" + else + progress_message="$(ColourTextBrightOrange "${success_count}/${groups_max}")" + fi + else + progress_message="${success_count}/${groups_max}" + fi + + progress_message+=' result groups downloaded.' + ProgressUpdater "$progress_message" + fi + + } + +RefreshDownloadCounts() + { + + parallel_count=$($CMD_LS -1 "$download_run_count_path" | wc -l) + success_count=$($CMD_LS -1 "$download_success_count_path" | wc -l) + fail_count=$($CMD_LS -1 "$download_fail_count_path" | wc -l) + + } + +ShowImageDownloadProgress() + { + + if [[ $verbose = true ]]; then + # number of image downloads that are OK + if [[ $colour = true ]]; then + progress_message="$(ColourTextBrightGreen "${success_count}/${images_required}")" + else + progress_message="${success_count}/${images_required}" + fi + + progress_message+=' downloaded' + + # show the number of files currently downloading (if any) + if [[ $parallel_count -gt 0 ]]; then + progress_message+=', ' + + if [[ $colour = true ]]; then + progress_message+="$(ColourTextBrightOrange "${parallel_count}/${parallel_limit}")" + else + progress_message+="${parallel_count}/${parallel_limit}" + fi + + progress_message+=' are in progress' + fi + + # include failures (if any) + if [[ $fail_count -gt 0 ]]; then + progress_message+=' and ' + + if [[ $colour = true ]]; then + progress_message+="$(ColourTextBrightRed "${fail_count}/${fail_limit}")" + else + progress_message+="${fail_count}/${fail_limit}" + fi + + progress_message+=' failed' + fi + + progress_message+='.' + ProgressUpdater "$progress_message" + fi + + } + +IsReqProgAvail() + { + + # $1 = search $PATH for this binary with 'which' + # $? = 0 if found, 1 if not found + + if (which "$1" > /dev/null 2>&1); then + DebugThis '$ required program is available' "$1" + else + echo " !! required program [$1] is unavailable" + DebugThis '! required program is unavailable' "$1" + return 1 + fi + + } + +IsOptProgAvail() + { + + # $1 = search $PATH for this binary with 'which' + # $? = 0 if found, 1 if not found + + if (which "$1" > /dev/null 2>&1); then + DebugThis '$ optional program is available' "$1" + else + DebugThis '! optional program is unavailable' "$1" + return 1 + fi + + } + +ShowGoogle() + { + + echo -n "$(ColourTextBrightBlue 'G')$(ColourTextBrightRed 'o')$(ColourTextBrightOrange 'o')$(ColourTextBrightBlue 'g')$(ColourTextBrightGreen 'l')$(ColourTextBrightRed 'e')" + + } + +HelpParameterFormat() + { + + # $1 = short parameter + # $2 = long parameter + # $3 = description + + if [[ ! -z $1 ]] && [[ ! -z $2 ]]; then + printf " -%-1s, --%-15s %s\n" "$1" "$2" "$3" + elif [[ -z $1 ]] && [[ ! -z $2 ]]; then + printf " %-1s --%-15s %s\n" '' "$2" "$3" + else + printf " %-1s %-15s %s\n" '' '' "$3" + fi + + } + +RenameExtAsType() + { + + # checks output of 'identify -format "%m"' and ensures provided file extension matches + # $1 = image filename. Is it actually a valid image? + # $? = 0 if it IS an image, 1 if not an image + + local returncode=0 + + if [[ $ident = true ]]; then + [[ -z $1 ]] && returncode=1 + [[ ! -e $1 ]] && returncode=1 + + if [[ $returncode -eq 0 ]]; then + rawtype=$(identify -format "%m" "$1") + returncode=$? + fi + + if [[ $returncode -eq 0 ]]; then + # only want first 4 chars + imagetype="${rawtype:0:4}" + + # exception to handle identify's output for animated gifs i.e. "GIFGIFGIFGIFGIF" + [[ $imagetype = 'GIFG' ]] && imagetype='GIF' + + # exception to handle identify's output for BMP i.e. "BMP3" + [[ $imagetype = 'BMP3' ]] && imagetype='BMP' + + case "$imagetype" in + JPEG|GIF|PNG|BMP|ICO) + # move file into temp file + mv "$1" "$1".tmp + + # then back but with new extension created from $imagetype + mv "$1".tmp "${1%.*}.$(Lowercase "$imagetype")" + ;; + *) + # not a valid image + returncode=1 + ;; + esac + fi + fi + + return $returncode + + } + +AllowableFileType() + { + + # only these image types are considered acceptable + # $1 = string to check + # $? = 0 if OK, 1 if not + + local lcase=$(Lowercase "$1") + local ext=$(echo ${lcase:(-5)} | $CMD_SED "s/.*\(\.[^\.]*\)$/\1/") + + # if string does not have a '.' then assume no extension present + [[ ! "$ext" =~ '.' ]] && ext='' + + case "$ext" in + .jpg|.jpeg|.gif|.png|.bmp|.ico) + # valid image type + return 0 + ;; + *) + # not a valid image + return 1 + ;; + esac + + } + +PageScraper() + { + + #------------- when Google change their web-code again, these regexes will need to be changed too -------------- + # + # sed 1. add 2 x newline chars before each occurence of ' "$imagelinks_pathfile" + + } + +CTRL_C_Captured() + { + + DebugThis "! [SIGINT]" "detected" + + echo + + if [[ $colour = true ]]; then + echo " -> $(ColourTextBrightRed '[SIGINT]') - let's cleanup now ..." + else + echo " -> [SIGINT] - let's cleanup now ..." + fi + + # http://stackoverflow.com/questions/81520/how-to-suppress-terminated-message-after-killing-in-bash + kill $(jobs -p) 2>/dev/null + wait $(jobs -p) 2>/dev/null + + RefreshDownloadCounts + + if [[ $parallel_count -gt 0 ]]; then + # remove any image files where processing by [DownloadImage_auto] was incomplete + for currentfile in $($CMD_LS -1 "$download_run_count_path"); do + rm -f "${target_path}/${image_file_prefix}($currentfile)".* + DebugThis "= link ($currentfile) was partially processed" 'deleted!' + done + fi + + DebugThis "< finished" "$(date)" + + echo + echo " -> And ... we're done." + + exit + + } + +DebugThis() + { + + # $1 = item + # $2 = value + + echo "$1: '$2'" >> "$debug_pathfile" + + } + +WgetReturnCodes() + { + + # convert wget return code into a description + # https://gist.github.com/cosimo/5747881#file-wget-exit-codes-txt + + # $1 = wget return code + # echo = text string + + case "$1" in + 0) + echo "No problems occurred" + ;; + 2) + echo "Parse error — for instance, when parsing command-line options, the .wgetrc or .netrc…" + ;; + 3) + echo "File I/O error" + ;; + 4) + echo "Network failure" + ;; + 5) + echo "SSL verification failure" + ;; + 6) + echo "Username/password authentication failure" + ;; + 7) + echo "Protocol errors" + ;; + 8) + echo "Server issued an error response" + ;; + *) + echo "Generic error code" + ;; + esac + + } + +ConvertSecs() + { + + # http://stackoverflow.com/questions/12199631/convert-seconds-to-hours-minutes-seconds + # $1 = a time in seconds to convert to 'hh:mm:ss' + + ((h=${1}/3600)) + ((m=(${1}%3600)/60)) + ((s=${1}%60)) + + printf "%02dh:%02dm:%02ds\n" $h $m $s + + } + +ColourTextBrightWhite() + { + + echo -en '\E[1;97m'"$(PrintResetColours "$1")" + + } + +ColourTextBrightGreen() + { + + echo -en '\E[1;32m'"$(PrintResetColours "$1")" + + } + +ColourTextBrightOrange() + { + + echo -en '\E[1;38;5;214m'"$(PrintResetColours "$1")" + + } + +ColourTextBrightRed() + { + + echo -en '\E[1;31m'"$(PrintResetColours "$1")" + + } + +ColourTextBrightBlue() + { + + echo -en '\E[1;94m'"$(PrintResetColours "$1")" + + } + +PrintResetColours() + { + + echo -en "$1"'\E[0m' + + } + +RemoveColourCodes() + { + + # http://www.commandlinefu.com/commands/view/3584/remove-color-codes-special-characters-with-sed + echo -n "$1" | $CMD_SED "s,\x1B\[[0-9;]*[a-zA-Z],,g" + + } + +ShowAsFailed() + { + + # $1 = message to show in colour if colour is set + + if [[ $colour = true ]]; then + echo -n "$(ColourTextBrightRed "$1")" + else + echo -n "$1" + fi + + } + +ShowAsSucceed() + { + + # $1 = message to show in colour if colour is set + + if [[ $colour = true ]]; then + echo -n "$(ColourTextBrightGreen "$1")" + else + echo -n "$1" + fi + + } + +Uppercase() + { + + # $1 = some text to convert to uppercase + + echo "$1" | tr "[a-z]" "[A-Z]" + + } + +Lowercase() + { + + # $1 = some text to convert to lowercase + + echo "$1" | tr "[A-Z]" "[a-z]" + + } + +DisplayISO() + { + + # show $1 formatted with 'k', 'M', 'G' + + echo $1 | awk 'BEGIN{ u[0]=""; u[1]=" k"; u[2]=" M"; u[3]=" G"} { n = $1; i = 0; while(n > 1000) { i+=1; n= int((n/1000)+0.5) } print n u[i] } ' + + } + +DisplayThousands() + { + + # show $1 formatted with thousands separator + + printf "%'.f\n" "$1" + + } + +WantedFonts() + { + + local font_list='' + + font_list+='Century-Schoolbook-L-Bold-Italic\n' + font_list+='Droid-Serif-Bold-Italic\n' + font_list+='FreeSerif-Bold-Italic\n' + font_list+='Nimbus-Roman-No9-L-Medium-Italic\n' + font_list+='Times-BoldItalic\n' + font_list+='URW-Palladio-L-Bold-Italic\n' + font_list+='Utopia-Bold-Italic\n' + font_list+='Bitstream-Charter-Bold-Italic\n' + + echo -e "$font_list" + + } + +FirstPreferredFont() + { + + local preferred_fonts=$(WantedFonts) + local available_fonts=$(convert -list font | grep "Font:" | $CMD_SED 's| Font: ||') + local first_available_font='' + + while read preferred_font; do + while read available_font; do + [[ $preferred_font = $available_font ]] && break 2 + done <<< "$available_fonts" + done <<< "$preferred_fonts" + + if [[ ! -z $preferred_font ]]; then + echo "$preferred_font" + else + # uncomment 2nd line down to return first installed font if no preferred fonts could be found. + # for 'convert -font' this isn't needed as it will use a default font if specified font is "". + + #read first_available_font others <<< $available_fonts + + echo "$first_available_font" + fi + + } + +Init + +if [[ $exitcode -eq 0 ]]; then + if [[ ! -z $input_pathfile ]]; then + while read -r file_query; do + if [[ -n $file_query ]]; then + if [[ $file_query != \#* ]]; then + user_query="$file_query" + ProcessQuery + else + DebugThis '! ignoring $file_query' 'comment' + fi + else + DebugThis '! ignoring $file_query' 'null' + fi + done < "$input_pathfile" + else + ProcessQuery + fi +fi + +Finish + +exit $exitcode diff --git a/script/master.sh b/script/master.sh new file mode 100644 index 0000000..9c592eb --- /dev/null +++ b/script/master.sh @@ -0,0 +1,5 @@ +#! /bin/bash +sudo /home/pi/StatusBerry/script/googledl.sh +sudo /home/pi/StatusBerry/src/bildercycle /home/pi/StatusBerry/img +# TFT wieder ausmachen +sudo /home/pi/C-Berry/SW/tft_init \ No newline at end of file diff --git a/script/wetterbilder.sh b/script/wetterbilder.sh new file mode 100644 index 0000000..850fda8 --- /dev/null +++ b/script/wetterbilder.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# (c) schick Informatik +# Dieses Script lädt alle Bilder aus der angegebenen Textdatei herunter und konvertiert sie in +# C-Berry hochkant Format via convert (imagemagick) +# Achtung, die Bilder sollten alle unterschiedliche Namen haben (url) +# +IMGDIR="/home/pi/StatusBerry/download/" +OUTDIR="/home/pi/StatusBerry/img/" +IMGURLLIST="/home/pi/StatusBerry/imgFileUrlList.txt" + +if [ ! -d "$IMGDIR" ] +then + echo "Directory $IMGDIR not found.." + exit 1 +fi + +if [ ! -f "$IMGURLLIST" ] +then + echo "Text file $IMGURLLIST with image url's not found.." + exit 1 +fi + +cat "$IMGURLLIST" | while read ANURL +do + # download image + wget -N -U Mozilla --directory-prefix=$IMGDIR "$ANURL" + FILENAME=$(basename $ANURL) + BASEFILENAME="${FILENAME%.*}" + # image resize and stuff + convert $IMGDIR$FILENAME -resize 240x320! -rotate 90 -depth 24 -compress None -type truecolor -units PixelsPerInch -density 72 "BMP3:$OUTDIR$BASEFILENAME.bmp" + +done + + + diff --git a/src/RAIO8870.c b/src/RAIO8870.c new file mode 100644 index 0000000..3476760 --- /dev/null +++ b/src/RAIO8870.c @@ -0,0 +1,342 @@ +/*##############################################################*/ +/* */ +/* File : RAIO8870.c */ +/* */ +/* Project : TFT for Raspberry Pi Revision 2 */ +/* */ +/* Date : 2013-11-22 last update: 2013-12-20 */ +/* */ +/* Author : Hagen Ploog */ +/* Kai Gillmann */ +/* Timo Pfander */ +/* */ +/* IDE : Geany 1.22 */ +/* Compiler : gcc (Debian 4.6.3-14+rpi1) 4.6.3 */ +/* */ +/* Copyright (C) 2013 admatec GmbH */ +/* */ +/* */ +/* Description : */ +/* */ +/* This file contain several functions to initialize and */ +/* control the graphic controller RAIO8870. */ +/* */ +/* */ +/* License: */ +/* */ +/* This program is free software; you can redistribute it */ +/* and/or modify it under the terms of the GNU General */ +/* Public License as published by the Free Software */ +/* Foundation; either version 3 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will */ +/* be useful, but WITHOUT ANY WARRANTY; without even the */ +/* implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General */ +/* Public License along with this program; if not, */ +/* see . */ +/* */ +/* */ +/* Revision History: */ +/* */ +/* Version 1.0 - Initial release */ +/* */ +/* */ +/* */ +/*##############################################################*/ + +#include +#include "RAIO8870.h" +#include "tft.h" + +uint16_t txc = 0x00; // character x position on screen +uint16_t tyc = 0x00; // character y position on screen +uint8_t char_higth = 15; // character hight depends on character set + + +#ifdef CM_4K + static uint8_t BankNo_WR=0, BankNo_RD=1; +#endif + + +// write command to a register +// ---------------------------------------------------------- +void RAIO_SetRegister( uint8_t reg, uint8_t value ) +{ + TFT_RegWrite( (uint16_t)reg ); + TFT_DataWrite( (uint16_t)value ); +} + + +// set PWM value for backlight +// ---------------------------------------------------------- +void RAIO_SetBacklightPWMValue( uint8_t BL_value ) +{ + RAIO_SetRegister( P1CR, 0x88 ); // Enable PWM1 output devider 256 + RAIO_SetRegister( P1DCR, BL_value ); // -> BL_vaue = 0 (0% PWM) - 255 (100% PWM) +} + + +// initialization of RAIO8870 +// ---------------------------------------------------------- +void RAIO_init( void ) +{ + static uint8_t PLL_Initial_Flag = 0; + + // *************** PLL settings (System Clock) + + if ( !PLL_Initial_Flag ) // wait until PLL is ready + { + PLL_Initial_Flag = 1; // set Flag to avoid repeated PLL init + + RAIO_SetRegister( PLLC1, 0x07 ); // set sys_clk + bcm2835_delayMicroseconds( 200 ); + RAIO_SetRegister( PLLC2, 0x03 ); // set sys_clk + bcm2835_delayMicroseconds( 200 ); + + RAIO_SetRegister( PWRR, 0x01 ); // Raio software reset ( bit 0 ) set + RAIO_SetRegister( PWRR, 0x00 ); // Raio software reset ( bit 0 ) set to 0 + delay( 100 ); + + + // *************** color modes (color depths) + + #ifdef CM_65K + // System Configuration Register + RAIO_SetRegister( SYSR, 0x0A ); // digital TFT + // parallel data out + // no external memory + // 8bit memory data bus + // 16bpp 65K color + // 16bit MCU-interface (data) + RAIO_SetRegister( DPCR, 0x00 ); // one layer + #elif defined(CM_4K) + // System Configuration Register + RAIO_SetRegister( SYSR, 0x06 ); // digital TFT + // parallel data out + // no external memory + // 8bit memory data bus + // 12bpp 4K color + // 16bit MCU-interface (data) + RAIO_SetRegister( DPCR, 0x80 ); // two layers + RAIO_SetRegister( MWCR1, BankNo_WR ); + RAIO_SetRegister( LTPR0, BankNo_RD ); + #else + #error "color_mode not defined" + #endif + } + + + // *************** horizontal settings + + // 0x27+1 * 8 = 320 pixel + RAIO_SetRegister( HDWR , (DISPLAY_WIDTH / 8) - 1 ); + RAIO_SetRegister( HNDFTR, 0x02 ); // Horizontal Non-Display Period Fine Tuning + + // HNDR , Horizontal Non-Display Period Bit[4:0] + // Horizontal Non-Display Period (pixels) = (HNDR + 1)*8 + RAIO_SetRegister( HNDR, 0x03 ); // 0x06 + RAIO_SetRegister( HSTR, 0x04 ); //HSTR , HSYNC Start Position[4:0], HSYNC Start Position(PCLK) = (HSTR + 1)*8 0x02 + + // HPWR , HSYNC Polarity ,The period width of HSYNC. + // 1xxxxxxx activ high 0xxxxxxx activ low + // HSYNC Width [4:0] HSYNC Pulse width + // (PCLK) = (HPWR + 1)*8 + RAIO_SetRegister( HPWR, 0x03 ); // 0x00 + + + // ********************* vertical settings + + // 0x0EF +1 = 240 pixel + RAIO_SetRegister( VDHR0 , ( (DISPLAY_HEIGHT-1) & 0xFF ) ); + RAIO_SetRegister( VDHR1 , ( (DISPLAY_HEIGHT-1) >> 8) ); + + // VNDR0 , Vertical Non-Display Period Bit [7:0] + // Vertical Non-Display area = (VNDR + 1) + // VNDR1 , Vertical Non-Display Period Bit [8] + // Vertical Non-Display area = (VNDR + 1) + RAIO_SetRegister( VNDR0, 0x10 ); + RAIO_SetRegister( VNDR1, 0x00 ); + + // VPWR , VSYNC Polarity ,VSYNC Pulse Width[6:0] + // VSYNC , Pulse Width(PCLK) = (VPWR + 1) + RAIO_SetRegister( VPWR, 0x00 ); + + + // *************** miscellaneous settings + + // active Window + Active_Window( 0, DISPLAY_WIDTH-1, 0, DISPLAY_HEIGHT-1 ); + + // PCLK fetch data on rising edge + RAIO_SetRegister( PCLK, 0x00 ); + + // Backlight dimming + RAIO_SetBacklightPWMValue(50); + + Text_Background_Color( COLOR_WHITE ); + // memory clear with background color + RAIO_SetRegister( MCLR, 0x81 ); + TFT_wait_for_raio(); + + RAIO_SetRegister( IODR, 0x07 ); + RAIO_SetRegister( PWRR, 0x80 ); +} + + + +// set coordinates for active window +// ---------------------------------------------------------- +void Active_Window( uint16_t XL, uint16_t XR , uint16_t YT, uint16_t YB ) +{ + union my_union number; + + //setting active window X + number.value = XL; + RAIO_SetRegister( HSAW0, number.split.low ); + RAIO_SetRegister( HSAW1, number.split.high ); + + number.value = XR; + RAIO_SetRegister( HEAW0, number.split.low ); + RAIO_SetRegister( HEAW1, number.split.high ); + + + //setting active window Y + number.value = YT; + RAIO_SetRegister( VSAW0, number.split.low ); + RAIO_SetRegister( VSAW1, number.split.high ); + + number.value = YB; + RAIO_SetRegister( VEAW0, number.split.low ); + RAIO_SetRegister( VEAW1, number.split.high ); +} + + +// show the BMP picture on the TFT screen +// ---------------------------------------------------------- +void RAIO_Write_Picture( uint16_t *data, uint32_t count ) +{ + TFT_RegWrite( MRWC ); + TFT_DataMultiWrite( data, count); + +#ifdef CM_4K + if ( BankNo_WR==0 ) + { + BankNo_WR=1; + BankNo_RD=0; + } + else + { + BankNo_WR=0; + BankNo_RD=1; + } + + RAIO_SetRegister( MWCR1, BankNo_WR ); + RAIO_SetRegister( LTPR0, BankNo_RD ); +#endif +} + + +// set mode for BET (Block Transfer Engine) +// ---------------------------------------------------------- +void BTE_mode( uint8_t bte_operation, uint8_t rop_function ) +{ + RAIO_SetRegister( BECR1, bte_operation | (rop_function<<4) ); +} + + +// set color +// ---------------------------------------------------------- +void Text_Background_Color( uint8_t color ) +{ + RAIO_SetRegister( TBCR, color ); +} +void Text_Foreground_Color( uint8_t color) +{ + RAIO_SetRegister( TFCR, color); +} + + +// set coordinates for drawing line and square +// ---------------------------------------------------------- +void Set_Geometric_Coordinate(uint16_t X1, uint16_t Y1 ,uint16_t X2 ,uint16_t Y2 ) +{ + union my_union number; + + number.value = X1; + RAIO_SetRegister( DLHSR0, number.split.low ); + RAIO_SetRegister( DLHSR1, number.split.high ); + + number.value = Y1; + RAIO_SetRegister( DLVSR0, number.split.low ); + RAIO_SetRegister( DLVSR1, number.split.high ); + + number.value = X2; + RAIO_SetRegister( DLHER0, number.split.low ); + RAIO_SetRegister( DLHER1, number.split.high ); + + number.value = Y2; + RAIO_SetRegister( DLVER0, number.split.low ); + RAIO_SetRegister( DLVER1, number.split.high ); +} + +// set coordinates for drawing circle +// ---------------------------------------------------------- +void Set_Geometric_Coordinate_circle (uint16_t X1, uint16_t Y1 ,uint8_t rad ) +{ + union my_union number; + + number.value = X1; + RAIO_SetRegister( DCHR0, number.split.low ); + RAIO_SetRegister( DCHR1, number.split.high ); + + number.value = Y1; + RAIO_SetRegister( DCVR0, number.split.low ); + RAIO_SetRegister( DCVR1, number.split.high ); + + RAIO_SetRegister( DCRR, rad ); +} + + +// set draw mode +// ---------------------------------------------------------- +void RAIO_StartDrawing( int16_t whattodraw ) +{ + switch( whattodraw ) // -> see DRAW_MODES + { + case CIRCLE_NONFILL: {RAIO_SetRegister( DCR, 0x40 ); break;} + case CIRCLE_FILL: {RAIO_SetRegister( DCR, 0x60 ); break;} + case SQUARE_NONFILL: {RAIO_SetRegister( DCR, 0x90 ); break;} + case SQUARE_FILL: {RAIO_SetRegister( DCR, 0xB0 ); break;} + case LINE: {RAIO_SetRegister( DCR, 0x80 ); break;} + default: break; + } + + TFT_wait_for_raio(); +} + + +// draw some basic geometrical forms +// ---------------------------------------------------------- +void Draw_Line( uint16_t X1, uint16_t Y1 ,uint16_t X2 ,uint16_t Y2 ) +{ + Set_Geometric_Coordinate( X1, Y1, X2, Y2 ); + RAIO_StartDrawing( LINE ); +} + +void Draw_Square( uint16_t X1, uint16_t Y1 ,uint16_t X2 ,uint16_t Y2 ) +{ + Set_Geometric_Coordinate( X1, Y1, X2, Y2 ); + RAIO_StartDrawing( SQUARE_NONFILL ); +} + +void Draw_Circle( uint16_t X1, uint16_t Y1 ,uint8_t rad ) +{ + Set_Geometric_Coordinate_circle ( X1, Y1, rad ); + RAIO_StartDrawing( CIRCLE_NONFILL ); +} + diff --git a/src/RAIO8870.h b/src/RAIO8870.h new file mode 100644 index 0000000..4a9f34f --- /dev/null +++ b/src/RAIO8870.h @@ -0,0 +1,337 @@ +/*##############################################################*/ +/* */ +/* File : RAIO8870.h */ +/* */ +/* Project : TFT for Raspberry Pi Revision 2 */ +/* */ +/* Date : 2013-11-22 last update: 2013-12-06 */ +/* */ +/* Author : Hagen Ploog */ +/* Kai Gillmann */ +/* Timo Pfander */ +/* */ +/* IDE : Geany 1.22 */ +/* Compiler : gcc (Debian 4.6.3-14+rpi1) 4.6.3 */ +/* */ +/* Copyright (C) 2013 admatec GmbH */ +/* */ +/* */ +/* Description : */ +/* */ +/* This file contains the defines of the RAIO register. */ +/* Furthermore declared the file several functions to control */ +/* the graphic controller RAIO8870. */ +/* */ +/* There can two different color depths to be set for the BMP */ +/* output. It can be changed behind the line color modes. */ +/* */ +/* */ +/* License: */ +/* */ +/* This program is free software; you can redistribute it */ +/* and/or modify it under the terms of the GNU General */ +/* Public License as published by the Free Software */ +/* Foundation; either version 3 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will */ +/* be useful, but WITHOUT ANY WARRANTY; without even the */ +/* implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General */ +/* Public License along with this program; if not, */ +/* see . */ +/* */ +/* */ +/* Revision History: */ +/* */ +/* Version 1.0 - Initial release */ +/* */ +/* */ +/* */ +/*##############################################################*/ + +#ifndef RAIO8870_H +#define RAIO8870_H + +#include + + +//color modes (color depths) { CM_4K=0, CM_65K }; +#define CM_65K + + +// TFT dimensions +#define DISPLAY_WIDTH 320 +#define DISPLAY_HEIGHT 240 +#define PICTURE_PIXELS ( DISPLAY_WIDTH*DISPLAY_HEIGHT ) + + +// RAIO register -> see datasheet RAIO8870 +#define PCOD 0x00 +#define PWRR 0x01 +#define MRWC 0x02 +#define PCLK 0x04 + +#define SYSR 0x10 +#define DRGB 0x11 +#define IOCR 0x12 +#define IODR 0x13 + +#define HDWR 0x14 +#define HNDFTR 0x15 +#define HNDR 0x16 +#define HSTR 0x17 +#define HPWR 0x18 + +#define VDHR0 0x19 +#define VDHR1 0x1a +#define VNDR0 0x1b +#define VNDR1 0x1c +#define VSTR0 0x1d +#define VSTR1 0x1e +#define VPWR 0x1f + +#define DPCR 0x20 +#define FNCR0 0x21 +#define FNCR1 0x22 +#define CGSR 0x23 +#define HOFS0 0x24 +#define HOFS1 0x25 +#define VOFS0 0x26 +#define VOFS1 0x27 +#define ROMS 0x28 + +#define FLDR 0x29 + +#define HSAW0 0x30 +#define HSAW1 0x31 +#define VSAW0 0x32 +#define VSAW1 0x33 +#define HEAW0 0x34 +#define HEAW1 0x35 +#define VEAW0 0x36 +#define VEAW1 0x37 +#define HSSW0 0x38 +#define HSSW1 0x39 +#define VSSW0 0x3a +#define VSSW1 0x3b +#define HESW0 0x3c +#define HESW1 0x3d +#define VESW0 0x3e +#define VESW1 0x3f + +#define MWCR0 0x40 +#define MWCR1 0x41 +#define TFCR 0x42 +#define TBCR 0x43 +#define BTCR 0x44 +#define CURS 0x45 +#define CURH0 0x46 +#define CURH1 0x47 +#define CURV0 0x48 +#define CURV1 0x49 +#define RCURH0 0x4a +#define RCURH01 0x4b +#define RCURV0 0x4c +#define RCURV1 0x4d +#define MRCD 0x4e +#define BECR0 0x50 +#define BECR1 0x51 +#define LTPR0 0x52 +#define LTPR1 0x53 +#define HSBE0 0x54 +#define HSBE1 0x55 +#define VSBE0 0x56 +#define VSBE1 0x57 +#define HDBE0 0x58 +#define HDBE1 0x59 +#define VDBE0 0x5a +#define VDBE1 0x5b +#define BEWR0 0x5c +#define BEWR1 0x5d +#define BEHR0 0x5e +#define BEHR1 0x5f + +#define BGCR0 0x60 +#define BGCR1 0x61 +#define BGCR2 0x62 +#define FGCR0 0x63 +#define FGCR1 0x64 +#define FGCR2 0x65 +#define PTNO 0x66 +#define BGTR 0x67 + +#define TPCR0 0x70 +#define TPCR1 0x71 +#define TPXH 0x72 +#define TPYH 0x73 +#define TPXYL 0x74 + +#define GCHP0 0x80 +#define GCHP1 0x81 +#define GCVP0 0x82 +#define GCVP1 0x83 +#define GCC0 0x84 +#define GCC1 0x85 + +#define PLLC1 0x88 +#define PLLC2 0x89 + +#define P1CR 0x8a +#define P1DCR 0x8b +#define P2CR 0x8c +#define P2DCR 0x8d +#define MCLR 0x8e +#define INTC 0x8f + +#define DCR 0x90 +#define DLHSR0 0x91 +#define DLHSR1 0x92 +#define DLVSR0 0x93 +#define DLVSR1 0x94 +#define DLHER0 0x95 +#define DLHER1 0x96 +#define DLVER0 0x97 +#define DLVER1 0x98 +#define DCHR0 0x99 +#define DCHR1 0x9a +#define DCVR0 0x9b +#define DCVR1 0x9c +#define DCRR 0x9d + +#define TCR1 0xa0 +#define TCR2 0xa1 +#define OEHTCR1 0xa2 +#define OEHTCR2 0xa3 +#define OEHTCR3 0xa4 +#define OEHTCR4 0xa5 +#define OEHTCR5 0xa6 +#define OEHTCR6 0xa7 +#define OEHTCR7 0xa8 +#define OEHTCR8 0xa9 + +#define STHTCR1 0xaa +#define STHTCR2 0xab +#define STHTCR3 0xac +#define STHTCR4 0xad + +#define Q1HCR1 0xae +#define Q1HCR2 0xaf + +#define OEVTCR1 0xb0 +#define OEVTCR2 0xb1 +#define OEVTCR3 0xb2 +#define OEVTCR4 0xb3 +#define CKVTCR1 0xb4 +#define CKVTCR2 0xb5 +#define CKVTCR3 0xb6 +#define CKVTCR4 0xb7 +#define STVTCR1 0xb8 +#define STVTCR2 0xb9 +#define STVTCR3 0xba +#define STVTCR4 0xbb +#define STVTCR5 0xbc +#define STVTCR6 0xbd +#define STVTCR7 0xbe +#define STVTCR8 0xbf + +#define COMTCR1 0xc0 +#define COMTCR2 0xc1 +#define RGBTCR1 0xc2 +#define RGBTCR2 0xc3 + + +// some colors RRRGGGBB +#define COLOR_RED 0xE0 +#define COLOR_BLUE 0x03 +#define COLOR_GREEN 0x1C +#define COLOR_BLACK 0x00 +#define COLOR_WHITE 0xFF +#define COLOR_CYAN 0x1F +#define COLOR_YELLOW 0xFC +#define COLOR_MAGENTA 0xE3 +#define COLOR_DARK_GREEN 0x0C + + +// ROP functions +#define ROP_SOURCE 0xC + + +// BTE operation functions +#define BTE_MOVE_POSITIVE 0x02 +#define BTE_SOLID_FILL 0x0C + + +// declaration of a union (used in RAIO8870.c and tft.c) +// ---------------------------------------------------------- +union my_union +{ + uint32_t value; + struct + { + unsigned char low; + unsigned char high; + } split; +}; + + +// enumeration of drawing modes +// ---------------------------------------------------------- +enum DRAW_MODES { CIRCLE_NONFILL, CIRCLE_FILL, SQUARE_NONFILL, SQUARE_FILL, LINE}; + + +// initialization of RAIO8870 +// ---------------------------------------------------------- +void RAIO_init( void ); + + +// write command to a register +// ---------------------------------------------------------- +void RAIO_SetRegister( uint8_t reg, uint8_t value ); + + +// set PWM value for backlight -> 0 (0% PWM) - 255 (100% PWM) +// ---------------------------------------------------------- +void RAIO_SetBacklightPWMValue( uint8_t BL_value ); + + +// set coordinates for active window +// ---------------------------------------------------------- +void Active_Window(uint16_t XL,uint16_t XR ,uint16_t YT ,uint16_t YB); + + +// set mode for BET (Block Transfer Engine) +// ---------------------------------------------------------- +void BTE_mode( uint8_t bte_operation, uint8_t rop_function ); + + +// set color +// ---------------------------------------------------------- +void Text_Background_Color( uint8_t color ); +void Text_Foreground_Color( uint8_t color ); + +// set coordinates for drawing +// ---------------------------------------------------------- +void Set_Geometric_Coordinate( uint16_t X1, uint16_t Y1 ,uint16_t X2 ,uint16_t Y2 ); +void Set_Geometric_Coordinate_circle (uint16_t X1, uint16_t Y1 ,uint8_t rad ); + +// show the BMP picture on the TFT screen +// ---------------------------------------------------------- +void RAIO_Write_Picture( uint16_t *data, uint32_t count ); + + +// set draw mode -> see DRAW_MODES +// ---------------------------------------------------------- +void RAIO_StartDrawing( int16_t whattodraw ); + + +// draw some basic geometrical forms +// ---------------------------------------------------------- +void Draw_Line( uint16_t X1, uint16_t Y1 ,uint16_t X2 ,uint16_t Y2 ); +void Draw_Square( uint16_t X1, uint16_t Y1 ,uint16_t X2 ,uint16_t Y2 ); + + +#endif diff --git a/src/ST7789.c b/src/ST7789.c new file mode 100644 index 0000000..b83cb2c --- /dev/null +++ b/src/ST7789.c @@ -0,0 +1,194 @@ +/*##############################################################*/ +/* */ +/* File : ST7789.c */ +/* */ +/* Project : TFT for Raspberry Pi Revision 2 */ +/* */ +/* Date : 2014-08-13 last update: 2014-08-13 */ +/* */ +/* Author : Hagen Ploog */ +/* Kai Gillmann */ +/* Timo Pfander */ +/* */ +/* IDE : Geany 1.22 */ +/* Compiler : gcc (Debian 4.6.3-14+rpi1) 4.6.3 */ +/* */ +/* Copyright (C) 2013 admatec GmbH */ +/* */ +/* */ +/* Description : */ +/* */ +/* This file contain several functions to initialize and */ +/* control the tft controller ST7789. */ +/* */ +/* */ +/* License: */ +/* */ +/* This program is free software; you can redistribute it */ +/* and/or modify it under the terms of the GNU General */ +/* Public License as published by the Free Software */ +/* Foundation; either version 3 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will */ +/* be useful, but WITHOUT ANY WARRANTY; without even the */ +/* implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General */ +/* Public License along with this program; if not, */ +/* see . */ +/* */ +/* */ +/* Revision History: */ +/* */ +/* Version 1.0 - Initial release */ +/* */ +/* */ +/* */ +/*##############################################################*/ + +#include +#include +#include +#include "ST7789.h" +#include "tft.h" +#include "bmp.h" + +// initialization of ST7789 +// ---------------------------------------------------------- +void STcontroller_init( void ) +{ + // *************** wakeup display + STcontroller_SetRegister(SLPOUT, 0); + bcm2835_delay(120); + + // *************** display and color format setting + + // write data from top-left to bottom-right + STcontroller_SetRegister(MADCTL, 1, 0xA0); // 0x00 + + #ifdef CM_262K + // 18bit/pixel + // 262K-colors (RGB 6-6-6) + STcontroller_SetRegister(COLMOD, 1, 0x06); + #elif defined(CM_65K) + // 16bit/pixel + // 65K-colors (RGB 5-6-5) + STcontroller_SetRegister(COLMOD, 1, 0x05); + #else + #error "color_mode not defined" + #endif + + // *************** ST7789 porch setting + + // seperate porch control = disabled + // front porch in normal mode = 13 CLK pulse + // back porch in normal mode = 13 CLK pulse + // front porch in idle mode = 3 CLK pulse + // back porch in idle mode = 3 CLK pulse + // front porch in partial mode = 3 CLK pulse + // back porch in partial mode = 3 CLK pulse + STcontroller_SetRegister(PORCTRL, 5, 0x0C, 0x0C, 0x00, 0x33, 0x33); + + // *************** ST7789 Power setting + + // VGH = 13.26V=0x03 + // VGL = -10.43V=0x05 + STcontroller_SetRegister( GCTRL, 1, 0x35 ); + + // VDV and VRH register value comes from command line + STcontroller_SetRegister( VDVVRHEN, 2, 0x01, 0xFF ); + + // VAP = 4.7 + Vcom + Vcom_offset + 0.5*VDV//0x17h + STcontroller_SetRegister( VRHS, 1, 0x17 ); + + // VDV = 0V //VDVS[5:0]=20h + STcontroller_SetRegister( VDVSET, 1, 0x20 ); + + // Vcom = 0.675V + STcontroller_SetRegister( VCOMS, 1, 0x17 ); + + // Vcom_offset = 0V + STcontroller_SetRegister( VCMOFSET, 1, 0x20 ); + + // AVDD = 6.8V + // AVCL = -4.8V//0x02 + // VDS = 2.3V//0x01 + STcontroller_SetRegister(PWCTRL1, 2, 0xA4, 0xA1); + + // *************** ST7789 gamma setting + + STcontroller_SetRegister(PVGAMCTRL, 14, 0xD0, 0x00, 0x14, 0x15, 0x13, 0x2C, 0x42, 0x43, 0x4E, 0x09, 0x16, 0x14, 0x18, 0x21); + STcontroller_SetRegister(NVGAMCTRL, 14, 0xD0, 0x00, 0x14, 0x15, 0x13, 0x0B, 0x43, 0x55, 0x53, 0x0C, 0x17, 0x14, 0x23, 0x20); + + // *************** miscellaneous settings + + // define area (start row, end row, start column, end column) of frame memory where MCU can access + set_row( 0, DISPLAY_HEIGHT - 1 ); + set_column( 0, DISPLAY_WIDTH - 1 ); + + // *************** display on + + STcontroller_SetRegister(DISPON, 0); +} + + +// write command to a register +// ---------------------------------------------------------- +void STcontroller_SetRegister( int reg, int count, ... ) +{ + int i; + va_list args; + va_start(args, count); + + TFT_RegWrite ( reg ); + + for( i=count; i > 0; i-- ) + { + TFT_DataWrite ( (uint8_t)va_arg(args, int) ); + } + + va_end(args); +} + + +// show the BMP picture on the TFT screen +// ---------------------------------------------------------- +#ifdef CM_262K +void STcontroller_Write_Picture( uint32_t *data, uint32_t count ) +#else +void STcontroller_Write_Picture( uint16_t *data, uint32_t count ) +#endif +{ + TFT_RegWrite( RAMWR ); + TFT_DataMultiWrite( data, count ); + +} + + +// define area of frame memory where MCU can access +// ---------------------------------------------------------- +void set_row( uint16_t row_start, uint16_t row_end ) +{ + union my_union start; + union my_union end; + + start.value = row_start; + end.value = row_end; + STcontroller_SetRegister( RASET, 4, start.split.high, start.split.low, end.split.high, end.split.low ); +} + +void set_column( uint16_t col_start, uint16_t col_end ) +{ + union my_union start; + union my_union end; + + start.value = col_start; + end.value = col_end; + STcontroller_SetRegister( CASET, 4, start.split.high, start.split.low, end.split.high, end.split.low ); +} + + + diff --git a/src/ST7789.h b/src/ST7789.h new file mode 100644 index 0000000..aca6ae3 --- /dev/null +++ b/src/ST7789.h @@ -0,0 +1,187 @@ +/*##############################################################*/ +/* */ +/* File : ST7789.h */ +/* */ +/* Project : TFT for Raspberry Pi Revision 2 */ +/* */ +/* Date : 2014-08-13 last update: 2014-08-13 */ +/* */ +/* Author : Hagen Ploog */ +/* Kai Gillmann */ +/* Timo Pfander */ +/* */ +/* IDE : Geany 1.22 */ +/* Compiler : gcc (Debian 4.6.3-14+rpi1) 4.6.3 */ +/* */ +/* Copyright (C) 2013 admatec GmbH */ +/* */ +/* */ +/* Description : */ +/* */ +/* This file contains the defines of the ST register. */ +/* Furthermore declared the file several functions to control */ +/* the tft controller ST7789. */ +/* */ +/* */ +/* License: */ +/* */ +/* This program is free software; you can redistribute it */ +/* and/or modify it under the terms of the GNU General */ +/* Public License as published by the Free Software */ +/* Foundation; either version 3 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will */ +/* be useful, but WITHOUT ANY WARRANTY; without even the */ +/* implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General */ +/* Public License along with this program; if not, */ +/* see . */ +/* */ +/* */ +/* Revision History: */ +/* */ +/* Version 1.0 - Initial release */ +/* */ +/* */ +/* */ +/*##############################################################*/ + +#ifndef ST7789_H +#define ST7789_H + +#include +#include + +//color modes (color depths) { CM_262K, CM_65K }; +#define CM_65K + +// TFT dimensions +#define DISPLAY_WIDTH 320 +#define DISPLAY_HEIGHT 240 +#define PICTURE_PIXELS ( DISPLAY_WIDTH*DISPLAY_HEIGHT ) + +// ST register -> see datasheet ST7789 +#define NOP 0x00 +#define SWRESET 0x01 +#define RDDID 0x04 +#define RDDST 0x09 +#define RDDPM 0x0A +#define RDDMADCTL 0x0B +#define RDDCOLMOD 0x0C +#define RDDIM 0x0D +#define RDDSM 0x0E +#define RDDSDR 0x0F +#define SLPIN 0x10 +#define SLPOUT 0x11 +#define PTLON 0x12 +#define NORON 0x13 +#define INVOFF 0x20 +#define INVON 0x21 +#define GAMSET 0x26 +#define DISPOFF 0x28 +#define DISPON 0x29 +#define CASET 0x2A +#define RASET 0x2B +#define RAMWR 0x2C +#define RAMRD 0x2E +#define PTLAR 0x30 +#define VSCRDEF 0x33 +#define TEOFF 0x34 +#define TEON 0x35 +#define MADCTL 0x36 +#define VSCRSADD 0x37 +#define IDMOFF 0x38 +#define IDMON 0x39 +#define COLMOD 0x3A +#define RAMWRC 0x3C +#define RAMRDC 0x3E +#define TESCAN 0x44 +#define RDTESCAN 0x45 +#define WRDISBV 0x51 +#define RDDISBV 0x52 +#define WRCTRLD 0x53 +#define RDCTRLD 0x54 +#define WRCACE 0x55 +#define RDCABC 0x56 +#define WRCABCMB 0x5E +#define RDCABCMB 0x5F +#define RDID1 0xDA +#define RDID2 0xDB +#define RDID3 0xDC + +#define RAMCTRL 0xB0 +#define RGBCTRL 0xB1 +#define PORCTRL 0xB2 +#define FRCTRL1 0xB3 +#define GCTRL 0xB7 +#define DGMEN 0xBA +#define VCOMS 0xBB +#define LCMCTRL 0xC0 +#define IDSET 0xC1 +#define VDVVRHEN 0xC2 +#define VRHS 0xC3 +#define VDVSET 0xC4 +#define VCMOFSET 0xC5 +#define FRCTRL2 0xC6 +#define CABCCTRL 0xC7 +#define REGSEL1 0xC8 +#define REGSEL2 0xCA +#define PWCTRL1 0xD0 +#define VAPVANEN 0xD2 +#define PVGAMCTRL 0xE0 +#define NVGAMCTRL 0xE1 +#define DGMLUTR 0xE2 +#define DGMLUTB 0xE3 +#define GATECTRL 0xE4 +#define PWCTRL2 0xE8 +#define EQCTRL 0xE9 +#define PROMCTRL 0xEC +#define PROMEN 0xFA +#define NVMSET 0xFC +#define PROMACT 0xFE + + +// declaration of a union (used in ST7789.c and tft.c) +// ---------------------------------------------------------- +/* +union my_union +{ + uint16_t value; + struct + { + unsigned char low; + unsigned char high; + } split; +}; +*/ + +// initialization of ST7789 +// ---------------------------------------------------------- +void STcontroller_init( void ); + + +// write command to a register +// ---------------------------------------------------------- +void STcontroller_SetRegister( int reg, int count, ... ); + + +// show the BMP picture on the TFT screen +// ---------------------------------------------------------- +#ifdef CM_262K +void STcontroller_Write_Picture( uint32_t *data, uint32_t count ); +#else +void STcontroller_Write_Picture( uint16_t *data, uint32_t count ); +#endif + + +// define area of frame memory where MCU can access +// ---------------------------------------------------------- +void set_row( uint16_t row_start, uint16_t row_end ); +void set_column( uint16_t col_start, uint16_t col_end ); + + +#endif diff --git a/src/bildercycle.c b/src/bildercycle.c new file mode 100644 index 0000000..82a59ff --- /dev/null +++ b/src/bildercycle.c @@ -0,0 +1,147 @@ +/* ------------------------------------------------------------------ + * (c) schick Informatik 2017 + * Hilfsprogramm, um Bilder aus einem Verzeichnis auf dem TFT CBerry + * anzuzeigen. + * ------------------------------------------------------------------ */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tft.h" +#include "ST7789.h" +#include "bmp.h" +#include "examples.h" + +#ifdef CM_262K + uint32_t** imageList; +#else + uint16_t** imageList; +#endif + +#define INTERVAL 15 + +int MAXCNT = 256; +int numImages = 0; + +int main( int argc, char **argv ) +{ + if(argc < 2) { + printf("Usage: bildercycle \n"); + return 1; + } + + char *sourcePath = argv[1]; + #ifdef CM_262K + imageList = calloc(MAXCNT, sizeof(uint32_t*)); + #else + imageList = calloc(MAXCNT, sizeof(uint16_t*)); + #endif + + if(ReadFromDirectory(sourcePath)) { + fprintf(stderr, "Error reading images from source path %s\n", sourcePath); + return 1; + } + + printf("%d images read\n", numImages); + + if (!bcm2835_init()) { + fprintf(stderr, "Error initializing TFT (bcm2835_init)\n"); + return 1; + } + + + TFT_init_board(); + + TFT_hard_reset(); + + STcontroller_init(); + + TFT_SetBacklightPWMValue( 20 ); + + // depict a BMP file + // --------------------------------------------- + //example_DepictBMP( &my_filename[0] ); + int i; + for(i=0;id_name, ".")) continue; + if (!strcmp (in_file->d_name, "..")) continue; + + /* Open directory entry file for common operation */ + /* TODO : change permissions to meet your need! */ + + char *bmpFileName = calloc(strlen(in_file->d_name) + strlen(in_dir) + 2, sizeof(char *)); + sprintf(bmpFileName, "%s/%s", in_dir, in_file->d_name); + // fprintf(stderr, "reading %s..\n", bmpFileName); + + #ifdef CM_262K + imageList[numImages] = calloc(PICTURE_PIXELS, sizeof(uint32_t)); + // Achtung Funktion liest von hinten nach vorn, daher den Bilderzeiger auf das letzte Pixel setzen + result = Read_bmp2memory ( bmpFileName, &imageList[numImages][PICTURE_PIXELS - 1] ); + #else + imageList[numImages] = calloc(PICTURE_PIXELS, sizeof(uint16_t)); + result = Read_bmp2memory ( bmpFileName, &imageList[numImages][PICTURE_PIXELS - 1] ); + #endif + + if(result) { + fprintf(stderr,"reading BMP %s failed\n", in_file->d_name); + } else { + result = 0; // at least one! successful + numImages++; + } + + /* + entry_file = fopen(in_file->d_name, "r"); + if (entry_file == NULL) + { + fprintf(stderr, "Error : Failed to open entry file - %s\n", strerror(errno)); + fclose(common_file); + + return 1; + } + */ + + } + + return result; +} + diff --git a/src/bildercycle.h b/src/bildercycle.h new file mode 100644 index 0000000..e69de29 diff --git a/src/bmp.c b/src/bmp.c new file mode 100644 index 0000000..ad4e5e2 --- /dev/null +++ b/src/bmp.c @@ -0,0 +1,206 @@ +/*##############################################################*/ +/* */ +/* File : bmp.c */ +/* */ +/* Project : TFT for Raspberry Pi Revision 2 */ +/* */ +/* Date : 2014-08-13 last update: 2014-08-13 */ +/* */ +/* Author : Hagen Ploog */ +/* Kai Gillmann */ +/* Timo Pfander */ +/* */ +/* IDE : Geany 1.22 */ +/* Compiler : gcc (Debian 4.6.3-14+rpi1) 4.6.3 */ +/* */ +/* Copyright (C) 2013 admatec GmbH */ +/* */ +/* */ +/* Description : */ +/* */ +/* The current software can display BMP files on the C-Berry. */ +/* The BMP file must have a dimension of 320 x 240 pixel and */ +/* a color depth of 24Bit. */ +/* The picture(s) will be stored into a memory. The function */ +/* returns back a pointer with the address of the memory. */ +/* */ +/* */ +/* License: */ +/* */ +/* This program is free software; you can redistribute it */ +/* and/or modify it under the terms of the GNU General */ +/* Public License as published by the Free Software */ +/* Foundation; either version 3 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will */ +/* be useful, but WITHOUT ANY WARRANTY; without even the */ +/* implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General */ +/* Public License along with this program; if not, */ +/* see . */ +/* */ +/* */ +/* Revision History: */ +/* */ +/* Version 1.0 - Initial release */ +/* */ +/* */ +/* */ +/*##############################################################*/ + +#include +#include +#include +#include +#include "bmp.h" +#include "ST7789.h" +#include + + +// store BMP files in memory +// ---------------------------------------------------------- +#ifdef CM_262K +int32_t Read_bmp2memory ( char const *file_name, uint32_t *picture_pointer ) +#else +int32_t Read_bmp2memory ( char const *file_name, uint16_t *picture_pointer ) +#endif +{ + FILE *my_file; + + // bmp_header_t bmp_header; + uint8_t bmp_header_buffer[54]; + uint8_t bmp_line_buffer[ DISPLAY_WIDTH * 3 ]; + + uint16_t bfType; + uint32_t bfOffBits; + + uint32_t biSize; + + int32_t biWidth; + int32_t biHeight; + uint16_t biBitCount; + + uint32_t y,x; + + uint8_t red, green, blue; + uint32_t color; + + + // check for file + // printf( "Opening input file...%s ", file_name ); + if( ( my_file = fopen( file_name, "rb" ) ) == NULL ) + { + printf( "ERROR: Could not open input file for reading: %s\n", strerror(errno) ); + return( -1 ); + } + //printf( "OK\n" ); + + + // read header + fread( &bmp_header_buffer, 1, 54, my_file ); + + + // check for "BM" + //printf( "Checking magic number... " ); + bfType = bmp_header_buffer[1]; + bfType = (bfType << 8) | bmp_header_buffer[0]; + if( bfType != 0x4D42) + { + printf( "ERROR: Not a bitmap file.\n" ); + fclose( my_file ); + return( -1 ); + } + //printf( "OK\n" ); + + + //printf( "Checking header size... " ); + biSize = bmp_header_buffer[17]; + biSize = (biSize << 8) | bmp_header_buffer[16]; + biSize = (biSize << 8) | bmp_header_buffer[15]; + biSize = (biSize << 8) | bmp_header_buffer[14]; + //printf( "%d ", biSize); + if( biSize != 40 ) + { + printf( "ERROR: Not Windows V3\n" ); + fclose( my_file ); + return( -1 ); + } + //printf( "OK\n" ); + + + //printf( "Checking dimensions... " ); + biWidth = bmp_header_buffer[21]; + biWidth = (biWidth << 8) | bmp_header_buffer[20]; + biWidth = (biWidth << 8) | bmp_header_buffer[19]; + biWidth = (biWidth << 8) | bmp_header_buffer[18]; + + biHeight = bmp_header_buffer[25]; + biHeight = (biHeight << 8) | bmp_header_buffer[24]; + biHeight = (biHeight << 8) | bmp_header_buffer[23]; + biHeight = (biHeight << 8) | bmp_header_buffer[22]; + + biBitCount = bmp_header_buffer[29]; + biBitCount = (biBitCount << 8) | bmp_header_buffer[28]; + + //printf( "%dx%dx%dbbp. ", biWidth, biHeight, biBitCount ); + + if( (biWidth != DISPLAY_WIDTH) || (biHeight != DISPLAY_HEIGHT) || (biBitCount != 24) ) + { + printf( "ERROR. %dx%dx%d required.\n", DISPLAY_WIDTH, DISPLAY_HEIGHT, 24 ); + fclose( my_file ); + return( -1 ); + } + //printf( "OK\n\n" ); + + + bfOffBits = bmp_header_buffer[13]; + bfOffBits = (bfOffBits << 8) | bmp_header_buffer[12]; + bfOffBits = (bfOffBits << 8) | bmp_header_buffer[11]; + bfOffBits = (bfOffBits << 8) | bmp_header_buffer[10]; + + //printf( "biOffBits = %d\n", bfOffBits ); + + + fseek( my_file, bfOffBits, SEEK_SET ); + //printf( "Filling picture buffer... \n" ); + + + for (y=DISPLAY_HEIGHT; y>0; y--) + { + fread( &bmp_line_buffer[0], sizeof(bmp_line_buffer), 1, my_file ); + for (x=DISPLAY_WIDTH; x>0; x--) + { + blue = bmp_line_buffer[(x-1)*3 +0]; + green = bmp_line_buffer[(x-1)*3 +1]; + red = bmp_line_buffer[(x-1)*3 +2]; + + #ifdef CM_262K + color = (red >> 2); + color = color << 8; + color = color | (green >> 2); + color = color << 8; + color = color | (blue >> 2); + color = color << 2; + #elif defined(CM_65K) + color = (red >> 3); + color = color << 6; + color = color | (green >> 2); + color = color << 5; + color = color | (blue >> 3); + #else + #error "color_mode not defined" + #endif + + *picture_pointer = color; + picture_pointer--; + } + } + + fclose( my_file ); + + return ( 0 ); +} diff --git a/src/bmp.h b/src/bmp.h new file mode 100644 index 0000000..7c9bdc2 --- /dev/null +++ b/src/bmp.h @@ -0,0 +1,70 @@ +/*##############################################################*/ +/* */ +/* File : bmp.h */ +/* */ +/* Project : TFT for Raspberry Pi Revision 2 */ +/* */ +/* Date : 2014-08-13 last update: 2014-08-13 */ +/* */ +/* Author : Hagen Ploog */ +/* Kai Gillmann */ +/* Timo Pfander */ +/* */ +/* IDE : Geany 1.22 */ +/* Compiler : gcc (Debian 4.6.3-14+rpi1) 4.6.3 */ +/* */ +/* Copyright (C) 2013 admatec GmbH */ +/* */ +/* */ +/* Description : */ +/* */ +/* The current software can display BMP files on the C-Berry. */ +/* The BMP file must have a dimension of 320 x 240 pixel and */ +/* a color depth of 24Bit. */ +/* The picture(s) will be stored into a memory. The function */ +/* returns back a pointer with the address of the memory. */ +/* */ +/* */ +/* License: */ +/* */ +/* This program is free software; you can redistribute it */ +/* and/or modify it under the terms of the GNU General */ +/* Public License as published by the Free Software */ +/* Foundation; either version 3 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will */ +/* be useful, but WITHOUT ANY WARRANTY; without even the */ +/* implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General */ +/* Public License along with this program; if not, */ +/* see . */ +/* */ +/* */ +/* Revision History: */ +/* */ +/* Version 1.0 - Initial release */ +/* */ +/* */ +/* */ +/*##############################################################*/ + +#ifndef BMP_H +#define BMP_H + +#include +#include "ST7789.h" + +// store BMP files in memory +// ---------------------------------------------------------- +#ifdef CM_262K +int32_t Read_bmp2memory ( char const *file_name, uint32_t *picture_pointer ); +#else +int32_t Read_bmp2memory ( char const *file_name, uint16_t *picture_pointer ); +#endif + + +#endif diff --git a/src/examples.c b/src/examples.c new file mode 100644 index 0000000..2fd6860 --- /dev/null +++ b/src/examples.c @@ -0,0 +1,71 @@ +/*##############################################################*/ +/* */ +/* File : examples.c */ +/* */ +/* Project : TFT for Raspberry Pi Revision 2 */ +/* */ +/* Date : 2014-08-13 last update: 2014-08-13 */ +/* */ +/* Author : Hagen Ploog */ +/* Timo Pfander */ +/* */ +/* IDE : Geany 1.22 */ +/* Compiler : gcc (Debian 4.6.3-14+rpi1) 4.6.3 */ +/* */ +/* Copyright (C) 2013 admatec GmbH */ +/* */ +/* */ +/* Description : */ +/* Exmples.c includes the following functions to demonstrate */ +/* some opportunities: */ +/* - depict one BMP file on the TFT */ +/* */ +/* */ +/* License: */ +/* */ +/* This program is free software; you can redistribute it */ +/* and/or modify it under the terms of the GNU General */ +/* Public License as published by the Free Software */ +/* Foundation; either version 3 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will */ +/* be useful, but WITHOUT ANY WARRANTY; without even the */ +/* implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General */ +/* Public License along with this program; if not, */ +/* see . */ +/* */ +/* */ +/* Revision History: */ +/* */ +/* Version 1.0 - Initial release */ +/* */ +/* */ +/* */ +/*##############################################################*/ + + +#include +#include +#include "ST7789.h" +#include "bmp.h" +#include "examples.h" + + +// load and depict a BMP file +// --------------------------------------------- +void example_DepictBMP( char const *file_name ) +{ + #ifdef CM_262K + uint32_t picture[1][ PICTURE_PIXELS ]; + #else + uint16_t picture[1][ PICTURE_PIXELS ]; + #endif + + Read_bmp2memory ( file_name, &picture[0][ PICTURE_PIXELS-1 ] ); + STcontroller_Write_Picture ( &picture[0][0], PICTURE_PIXELS ); +} diff --git a/src/examples.h b/src/examples.h new file mode 100644 index 0000000..d626b7e --- /dev/null +++ b/src/examples.h @@ -0,0 +1,59 @@ +/*##############################################################*/ +/* */ +/* File : examples.h */ +/* */ +/* Project : TFT for Raspberry Pi Revision 2 */ +/* */ +/* Date : 2014-08-13 last update: 2014-08-13 */ +/* */ +/* Author : Hagen Ploog */ +/* Timo Pfander */ +/* */ +/* IDE : Geany 1.22 */ +/* Compiler : gcc (Debian 4.6.3-14+rpi1) 4.6.3 */ +/* */ +/* Copyright (C) 2013 admatec GmbH */ +/* */ +/* */ +/* Description : */ +/* This file declared functions for the different examples in */ +/* example.c */ +/* */ +/* */ +/* License: */ +/* */ +/* This program is free software; you can redistribute it */ +/* and/or modify it under the terms of the GNU General */ +/* Public License as published by the Free Software */ +/* Foundation; either version 3 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will */ +/* be useful, but WITHOUT ANY WARRANTY; without even the */ +/* implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General */ +/* Public License along with this program; if not, */ +/* see . */ +/* */ +/* */ +/* Revision History: */ +/* */ +/* Version 1.0 - Initial release */ +/* */ +/* */ +/* */ +/*##############################################################*/ + +#ifndef EXAMPLES_H +#define EXAMPLES_H + +#include + +// load and depict a BMP file +// --------------------------------------------- +void example_DepictBMP( char const *file_name ); + +#endif diff --git a/src/makefile b/src/makefile new file mode 100644 index 0000000..93b1e29 --- /dev/null +++ b/src/makefile @@ -0,0 +1,20 @@ +all: bildercycle + +bildercycle: bildercycle.o ST7789.o bmp.o tft.o + gcc -g bildercycle.o tft.o ST7789.o bmp.o -lbcm2835 -lrt -lm -o bildercycle + +tft.o: tft.c tft.h ST7789.h + gcc -g -c tft.c + +ST7789.o: ST7789.c ST7789.h + gcc -g -c ST7789.c + +bmp.o: bmp.c bmp.h ST7789.h + gcc -g -c bmp.c + +examples.o: examples.c examples.h ST7789.h bmp.h + gcc -Os -c examples.c + +clean: + rm -rf *o bildercycle + diff --git a/src/tft.c b/src/tft.c new file mode 100644 index 0000000..5c6f917 --- /dev/null +++ b/src/tft.c @@ -0,0 +1,193 @@ +/*##############################################################*/ +/* */ +/* File : tft.c */ +/* */ +/* Project : TFT for Raspberry Pi Revision 2 */ +/* */ +/* Date : 2014-08-13 last update: 2014-08-13 */ +/* */ +/* Author : Hagen Ploog */ +/* Kai Gillmann */ +/* Timo Pfander */ +/* */ +/* IDE : Geany 1.22 */ +/* Compiler : gcc (Debian 4.6.3-14+rpi1) 4.6.3 */ +/* */ +/* Copyright (C) 2013 admatec GmbH */ +/* */ +/* */ +/* Description : */ +/* */ +/* This file controlls the communications between the */ +/* Raspberry Pi and the TFT. The file initialized also the */ +/* GPIO Pins of the Raspberry Pi. */ +/* */ +/* */ +/* License: */ +/* */ +/* This program is free software; you can redistribute it */ +/* and/or modify it under the terms of the GNU General */ +/* Public License as published by the Free Software */ +/* Foundation; either version 3 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will */ +/* be useful, but WITHOUT ANY WARRANTY; without even the */ +/* implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General */ +/* Public License along with this program; if not, */ +/* see . */ +/* */ +/* */ +/* Revision History: */ +/* */ +/* Version 1.0 - Initial release */ +/* */ +/* */ +/* */ +/*##############################################################*/ + + +#include +#include +#include +#include +#include "ST7789.h" +#include "tft.h" + + +// initialization of GPIO and SPI +// ---------------------------------------------------------- +void TFT_init_board ( void ) +{ + // *************** set the pins to be an output and turn them on + + bcm2835_gpio_fsel( ST_RS, BCM2835_GPIO_FSEL_OUTP ); + bcm2835_gpio_write( ST_RS, HIGH ); + + bcm2835_gpio_fsel( ST_RST, BCM2835_GPIO_FSEL_OUTP ); + bcm2835_gpio_write( ST_RST, HIGH ); + + // *************** set pins for PWM + + bcm2835_gpio_fsel( BL_PWM, BCM2835_GPIO_FSEL_ALT5 ); + + // Clock divider is set to 16. + // 1.2MHz/1024 = 1171.875Hz + bcm2835_pwm_set_clock(BCM2835_PWM_CLOCK_DIVIDER_16); + bcm2835_pwm_set_mode(PWM_CHANNEL, 1, 1); + bcm2835_pwm_set_range(PWM_CHANNEL, PWM_RANGE); + + // *************** set pins for SPI + + bcm2835_gpio_fsel(MOSI, BCM2835_GPIO_FSEL_ALT0); + bcm2835_gpio_fsel(SCLK, BCM2835_GPIO_FSEL_ALT0); + bcm2835_gpio_fsel(SPI_CE0, BCM2835_GPIO_FSEL_ALT0); + + // set the SPI CS register to the some sensible defaults + volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/8; + bcm2835_peri_write( paddr, 0 ); // All 0s + + // clear TX and RX fifos + bcm2835_peri_write_nb( paddr, BCM2835_SPI0_CS_CLEAR ); + + bcm2835_spi_setBitOrder( BCM2835_SPI_BIT_ORDER_MSBFIRST ); + bcm2835_spi_setDataMode( BCM2835_SPI_MODE0 ); + bcm2835_spi_setClockDivider( BCM2835_SPI_CLOCK_DIVIDER_2 ); + bcm2835_spi_chipSelect( BCM2835_SPI_CS0 ); + bcm2835_spi_setChipSelectPolarity( BCM2835_SPI_CS0, LOW ); +} + + +// hard reset of the tft controller +// ---------------------------------------------------------- +void TFT_hard_reset( void ) +{ + bcm2835_delay( 1 ); + bcm2835_gpio_write( ST_RST, LOW ); + bcm2835_delay( 10 ); + bcm2835_gpio_write( ST_RST, HIGH ); + bcm2835_delay( 120 ); +} + + +// write byte to register +// ---------------------------------------------------------- +void TFT_RegWrite( uint8_t reg ) +{ + bcm2835_gpio_write( ST_RS, LOW ); + TFT_SPI_data_out ( reg ); +} + + +// write byte to tft +// ---------------------------------------------------------- +void TFT_DataWrite( uint8_t value ) +{ + bcm2835_gpio_write( ST_RS, HIGH ); + TFT_SPI_data_out ( value ); +} + + +// write 3 * 'count'-bytes to tft +// ---------------------------------------------------------- +#ifdef CM_262K +void TFT_DataMultiWrite( uint32_t *data, uint32_t count ) +#else +void TFT_DataMultiWrite( uint16_t *data, uint32_t count ) +#endif +{ + volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; + volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; + + volatile uint32_t* gpio_set = bcm2835_gpio + BCM2835_GPSET0/4; + volatile uint32_t* gpio_clear = bcm2835_gpio + BCM2835_GPCLR0/4; + + uint32_t i; + + bcm2835_gpio_write( ST_RS, HIGH ); + + for( i=0; i> 16); + #endif + *fifo = (uint8_t)(data[i] >> 8); + *fifo = (uint8_t)(data[i] & 0xFF); + + + // write fifo data to SPI TX buffer + while (!(*paddr & BCM2835_SPI0_CS_DONE)) + { + // clear SPI RX buffer + *paddr |=BCM2835_SPI0_CS_CLEAR_RX; + }; + + // deactivate SPI transfer + *paddr &= ~BCM2835_SPI0_CS_TA; + // if(i>3) { while(1); } + } +} + + +// write data via SPI to tft +// ---------------------------------------------------------- +void TFT_SPI_data_out ( uint8_t data ) +{ + bcm2835_spi_writenb( &data, 1 ); +} + + +// set PWM value for backlight -> 0 (0% PWM) - 1024 (100% PWM) +// ---------------------------------------------------------- +void TFT_SetBacklightPWMValue( uint8_t BL_value ) +{ + bcm2835_pwm_set_data( PWM_CHANNEL, BL_value ); +} diff --git a/src/tft.h b/src/tft.h new file mode 100644 index 0000000..40aea9a --- /dev/null +++ b/src/tft.h @@ -0,0 +1,111 @@ +/*##############################################################*/ +/* */ +/* File : tft.h */ +/* */ +/* Project : TFT for Raspberry Pi Revision 2 */ +/* */ +/* Date : 2014-08-13 last update: 2014-08-13 */ +/* */ +/* Author : Hagen Ploog */ +/* Kai Gillmann */ +/* Timo Pfander */ +/* */ +/* IDE : Geany 1.22 */ +/* Compiler : gcc (Debian 4.6.3-14+rpi1) 4.6.3 */ +/* */ +/* Copyright (C) 2013 admatec GmbH */ +/* */ +/* */ +/* Description : */ +/* */ +/* This file declared functions for the SPI communications */ +/* between the Raspberry Pi and the TFT and for the */ +/* initialization of the GPIO Pins of the Raspberry Pi. */ +/* */ +/* */ +/* License: */ +/* */ +/* This program is free software; you can redistribute it */ +/* and/or modify it under the terms of the GNU General */ +/* Public License as published by the Free Software */ +/* Foundation; either version 3 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will */ +/* be useful, but WITHOUT ANY WARRANTY; without even the */ +/* implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General */ +/* Public License along with this program; if not, */ +/* see . */ +/* */ +/* */ +/* Revision History: */ +/* */ +/* Version 1.0 - Initial release */ +/* */ +/* */ +/* */ +/*##############################################################*/ + +#ifndef TFT_H +#define TFT_H + +#include +#include "ST7789.h" + +#define MOSI RPI_V2_GPIO_P1_19 +#define SCLK RPI_V2_GPIO_P1_23 +#define SPI_CE0 RPI_V2_GPIO_P1_24 +#define ST_RST RPI_V2_GPIO_P1_22 +#define ST_RS RPI_V2_GPIO_P1_15 +#define BL_PWM RPI_V2_GPIO_P1_12 + +// PWM settings +#define PWM_CHANNEL 0 +#define PWM_RANGE 255 + + +// initialization of GPIO and SPI +// ---------------------------------------------------------- +void TFT_init_board( void ); + + +// hard reset of the graphic controller and the tft +// ---------------------------------------------------------- +void TFT_hard_reset( void ); + + +// write byte to register +// ---------------------------------------------------------- +void TFT_RegWrite( uint8_t reg ); + + +// write byte to tft +// ---------------------------------------------------------- +void TFT_DataWrite( uint8_t value ); + + +// write 'count'-bytes to tft +// ---------------------------------------------------------- +#ifdef CM_262K +void TFT_DataMultiWrite( uint32_t *data, uint32_t count ); +#else +void TFT_DataMultiWrite( uint16_t *data, uint32_t count ); +#endif + +// write data via SPI to tft +// ---------------------------------------------------------- +void TFT_SPI_data_out ( uint8_t data ); + + +// set PWM value for backlight -> 0 (0% PWM) - PWM_RANGE (100% PWM) +// PWM channel 0 +// MARKSPACE mode +// ---------------------------------------------------------- +void TFT_SetBacklightPWMValue( uint8_t BL_value ); + + +#endif diff --git a/src/tft_string.c b/src/tft_string.c new file mode 100644 index 0000000..0c4fc1b --- /dev/null +++ b/src/tft_string.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include +#include "RAIO8870.h" +#include + + +int main( int argc, char *argv[] ) +{ + + + if( argc !=9 ){ + printf("\ntft_string: Error! Use 'tft_string fontsize pos_x pos_y textcolor backgroundcolor transparenz bold textstring'\n"); + exit(1); + } + + + char text[255]; + strcpy(text,argv[8]); + int fsf=atoi(argv[1]); + int px=atoi(argv[2]); + int py=atoi(argv[3]); + int col_fg=atoi(argv[4]); + int col_bg=atoi(argv[5]); + int transparent=atoi(argv[6]); + int bold=atoi(argv[7]); + + if (!bcm2835_init()){ + printf("tft_string: Error, check your display! \n"); + exit(1); + } + + + if( strlen(text) > 255){ + printf("tft_string: Error, string too long! Limit: 255 chars \n"); + exit(1); + } + + + + if( col_fg < 0 || col_fg > 255){ + printf("tft_string: Error, foregroundcolor out of range! Use 0...255! \n"); + exit(1); + } + + if(col_bg < 0 || col_bg > 255){ + printf("tft_string: Error, backgroundcolor out oft range! Use 0...255!\n"); + exit(1); + } +if( px < 0 || px > 319){ + printf("tft_string: Error, pos_x out of range! pos_x: 0...319!\n"); + exit(1); + } + + if ( py < 0 || py > 239){ + printf("tft_string: Error, pos_y out of range! pos_y: 0...239!\n"); + exit(1); + } + + if ( fsf < 0 || fsf > 15){ + printf("tft_string: Error, bad fontsize! fs: 0...15!\n"); + exit(1); + } + + if (transparent < 0 || transparent > 1){ + printf("Error! Tansparenz muss 0 oder 1 sein!"); + exit(1); + } + if (bold != 0 && bold !=1) { + printf("Error! Bold muss 0 oder 1 sein!"); + exit(1); + } + + + //RAIO_SetFontSizeFactor ( fsf ); + if(transparent == 0) { + fsf=fsf | 0x80; + } + else{ + + fsf=fsf | 0xC0; + } + + if( bold == 1 ){ + + fsf=fsf | 0x20; + } + else { + fsf=fsf & 0xDF; + } + + RAIO_SetRegister( FNCR1, fsf); + RAIO_print_text ( px, py, text, col_bg ,col_fg); + + return 0; +} \ No newline at end of file diff --git a/src/tft_test.c b/src/tft_test.c new file mode 100644 index 0000000..c0201bf --- /dev/null +++ b/src/tft_test.c @@ -0,0 +1,86 @@ +/*##############################################################*/ +/* */ +/* File : tft_test.c */ +/* */ +/* Project : TFT for Raspberry Pi Revision 2 */ +/* */ +/* Date : 2014-08-13 last update: 2014-08-13 */ +/* */ +/* Author : Hagen Ploog */ +/* Kai Gillmann */ +/* Timo Pfander */ +/* */ +/* IDE : Geany 1.22 */ +/* Compiler : gcc (Debian 4.6.3-14+rpi1) 4.6.3 */ +/* */ +/* Copyright (C) 2013 admatec GmbH */ +/* */ +/* */ +/* Description : */ +/* */ +/* This file contains the main loop. The main loop uses the */ +/* functions from examples.h to demonstrate different kind */ +/* of opportunities. */ +/* */ +/* */ +/* License: */ +/* */ +/* This program is free software; you can redistribute it */ +/* and/or modify it under the terms of the GNU General */ +/* Public License as published by the Free Software */ +/* Foundation; either version 3 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will */ +/* be useful, but WITHOUT ANY WARRANTY; without even the */ +/* implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General */ +/* Public License along with this program; if not, */ +/* see . */ +/* */ +/* */ +/* Revision History: */ +/* */ +/* Version 1.0 - Initial release */ +/* */ +/* */ +/* */ +/*##############################################################*/ + +#include +#include +#include +#include +#include "tft.h" +#include "ST7789.h" +#include "bmp.h" +#include "examples.h" + + + +int main( int argc, char **argv ) +{ + char my_filename[] = "../bmp/admatec.bmp"; + + if (!bcm2835_init()) + return 1; + + TFT_init_board(); + TFT_hard_reset(); + STcontroller_init(); + + TFT_SetBacklightPWMValue( 255 ); + + // depict a BMP file + // --------------------------------------------- + example_DepictBMP( &my_filename[0] ); + + + bcm2835_close(); + + return 0; + +}