├── ESP32 source code ├── .gitattributes ├── data │ ├── favicon.ico │ ├── logos │ │ ├── edge.bmp │ │ ├── home.bmp │ │ ├── info.bmp │ │ ├── lock.bmp │ │ ├── mute.bmp │ │ ├── off.bmp │ │ ├── on.bmp │ │ ├── play.bmp │ │ ├── run.bmp │ │ ├── snip.bmp │ │ ├── sp.bmp │ │ ├── stop.bmp │ │ ├── todo.bmp │ │ ├── wifi.bmp │ │ ├── win.bmp │ │ ├── media.bmp │ │ ├── share.bmp │ │ ├── sleep.bmp │ │ ├── teams.bmp │ │ ├── unmute.bmp │ │ ├── window.bmp │ │ ├── closetab.bmp │ │ ├── desktop.bmp │ │ ├── devtools.bmp │ │ ├── explorer.bmp │ │ ├── leftdock.bmp │ │ ├── nosound.bmp │ │ ├── outlook.bmp │ │ ├── raisehand.bmp │ │ ├── refresh.bmp │ │ ├── rightdock.bmp │ │ ├── settings.bmp │ │ ├── topdock.bmp │ │ ├── videooff.bmp │ │ ├── videoon.bmp │ │ ├── volumeup.bmp │ │ ├── bottomdock.bmp │ │ ├── closeshare.bmp │ │ ├── volumedown.bmp │ │ ├── brightnessdown.bmp │ │ ├── brightnessup.bmp │ │ └── freetouchdeck_logo.bmp │ ├── config │ │ ├── colors.json │ │ ├── homescreen.json │ │ ├── wificonfig.json │ │ ├── menu1.json │ │ ├── menu3.json │ │ ├── menu5.json │ │ ├── menu4.json │ │ └── menu2.json │ ├── upload.htm │ ├── error.htm │ ├── editor.htm │ └── saveconfig.htm ├── .gitignore ├── case │ └── ESP32_TFT_Combiner_Case │ │ ├── Top.stl │ │ ├── Bottom.stl │ │ ├── top_screenshot.jpg │ │ ├── FreeTouchDeck_Case.png │ │ ├── bottom_screenshot.jpg │ │ ├── FreeTouchDeck Case V1.f3z │ │ ├── freetouchdeck_case1.jpg │ │ └── readme.md ├── user_setup.h Examples │ ├── ESP32_Dev_Kit_V1_ILI9488_Resistive.png │ ├── README.md │ ├── ESP32_Dev_Kit_V1_ILI9488_Resistive.h │ └── Makerfabs_Capacitive_Touch_User_Setup.h ├── LICENSE ├── Touch.h ├── README.md ├── ConfigHelper.h ├── Action.h ├── ScreenHelper.h └── FreeTouchDeck │ └── FreeTouchDeck.ino ├── Teams Deck source code ├── FreeDeckWindows │ ├── Cat3.ico │ ├── publish │ │ ├── setup.exe │ │ ├── Free Teams Deck.zip │ │ ├── Application Files │ │ │ └── Free Teams Deck_1_0_0_0 │ │ │ │ ├── Cat3.ico.deploy │ │ │ │ ├── Free Teams Deck.exe.deploy │ │ │ │ ├── Free Teams Deck.ico.deploy │ │ │ │ ├── Free Teams Deck.exe.config.deploy │ │ │ │ ├── Free Teams Deck.application │ │ │ │ └── Free Teams Deck.exe.manifest │ │ └── Free Teams Deck.application │ ├── Free Teams Deck.ico │ ├── bin │ │ └── Debug │ │ │ ├── Free Teams Deck.exe │ │ │ ├── Free Teams Deck.pdb │ │ │ ├── app.publish │ │ │ ├── setup.exe │ │ │ ├── Free Teams Deck.exe │ │ │ ├── Application Files │ │ │ │ └── Free Teams Deck_1_0_0_0 │ │ │ │ │ ├── Cat3.ico.deploy │ │ │ │ │ ├── Free Teams Deck.exe.deploy │ │ │ │ │ ├── Free Teams Deck.ico.deploy │ │ │ │ │ ├── Free Teams Deck.exe.config.deploy │ │ │ │ │ └── Free Teams Deck.exe.manifest │ │ │ └── Free Teams Deck.application │ │ │ ├── Free Teams Deck.exe.config │ │ │ ├── Free Teams Deck.application │ │ │ └── Free Teams Deck.exe.manifest │ ├── obj │ │ └── Debug │ │ │ ├── Free Teams Deck.exe │ │ │ ├── Free Teams Deck.pdb │ │ │ ├── DesignTimeResolveAssemblyReferences.cache │ │ │ ├── FreeDeckWindows.csprojAssemblyReference.cache │ │ │ ├── DesignTimeResolveAssemblyReferencesInput.cache │ │ │ ├── FreeDeckWindows.csproj.FileListAbsolute.txt │ │ │ ├── Free Teams Deck.application │ │ │ └── Free Teams Deck.exe.manifest │ ├── FreeDeckWindows_TemporaryKey.pfx │ ├── App.config │ ├── FreeDeckWindows.csproj.user │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── FreeDeckWindows.csproj │ └── Program.cs └── FreeDeckWindows.sln └── README.md /ESP32 source code/.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /ESP32 source code/data/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/favicon.ico -------------------------------------------------------------------------------- /ESP32 source code/data/logos/edge.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/edge.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/home.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/home.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/info.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/info.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/lock.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/lock.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/mute.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/mute.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/off.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/off.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/on.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/on.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/play.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/play.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/run.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/run.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/snip.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/snip.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/sp.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/sp.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/stop.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/stop.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/todo.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/todo.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/wifi.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/wifi.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/win.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/win.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/media.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/media.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/share.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/share.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/sleep.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/sleep.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/teams.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/teams.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/unmute.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/unmute.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/window.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/window.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/closetab.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/closetab.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/desktop.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/desktop.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/devtools.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/devtools.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/explorer.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/explorer.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/leftdock.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/leftdock.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/nosound.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/nosound.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/outlook.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/outlook.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/raisehand.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/raisehand.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/refresh.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/refresh.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/rightdock.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/rightdock.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/settings.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/settings.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/topdock.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/topdock.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/videooff.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/videooff.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/videoon.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/videoon.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/volumeup.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/volumeup.bmp -------------------------------------------------------------------------------- /ESP32 source code/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | data/config/wificonfig.json 4 | .vscode/c_cpp_properties.json 5 | .vscode/arduino.json 6 | *.json 7 | -------------------------------------------------------------------------------- /ESP32 source code/data/logos/bottomdock.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/bottomdock.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/closeshare.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/closeshare.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/volumedown.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/volumedown.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/brightnessdown.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/brightnessdown.bmp -------------------------------------------------------------------------------- /ESP32 source code/data/logos/brightnessup.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/brightnessup.bmp -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/Cat3.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/Cat3.ico -------------------------------------------------------------------------------- /ESP32 source code/data/logos/freetouchdeck_logo.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/data/logos/freetouchdeck_logo.bmp -------------------------------------------------------------------------------- /ESP32 source code/case/ESP32_TFT_Combiner_Case/Top.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/case/ESP32_TFT_Combiner_Case/Top.stl -------------------------------------------------------------------------------- /ESP32 source code/case/ESP32_TFT_Combiner_Case/Bottom.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/case/ESP32_TFT_Combiner_Case/Bottom.stl -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/publish/setup.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/publish/setup.exe -------------------------------------------------------------------------------- /ESP32 source code/data/config/colors.json: -------------------------------------------------------------------------------- 1 | { 2 | "menubuttoncolor": "#000000", 3 | "functionbuttoncolor": "#000000", 4 | "latchcolor": "#fe0149", 5 | "background": "#000000" 6 | } -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/Free Teams Deck.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/Free Teams Deck.ico -------------------------------------------------------------------------------- /ESP32 source code/case/ESP32_TFT_Combiner_Case/top_screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/case/ESP32_TFT_Combiner_Case/top_screenshot.jpg -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/publish/Free Teams Deck.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/publish/Free Teams Deck.zip -------------------------------------------------------------------------------- /ESP32 source code/case/ESP32_TFT_Combiner_Case/FreeTouchDeck_Case.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/case/ESP32_TFT_Combiner_Case/FreeTouchDeck_Case.png -------------------------------------------------------------------------------- /ESP32 source code/case/ESP32_TFT_Combiner_Case/bottom_screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/case/ESP32_TFT_Combiner_Case/bottom_screenshot.jpg -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/bin/Debug/Free Teams Deck.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/bin/Debug/Free Teams Deck.exe -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/bin/Debug/Free Teams Deck.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/bin/Debug/Free Teams Deck.pdb -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/obj/Debug/Free Teams Deck.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/obj/Debug/Free Teams Deck.exe -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/obj/Debug/Free Teams Deck.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/obj/Debug/Free Teams Deck.pdb -------------------------------------------------------------------------------- /ESP32 source code/case/ESP32_TFT_Combiner_Case/FreeTouchDeck Case V1.f3z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/case/ESP32_TFT_Combiner_Case/FreeTouchDeck Case V1.f3z -------------------------------------------------------------------------------- /ESP32 source code/case/ESP32_TFT_Combiner_Case/freetouchdeck_case1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/case/ESP32_TFT_Combiner_Case/freetouchdeck_case1.jpg -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/FreeDeckWindows_TemporaryKey.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/FreeDeckWindows_TemporaryKey.pfx -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/bin/Debug/app.publish/setup.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/bin/Debug/app.publish/setup.exe -------------------------------------------------------------------------------- /ESP32 source code/data/config/homescreen.json: -------------------------------------------------------------------------------- 1 | { 2 | "logo0": "win.bmp", 3 | "logo1": "teams.bmp", 4 | "logo2": "edge.bmp", 5 | "logo3": "window.bmp", 6 | "logo4": "media.bmp", 7 | "logo5": "settings.bmp" 8 | } -------------------------------------------------------------------------------- /ESP32 source code/user_setup.h Examples/ESP32_Dev_Kit_V1_ILI9488_Resistive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/ESP32 source code/user_setup.h Examples/ESP32_Dev_Kit_V1_ILI9488_Resistive.png -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/bin/Debug/app.publish/Free Teams Deck.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/bin/Debug/app.publish/Free Teams Deck.exe -------------------------------------------------------------------------------- /ESP32 source code/data/config/wificonfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "ssid": "HANDS ON tek", 3 | "password": "123@password", 4 | "wifimode": "WIFI_STA", 5 | "wifihostname": "freetouchdeck", 6 | "sleepenable": true, 7 | "sleeptimer": 10 8 | } -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/obj/Debug/DesignTimeResolveAssemblyReferences.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/obj/Debug/DesignTimeResolveAssemblyReferences.cache -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/obj/Debug/FreeDeckWindows.csprojAssemblyReference.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/obj/Debug/FreeDeckWindows.csprojAssemblyReference.cache -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/publish/Application Files/Free Teams Deck_1_0_0_0/Cat3.ico.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/publish/Application Files/Free Teams Deck_1_0_0_0/Cat3.ico.deploy -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/bin/Debug/Free Teams Deck.exe.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/publish/Application Files/Free Teams Deck_1_0_0_0/Free Teams Deck.exe.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/publish/Application Files/Free Teams Deck_1_0_0_0/Free Teams Deck.exe.deploy -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/publish/Application Files/Free Teams Deck_1_0_0_0/Free Teams Deck.ico.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/publish/Application Files/Free Teams Deck_1_0_0_0/Free Teams Deck.ico.deploy -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/bin/Debug/app.publish/Application Files/Free Teams Deck_1_0_0_0/Cat3.ico.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/bin/Debug/app.publish/Application Files/Free Teams Deck_1_0_0_0/Cat3.ico.deploy -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/bin/Debug/app.publish/Application Files/Free Teams Deck_1_0_0_0/Free Teams Deck.exe.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/bin/Debug/app.publish/Application Files/Free Teams Deck_1_0_0_0/Free Teams Deck.exe.deploy -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/bin/Debug/app.publish/Application Files/Free Teams Deck_1_0_0_0/Free Teams Deck.ico.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaoferreira/Free-Teams-Deck/HEAD/Teams Deck source code/FreeDeckWindows/bin/Debug/app.publish/Application Files/Free Teams Deck_1_0_0_0/Free Teams Deck.ico.deploy -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/publish/Application Files/Free Teams Deck_1_0_0_0/Free Teams Deck.exe.config.deploy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/bin/Debug/app.publish/Application Files/Free Teams Deck_1_0_0_0/Free Teams Deck.exe.config.deploy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Free Teams Deck 2 | Control Microsoft Teams using Free Touch Deck when the application is not in focus using Microsoft Windows 3 | 4 | In this respository you will find 2 different different projects: 5 | * ESP32 source code 6 | * Teams Deck source code 7 | 8 | To learn more about these projects I recommend you to have a look to the following articles: 9 | 10 | * [How to build a Free Touch Deck to control Microsoft Teams](https://teams.handsontek.net/2021/01/31/build-free-touch-deck-control-microsoft-teams) 11 | * [My experience building a Free Touch Deck](https://handsontek.net/experience-building-free-touch-deck) 12 | 13 | ![Free Teams Deck](https://handsontek.net/images/Teams/TeamsDeck/Free%20Teams%20Deck.png) 14 | -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/FreeDeckWindows.csproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | publish\ 5 | 6 | https://teams.handsnontek.net/teamsdeck 7 | 8 | 9 | https://teams.handsnontek.net/teamsdeck 10 | en-US 11 | false 12 | 13 | 14 | false 15 | 16 | -------------------------------------------------------------------------------- /ESP32 source code/data/config/menu1.json: -------------------------------------------------------------------------------- 1 | { 2 | "logo0": "snip.bmp", 3 | "logo1": "todo.bmp", 4 | "logo2": "outlook.bmp", 5 | "logo3": "explorer.bmp", 6 | "logo4": "lock.bmp", 7 | "button0":{ 8 | "latch": false, 9 | "latchlogo": "", 10 | "actionarray": [ "5", "5", "4" ], 11 | "valuearray": [ "8", "2", "s" ] 12 | }, 13 | "button1":{ 14 | "latch": false, 15 | "latchlogo": "", 16 | "actionarray": [ "5", "7", "0" ], 17 | "valuearray": [ "8", "2", "0" ] 18 | }, 19 | "button2":{ 20 | "latch": false, 21 | "latchlogo": "", 22 | "actionarray": [ "5", "7", "0" ], 23 | "valuearray": [ "8", "3", "0" ] 24 | }, 25 | "button3":{ 26 | "latch": false, 27 | "latchlogo": "", 28 | "actionarray": [ "5", "4", "0"], 29 | "valuearray": [ "8", "e", "0" ] 30 | }, 31 | "button4":{ 32 | "latch": false, 33 | "latchlogo": "", 34 | "actionarray": [ "5", "4", "0" ], 35 | "valuearray": [ "8", "l", "0" ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ESP32 source code/data/config/menu3.json: -------------------------------------------------------------------------------- 1 | { 2 | "logo0": "refresh.bmp", 3 | "logo1": "devtools.bmp", 4 | "logo2": "closetab.bmp", 5 | "logo3": "sp.bmp", 6 | "logo4": "sp.bmp", 7 | "button0":{ 8 | "latch": false, 9 | "latchlogo": "", 10 | "actionarray": [ "5", "6", "0" ], 11 | "valuearray": [ "2", "5", "0" ] 12 | }, 13 | "button1":{ 14 | "latch": false, 15 | "latchlogo": "", 16 | "actionarray": [ "6", "0", "0" ], 17 | "valuearray": [ "12", "0", "0" ] 18 | }, 19 | "button2":{ 20 | "latch": false, 21 | "latchlogo": "", 22 | "actionarray": [ "5", "4", "0" ], 23 | "valuearray": [ "1", "w", "0" ] 24 | }, 25 | "button3":{ 26 | "latch": false, 27 | "latchlogo": "", 28 | "actionarray": [ "5", "7", "0"], 29 | "valuearray": [ "1", "2", "0" ] 30 | }, 31 | "button4":{ 32 | "latch": false, 33 | "latchlogo": "", 34 | "actionarray": [ "5", "7", "0" ], 35 | "valuearray": [ "1", "1", "0" ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ESP32 source code/data/config/menu5.json: -------------------------------------------------------------------------------- 1 | { 2 | "logo0": "nosound.bmp", 3 | "logo1": "volumedown.bmp", 4 | "logo2": "volumeup.bmp", 5 | "logo3": "play.bmp", 6 | "logo4": "stop.bmp", 7 | "button0":{ 8 | "latch": true, 9 | "latchlogo": "", 10 | "actionarray": [ "3", "0", "0" ], 11 | "valuearray": [ "1", "0", "0" ] 12 | }, 13 | "button1":{ 14 | "latch": false, 15 | "latchlogo": "", 16 | "actionarray": [ "3", "0", "0" ], 17 | "valuearray": [ "2", "0", "0" ] 18 | }, 19 | "button2":{ 20 | "latch": false, 21 | "latchlogo": "", 22 | "actionarray": [ "3", "0", "0" ], 23 | "valuearray": [ "3", "0", "0" ] 24 | }, 25 | "button3":{ 26 | "latch": false, 27 | "latchlogo": "", 28 | "actionarray": [ "3", "0", "0"], 29 | "valuearray": [ "4", "0", "0" ] 30 | }, 31 | "button4":{ 32 | "latch": false, 33 | "latchlogo": "", 34 | "actionarray": [ "3", "0", "0" ], 35 | "valuearray": [ "5", "0", "0" ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ESP32 source code/user_setup.h Examples/README.md: -------------------------------------------------------------------------------- 1 | # TFT_eSPI configuration (User_Setup.h) 2 | 3 | Before compiling and uploading the FreeTouchDeck.ino sketch, you will have to edit the **User_Setup.h** file included with the TFT_eSPI library to match the setup you have. This can be found in your Arduino skechtbook folder under "libraries". If you have not renamed the TFT_eSPI library folder, the file **User_Setup.h** can be found in **TFT_eSPI-master**. 4 | 5 | You can use the files in this directory as an example for different boards and screens. Simple rename the file that matches your combination of board and screen to `User_Setup.h` and replace the file that is in the library folder. You can also copy the contents of a file and replace the contenst in the existing `User_Setup.h` 6 | 7 | If there is a wiring diagram available, it is a .png image with the same name. 8 | 9 | # Help 10 | 11 | You can join my Discord server where I have a dedicated #freetouchdeck channel. https://discord.gg/RE3XevS 12 | -------------------------------------------------------------------------------- /ESP32 source code/data/config/menu4.json: -------------------------------------------------------------------------------- 1 | { 2 | "logo0": "desktop.bmp", 3 | "logo1": "leftdock.bmp", 4 | "logo2": "rightdock.bmp", 5 | "logo3": "topdock.bmp", 6 | "logo4": "bottomdock.bmp", 7 | "button0":{ 8 | "latch": false, 9 | "latchlogo": "", 10 | "actionarray": [ "5", "4", "0" ], 11 | "valuearray": [ "8", "d", "0" ] 12 | }, 13 | "button1":{ 14 | "latch": false, 15 | "latchlogo": "", 16 | "actionarray": [ "5", "2", "0" ], 17 | "valuearray": [ "8", "3", "0" ] 18 | }, 19 | "button2":{ 20 | "latch": false, 21 | "latchlogo": "", 22 | "actionarray": [ "5", "2", "0" ], 23 | "valuearray": [ "8", "4", "0" ] 24 | }, 25 | "button3":{ 26 | "latch": false, 27 | "latchlogo": "", 28 | "actionarray": [ "5", "2", "0"], 29 | "valuearray": [ "8", "1", "0" ] 30 | }, 31 | "button4":{ 32 | "latch": false, 33 | "latchlogo": "", 34 | "actionarray": [ "5", "2", "0" ], 35 | "valuearray": [ "8", "2", "0" ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ESP32 source code/data/upload.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | FreeTouchDeck Configurator 10 | 18 | 19 | 20 | 21 |

FreeTouchDeck Configurator


22 | Upload Succes! 23 | 24 | 25 |

26 |
27 | 30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /ESP32 source code/data/config/menu2.json: -------------------------------------------------------------------------------- 1 | { 2 | "logo0": "mute.bmp", 3 | "logo1": "videooff.bmp", 4 | "logo2": "share.bmp", 5 | "logo3": "raisehand.bmp", 6 | "logo4": "off.bmp", 7 | "button0":{ 8 | "latch": true, 9 | "latchlogo": "unmute.bmp", 10 | "actionarray": [ "5", "5", "4" ], 11 | "valuearray": [ "1", "6", "m" ] 12 | }, 13 | "button1":{ 14 | "latch": true, 15 | "latchlogo": "videoon.bmp", 16 | "actionarray": [ "5", "5", "4" ], 17 | "valuearray": [ "1", "6", "o" ] 18 | }, 19 | "button2":{ 20 | "latch": true, 21 | "latchlogo": "closeshare.bmp", 22 | "actionarray": [ "5", "5", "4" ], 23 | "valuearray": [ "1", "6", "e" ] 24 | }, 25 | "button3":{ 26 | "latch": false, 27 | "latchlogo": "", 28 | "actionarray": [ "5", "5", "4" ], 29 | "valuearray": [ "1", "6", "k" ] 30 | }, 31 | "button4":{ 32 | "latch": false, 33 | "latchlogo": "", 34 | "actionarray": [ "5", "5", "4" ], 35 | "valuearray": [ "1", "6", "b" ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ESP32 source code/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Dustin Watts 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/obj/Debug/FreeDeckWindows.csproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- 1 | C:\Users\JOFR\Desktop\Personal\Windows\FreeDeckWindows\FreeDeckWindows\obj\Debug\FreeDeckWindows.csprojAssemblyReference.cache 2 | C:\Users\JOFR\Desktop\Personal\Windows\FreeDeckWindows\FreeDeckWindows\bin\Debug\Free Teams Deck.exe.config 3 | C:\Users\JOFR\Desktop\Personal\Windows\FreeDeckWindows\FreeDeckWindows\bin\Debug\Free Teams Deck.exe.manifest 4 | C:\Users\JOFR\Desktop\Personal\Windows\FreeDeckWindows\FreeDeckWindows\bin\Debug\Free Teams Deck.application 5 | C:\Users\JOFR\Desktop\Personal\Windows\FreeDeckWindows\FreeDeckWindows\bin\Debug\Free Teams Deck.exe 6 | C:\Users\JOFR\Desktop\Personal\Windows\FreeDeckWindows\FreeDeckWindows\bin\Debug\Free Teams Deck.pdb 7 | C:\Users\JOFR\Desktop\Personal\Windows\FreeDeckWindows\FreeDeckWindows\obj\Debug\Free Teams Deck.exe.manifest 8 | C:\Users\JOFR\Desktop\Personal\Windows\FreeDeckWindows\FreeDeckWindows\obj\Debug\Free Teams Deck.application 9 | C:\Users\JOFR\Desktop\Personal\Windows\FreeDeckWindows\FreeDeckWindows\obj\Debug\Free Teams Deck.exe 10 | C:\Users\JOFR\Desktop\Personal\Windows\FreeDeckWindows\FreeDeckWindows\obj\Debug\Free Teams Deck.pdb 11 | -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29411.108 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FreeDeckWindows", "FreeDeckWindows\FreeDeckWindows.csproj", "{746AF44D-8C58-48E2-ADA6-97A412E566F6}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {746AF44D-8C58-48E2-ADA6-97A412E566F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {746AF44D-8C58-48E2-ADA6-97A412E566F6}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {746AF44D-8C58-48E2-ADA6-97A412E566F6}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {746AF44D-8C58-48E2-ADA6-97A412E566F6}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {CA480C73-37B4-41F7-837C-2DAA559364B6} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /ESP32 source code/case/ESP32_TFT_Combiner_Case/readme.md: -------------------------------------------------------------------------------- 1 | # FreeTouchDeck Case 2 | 3 | ![](freetouchdeck_case1.jpg) 4 | 5 | You can print the case that will house both The ILI9488 + TFT screen and you ESP32 in a nice case. This housing is made with the ESP32 TFT Combiner PCB in mind, but will also work if you made your FreeTouchDeck on a prototyping board. 6 | 7 | This case is made to have a press fit. If you are happy with your print and don't plan on taking it apart again, you could use some CA glue to hold the two halves together, but is it not necessary. 8 | 9 | # Print settings 10 | 11 | I recommend the following settings when printing the case: 12 | 13 | ## Top 14 | 15 | - Orientation: Flat side down 16 | - Layer height: 0.2 mm 17 | - Infill: 100% 18 | - Support: none 19 | 20 | ![](top_screenshot.jpg) 21 | 22 | ## Bottom 23 | 24 | - Orientation: The part that connects to the top down 25 | - Layer Height: 0.2 mm 26 | - Infill: 20% 27 | - Support: Everywhere 28 | - Support Overhang Angle: 70 29 | 30 | ![](bottom_screenshot.jpg) 31 | 32 | Setting the Support Overhang Angle to 70 ensures that the hole for the USB cable and the the press fit ridge are properly supported, but doesn't over-support everything. 33 | 34 | You can also download the case from Thingiverse: [FreeTouchDeck Case](https://www.thingiverse.com/thing:4661069) 35 | -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("FreeDeckWindows")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("FreeDeckWindows")] 13 | [assembly: AssemblyCopyright("Copyright © 2021")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("746af44d-8c58-48e2-ada6-97a412e566f6")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ESP32 source code/data/error.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | FreeTouchDeck Configurator 10 | 11 | 34 | 35 | 36 | 37 | 38 |
39 |

FreeTouchDeck Configurator

40 |
41 |
42 |

Oops! Something went wrong. The configurator returned the following error:
43 |

44 | %ERROR_CODE% : %ERROR_TEXT% 45 |

46 |
47 |
48 | 49 |
50 | 51 |
52 | 53 |
54 |
55 | 56 | 57 | -------------------------------------------------------------------------------- /ESP32 source code/data/editor.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | FreeTouchDeck Configurator 10 | 11 | 34 | 35 | 36 | 37 | 38 |
39 |

FreeTouchDeck Configurator

40 |
41 |
42 |

%RESULT% %TEXT% file(s) deleted.
43 |

44 | %FILES% 45 |
46 |
47 | 50 |
51 |
52 |
53 | 54 |
55 |

56 |
57 | 58 |
59 | 60 | 61 | -------------------------------------------------------------------------------- /ESP32 source code/user_setup.h Examples/ESP32_Dev_Kit_V1_ILI9488_Resistive.h: -------------------------------------------------------------------------------- 1 | /* This is a stripped down version of a User_Setup.h file for TFT_eSPI 2 | 3 | Copy the contents of this file to TFT_eSPI-master/User_setup.h 4 | 5 | This version is for a 38-pin ESP32 DevKitC and an ILI9488 screen with resistive touch controller. 6 | 7 | */ 8 | 9 | #define ILI9488_DRIVER // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high) 10 | 11 | #define TFT_BL 32 // LED back-light control pin 12 | #define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW) 13 | 14 | #define TFT_MISO 19 15 | #define TFT_MOSI 23 16 | #define TFT_SCLK 18 17 | #define TFT_CS 15 // Chip select control pin 18 | #define TFT_DC 2 // Data Command control pin 19 | #define TFT_RST 4 // Reset pin (could connect to RST pin) 20 | 21 | #define TOUCH_CS 21 // Chip select pin (T_CS) of touch screen 22 | 23 | #define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH 24 | #define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters 25 | #define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters 26 | #define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm 27 | #define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-. 28 | #define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-. 29 | 30 | #define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts 31 | 32 | #define SMOOTH_FONT 33 | 34 | #define SPI_FREQUENCY 27000000 35 | #define SPI_READ_FREQUENCY 20000000 36 | #define SPI_TOUCH_FREQUENCY 2500000 -------------------------------------------------------------------------------- /ESP32 source code/data/saveconfig.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | FreeTouchDeck Configurator 10 | 11 | 38 | 39 | 40 | 41 | 42 |
43 |

FreeTouchDeck Configurator

44 |
45 |
46 |

Configuration Saved! Go back to the configurator or click Restart to re-enable Bluetooth.

47 |
48 |
49 | 50 |
51 |
52 | 53 | 54 |

55 |
56 | 57 |
58 |
59 | 60 |
61 | 62 | 63 | -------------------------------------------------------------------------------- /ESP32 source code/Touch.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @brief This function presents the user with 4 points to touch and saves 3 | that data to a claibration file. 4 | * 5 | * @param none 6 | * 7 | * @return none 8 | * 9 | * @note If USECAPTOUCH is defined we do not need to calibrate touch 10 | */ 11 | void touch_calibrate() 12 | { 13 | uint16_t calData[5]; 14 | uint8_t calDataOK = 0; 15 | 16 | // check if calibration file exists and size is correct 17 | if (FILESYSTEM.exists(CALIBRATION_FILE)) 18 | { 19 | if (REPEAT_CAL) 20 | { 21 | // Delete if we want to re-calibrate 22 | FILESYSTEM.remove(CALIBRATION_FILE); 23 | } 24 | else 25 | { 26 | File f = FILESYSTEM.open(CALIBRATION_FILE, "r"); 27 | if (f) 28 | { 29 | if (f.readBytes((char *)calData, 14) == 14) 30 | calDataOK = 1; 31 | f.close(); 32 | } 33 | } 34 | } 35 | 36 | if (calDataOK && !REPEAT_CAL) 37 | { 38 | // calibration data valid 39 | tft.setTouch(calData); 40 | } 41 | else 42 | { 43 | // data not valid so recalibrate 44 | tft.fillScreen(TFT_BLACK); 45 | tft.setCursor(20, 0); 46 | tft.setTextFont(2); 47 | tft.setTextSize(1); 48 | tft.setTextColor(TFT_WHITE, TFT_BLACK); 49 | 50 | tft.println("Touch corners as indicated"); 51 | 52 | tft.setTextFont(1); 53 | tft.println(); 54 | 55 | if (REPEAT_CAL) 56 | { 57 | tft.setTextColor(TFT_RED, TFT_BLACK); 58 | tft.println("Set REPEAT_CAL to false to stop this running again!"); 59 | } 60 | 61 | tft.calibrateTouch(calData, TFT_MAGENTA, TFT_BLACK, 15); 62 | 63 | tft.setTextColor(TFT_GREEN, TFT_BLACK); 64 | tft.println("Calibration complete!"); 65 | 66 | // store data 67 | File f = FILESYSTEM.open(CALIBRATION_FILE, "w"); 68 | if (f) 69 | { 70 | f.write((const unsigned char *)calData, 14); 71 | f.close(); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/bin/Debug/Free Teams Deck.application: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | kQAEm8kE9dKgwuf4BWBxfklWEDHhgbwjeBIGJN6DH0I= 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/obj/Debug/Free Teams Deck.application: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | kQAEm8kE9dKgwuf4BWBxfklWEDHhgbwjeBIGJN6DH0I= 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/publish/Free Teams Deck.application: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | kQAEm8kE9dKgwuf4BWBxfklWEDHhgbwjeBIGJN6DH0I= 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/bin/Debug/app.publish/Free Teams Deck.application: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | kQAEm8kE9dKgwuf4BWBxfklWEDHhgbwjeBIGJN6DH0I= 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/publish/Application Files/Free Teams Deck_1_0_0_0/Free Teams Deck.application: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | kQAEm8kE9dKgwuf4BWBxfklWEDHhgbwjeBIGJN6DH0I= 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /ESP32 source code/README.md: -------------------------------------------------------------------------------- 1 | # FreeTouchDeck 2 | For interfacing with Windows/macOS/Linux using an ESP32, a touchscreen and BLE. 3 | 4 | ### [User guide](https://github.com/DustinWatts/FreeTouchDeck/wiki) 5 | 6 | # Delete the old clone and use the new 7 | 8 | ### Mixing files of different versions may cause some unexpected behavior! 9 | 10 | Important to realise is that since this is a beta version, changes to te code happen frequently. The FreeTouchDeck.ino and other files (for example in the data folder) rely on each other, they come as one. So when you download the new version, make sure that you only use the files that come with the current download, and not files from other versions. Best practise is to completely delete the old version and then download/clone the new version to make sure you do not accidently mix files from different versions. **After downloading/cloning the latest version, make sure to also upload the "data" folder again using 'ESP32 Sketch Data Upload".** 11 | 12 | # Beta Version! 13 | 14 | This version is in it's very early stages of development. Chances are that if you are not using the exact 15 | same setup as I am, you will run in to problems. But that is what this version is for: finding out what is needed 16 | to make FreeTouchDeck work across most ESP's and TFT screens. Also there is a lack of documentation which is gradually being written. 17 | 18 | # Hardware used 19 | 20 | The hardware I currenlty use is: 21 | 22 | For Resistive touch: 23 | - an ESP32 DEVKIT V1 (WROOM32) (Partition scheme: NO OTA with 2MB app and 2MB SPIFFS) 24 | - an 3.5" (480x320) TFT + Touchscreen with ILI9488 driver and XPT2046 resitive touch controller 25 | 26 | For Capacitive touch: 27 | - an ESP32 DEVKIT V1 (WROOM32) (Partition scheme: NO OTA with 2MB app and 2MB SPIFFS) 28 | - an 3.5" (480x320) TFT + Touchscreen with ILI9488 driver and FT6236 capacitive touch controller 29 | 30 | # !- Library Dependencies -! 31 | - Adafruit-GFX-Library (version 1.10.0), available through Library Manager 32 | - TFT_eSPI (version 2.2.14), available through Library Manager 33 | - ESP32-BLE-Keyboard (forked) (latest version) download from: https://github.com/DustinWatts/ESP32-BLE-Keyboard 34 | - ESPAsyncWebserver (latest version) download from: https://github.com/me-no-dev/ESPAsyncWebServer 35 | - AsyncTCP (latest version) download from: https://github.com/me-no-dev/AsyncTCP 36 | - ArduinoJson (version 6.16.1), available through Library Manager 37 | 38 | If you use capacitive touch: 39 | - FT6236 (latest version), download from: https://github.com/DustinWatts/FT6236 40 | 41 | # TFT_eSPI configuration 42 | 43 | Before compiling and uploading the FreeTouchDeck.ino sketch, you will have to edit the **user_setup.h** file included with the TFT_eSPI library. This can be found in your Arduino skechtbook folder under "libraries". If you have not renamed the TFT_eSPI library folder, the file **user_setup.h** can be found in **TFT_eSPI-master**. Here you will have to uncomment the lines that apply to you hardware configuration. For example: if you have an TFT with an ILI9488 driver, you will have to uncomment that line under `Section 1`. Make sure all the other drivers are commented out! 44 | 45 | The next section is `Section 2`. This also depends on what hardware you are using. For example for an ESP32 you'll have to uncomment the correct #define(s) under `EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP32 SETUP`. Also if your TFT has the blacklight control pin available you will have to uncomment the lines found under `#define TFT_BL` and `#define TFT_BACKLIGHT_ON`. 46 | 47 | "Section 3" can be left alone. 48 | 49 | # Help 50 | 51 | You can join my Discord server where I have a dedicated #freetouchdeck channel. https://discord.gg/RE3XevS 52 | -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/bin/Debug/Free Teams Deck.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | yMGrFH3gR4kOw26utDs3h3KDS3bqPZ+N2FDjqzEqZto= 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 3/SaG4z0MGkXQMEbj28j0Aj+V+qKIMfcTNk5zeAC1UI= 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | R+Wg8QGvQVHX8T0ta/qbhH1bXkqY0fRnS3wBV3J0bN8= 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | o6ZwcZ3iAyb1v4mcp375a5fr+vu/X22IMuU87H17G7E= 82 | 83 | 84 | -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/obj/Debug/Free Teams Deck.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | yMGrFH3gR4kOw26utDs3h3KDS3bqPZ+N2FDjqzEqZto= 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 3/SaG4z0MGkXQMEbj28j0Aj+V+qKIMfcTNk5zeAC1UI= 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | R+Wg8QGvQVHX8T0ta/qbhH1bXkqY0fRnS3wBV3J0bN8= 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | o6ZwcZ3iAyb1v4mcp375a5fr+vu/X22IMuU87H17G7E= 82 | 83 | 84 | -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/publish/Application Files/Free Teams Deck_1_0_0_0/Free Teams Deck.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | yMGrFH3gR4kOw26utDs3h3KDS3bqPZ+N2FDjqzEqZto= 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 3/SaG4z0MGkXQMEbj28j0Aj+V+qKIMfcTNk5zeAC1UI= 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | R+Wg8QGvQVHX8T0ta/qbhH1bXkqY0fRnS3wBV3J0bN8= 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | o6ZwcZ3iAyb1v4mcp375a5fr+vu/X22IMuU87H17G7E= 82 | 83 | 84 | -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/bin/Debug/app.publish/Application Files/Free Teams Deck_1_0_0_0/Free Teams Deck.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | yMGrFH3gR4kOw26utDs3h3KDS3bqPZ+N2FDjqzEqZto= 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 3/SaG4z0MGkXQMEbj28j0Aj+V+qKIMfcTNk5zeAC1UI= 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | R+Wg8QGvQVHX8T0ta/qbhH1bXkqY0fRnS3wBV3J0bN8= 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | o6ZwcZ3iAyb1v4mcp375a5fr+vu/X22IMuU87H17G7E= 82 | 83 | 84 | -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/FreeDeckWindows.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {746AF44D-8C58-48E2-ADA6-97A412E566F6} 8 | Exe 9 | FreeDeckWindows 10 | Free Teams Deck 11 | v4.7.2 12 | 512 13 | true 14 | true 15 | false 16 | publish\ 17 | true 18 | Disk 19 | false 20 | Foreground 21 | 7 22 | Days 23 | false 24 | false 25 | true 26 | https://teams.handsnontek.net/teamsdeck 27 | https://teams.handsnontek.net/teamsdeck 28 | en 29 | Free Teams Deck 30 | João Ferreira 31 | HANDS ON tek 32 | 0 33 | 1.0.0.0 34 | false 35 | true 36 | true 37 | 38 | 39 | AnyCPU 40 | true 41 | full 42 | false 43 | bin\Debug\ 44 | DEBUG;TRACE 45 | prompt 46 | 4 47 | 48 | 49 | AnyCPU 50 | pdbonly 51 | true 52 | bin\Release\ 53 | TRACE 54 | prompt 55 | 4 56 | 57 | 58 | Free Teams Deck.ico 59 | 60 | 61 | 3B5B150679797F19693495850BC0017754BF9F92 62 | 63 | 64 | FreeDeckWindows_TemporaryKey.pfx 65 | 66 | 67 | true 68 | 69 | 70 | false 71 | 72 | 73 | FreeDeck.FreeDeckWindows 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | False 101 | Microsoft .NET Framework 4.7.2 %28x86 and x64%29 102 | true 103 | 104 | 105 | False 106 | .NET Framework 3.5 SP1 107 | false 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /ESP32 source code/ConfigHelper.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @brief This function stops Bluetooth and connects to the given 3 | WiFi network. It the starts mDNS and starts the Async 4 | Webserver. 5 | * 6 | * @param none 7 | * 8 | * @return none 9 | * 10 | * @note none 11 | */ 12 | void configmode() 13 | { 14 | 15 | Serial.println("[INFO]: Entering Config Mode"); 16 | 17 | // Delete the task bleKeyboard had create to free memory and to not interfere with AsyncWebServer 18 | bleKeyboard.end(); 19 | 20 | // Stop BLE from interfering with our WIFI signal 21 | btStop(); 22 | esp_bt_controller_disable(); 23 | esp_bt_controller_deinit(); 24 | esp_bt_controller_mem_release(ESP_BT_MODE_BTDM); 25 | 26 | Serial.println("[INFO]: BLE Stopped"); 27 | 28 | if (String(wificonfig.ssid) == "YOUR_WIFI_SSID" || String(wificonfig.password) == "YOUR_WIFI_PASSWORD") // Still default 29 | { 30 | drawErrorMessage("WiFi Config still set to default!"); 31 | Serial.println("[ERROR]: WiFi Config still set to default!"); 32 | while (1) 33 | yield(); // Stop! 34 | } 35 | 36 | if (String(wificonfig.ssid) == "FAILED" || String(wificonfig.password) == "FAILED" || String(wificonfig.wifimode) == "FAILED") // The wificonfig.json failed to load 37 | { 38 | drawErrorMessage("WiFi Config Failed to load!"); 39 | Serial.println("[ERROR]: WiFi Config Failed to load!"); 40 | while (1) 41 | yield(); // Stop! 42 | } 43 | 44 | drawErrorMessage("Connecting to Wifi..."); 45 | 46 | Serial.printf("[INFO]: Connecting to %s", wificonfig.ssid); 47 | if (String(WiFi.SSID()) != String(wificonfig.ssid)) 48 | { 49 | if (strcmp(wificonfig.wifimode, "WIFI_STA") == 0) 50 | { 51 | WiFi.mode(WIFI_STA); 52 | WiFi.begin(wificonfig.ssid, wificonfig.password); 53 | while (WiFi.status() != WL_CONNECTED) 54 | { 55 | delay(500); 56 | Serial.print("."); 57 | } 58 | Serial.println(""); 59 | Serial.print("[INFO]: Connected! IP address: "); 60 | Serial.println(WiFi.localIP()); 61 | } 62 | else if (strcmp(wificonfig.wifimode, "WIFI_AP") == 0) 63 | { 64 | WiFi.mode(WIFI_AP); 65 | WiFi.softAP(wificonfig.ssid, wificonfig.password); 66 | Serial.println(""); 67 | Serial.print("[INFO]: Access Point Started! IP address: "); 68 | Serial.println(WiFi.softAPIP()); 69 | } 70 | } 71 | 72 | MDNS.begin(wificonfig.hostname); 73 | MDNS.addService("http", "tcp", 80); 74 | 75 | // Set pageNum to 7 so no buttons are displayed and touches are ignored 76 | pageNum = 7; 77 | 78 | // Start the webserver 79 | webserver.begin(); 80 | Serial.println("[INFO]: Webserver started"); 81 | } 82 | 83 | /** 84 | * @brief This function allows for saving (updating) the WiFi SSID 85 | * 86 | * @param String ssid 87 | * 88 | * @return boolean True if succeeded. False otherwise. 89 | * 90 | * @note Returns true if successful. To enable the new set SSID, you must reload the the 91 | configuration using loadMainConfig() 92 | */ 93 | bool saveWifiSSID(String ssid) 94 | { 95 | 96 | FILESYSTEM.remove("/config/wificonfig.json"); 97 | File file = FILESYSTEM.open("/config/wificonfig.json", "w"); 98 | 99 | DynamicJsonDocument doc(256); 100 | 101 | JsonObject wificonfigobject = doc.to(); 102 | 103 | wificonfigobject["ssid"] = ssid; 104 | wificonfigobject["password"] = wificonfig.password; 105 | wificonfigobject["wifimode"] = wificonfig.wifimode; 106 | wificonfigobject["wifihostname"] = wificonfig.hostname; 107 | wificonfigobject["sleepenable"] = wificonfig.sleepenable; 108 | wificonfigobject["sleeptimer"] = wificonfig.sleeptimer; 109 | 110 | if (serializeJsonPretty(doc, file) == 0) 111 | { 112 | Serial.println("[WARNING]: Failed to write to file"); 113 | return false; 114 | } 115 | file.close(); 116 | return true; 117 | } 118 | 119 | /** 120 | * @brief This function allows for saving (updating) the WiFi Password 121 | * 122 | * @param String password 123 | * 124 | * @return boolean True if succeeded. False otherwise. 125 | * 126 | * @note Returns true if successful. To enable the new set password, you must reload the the 127 | configuration using loadMainConfig() 128 | */ 129 | bool saveWifiPW(String password) 130 | { 131 | 132 | FILESYSTEM.remove("/config/wificonfig.json"); 133 | File file = FILESYSTEM.open("/config/wificonfig.json", "w"); 134 | 135 | DynamicJsonDocument doc(256); 136 | 137 | JsonObject wificonfigobject = doc.to(); 138 | 139 | wificonfigobject["ssid"] = wificonfig.ssid; 140 | wificonfigobject["password"] = password; 141 | wificonfigobject["wifimode"] = wificonfig.wifimode; 142 | wificonfigobject["wifihostname"] = wificonfig.hostname; 143 | wificonfigobject["sleepenable"] = wificonfig.sleepenable; 144 | wificonfigobject["sleeptimer"] = wificonfig.sleeptimer; 145 | 146 | if (serializeJsonPretty(doc, file) == 0) 147 | { 148 | Serial.println("[WARNING]: Failed to write to file"); 149 | return false; 150 | } 151 | file.close(); 152 | return true; 153 | } 154 | 155 | /** 156 | * @brief This function allows for saving (updating) the WiFi Mode 157 | * 158 | * @param String wifimode "WIFI_STA" of "WIFI_AP" 159 | * 160 | * @return boolean True if succeeded. False otherwise. 161 | * 162 | * @note Returns true if successful. To enable the new set WiFi Mode, you must reload the the 163 | configuration using loadMainConfig() 164 | */ 165 | bool saveWifiMode(String wifimode) 166 | { 167 | 168 | if (wifimode != "WIFI_STA" && wifimode != "WIFI_AP") 169 | { 170 | Serial.println("[WARNING]: WiFi Mode not supported. Try WIFI_STA of WIFI_AP."); 171 | return false; 172 | } 173 | 174 | FILESYSTEM.remove("/config/wificonfig.json"); 175 | File file = FILESYSTEM.open("/config/wificonfig.json", "w"); 176 | 177 | DynamicJsonDocument doc(256); 178 | 179 | JsonObject wificonfigobject = doc.to(); 180 | 181 | wificonfigobject["ssid"] = wificonfig.ssid; 182 | wificonfigobject["password"] = wificonfig.password; 183 | wificonfigobject["wifimode"] = wifimode; 184 | wificonfigobject["wifihostname"] = wificonfig.hostname; 185 | wificonfigobject["sleepenable"] = wificonfig.sleepenable; 186 | wificonfigobject["sleeptimer"] = wificonfig.sleeptimer; 187 | 188 | if (serializeJsonPretty(doc, file) == 0) 189 | { 190 | Serial.println("[WARNING]: Failed to write to file"); 191 | return false; 192 | } 193 | file.close(); 194 | return true; 195 | } 196 | 197 | /** 198 | * @brief This function checks if a file exists and returns a boolean accordingly. 199 | It then prints a debug message to the serial as wel as the tft. 200 | * 201 | * @param filename (const char *) 202 | * 203 | * @return boolean True if succeeded. False otherwise. 204 | * 205 | * @note Pass the filename including a leading / 206 | */ 207 | bool checkfile(const char *filename) 208 | { 209 | 210 | if (!FILESYSTEM.exists(filename)) 211 | { 212 | tft.fillScreen(TFT_BLACK); 213 | tft.setCursor(1, 3); 214 | tft.setTextFont(2); 215 | tft.setTextSize(2); 216 | tft.setTextColor(TFT_WHITE, TFT_BLACK); 217 | tft.printf("%s not found!\n\n", filename); 218 | tft.setTextSize(1); 219 | tft.printf("If this has happend after confguration, the data on the ESP may \nbe corrupted."); 220 | return false; 221 | } 222 | else 223 | { 224 | return true; 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /Teams Deck source code/FreeDeckWindows/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO.Ports; 5 | using System.Linq; 6 | using System.Runtime.InteropServices; 7 | using System.Text; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | using System.Windows.Forms; 11 | 12 | namespace FreeDeck 13 | { 14 | class FreeDeckWindows 15 | { 16 | [DllImport("user32.dll")] 17 | static extern IntPtr GetForegroundWindow(); 18 | [DllImport("user32.dll")] 19 | static extern bool SetForegroundWindow(IntPtr hWnd); 20 | [DllImport("user32.dll")] 21 | private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow); 22 | 23 | [return: MarshalAs(UnmanagedType.Bool)] 24 | 25 | 26 | SerialPort sp; 27 | Boolean init = false; 28 | 29 | static void Main(string[] args) 30 | { 31 | Console.Title = "Free Teams Deck"; 32 | //Open the Program function 33 | new FreeDeckWindows(); 34 | 35 | } 36 | 37 | 38 | private FreeDeckWindows() 39 | { 40 | Console.ForegroundColor = ConsoleColor.DarkGray; 41 | 42 | Console.WriteLine(" "); 43 | Console.WriteLine(" &&&&&&&&&& "); 44 | Console.WriteLine(" &&& &&& &&&&&& Microsoft Teams Deck"); 45 | Console.WriteLine(" &&& &&& && && "); 46 | Console.WriteLine(" &&&&&&&&&&&&&&&&&&&&&&&&& &&&&&& Control Microsoft Teams from your Free Touch Deck"); 47 | Console.WriteLine(" &&&& &&&&& #FreeTeamsDeck"); 48 | Console.WriteLine(" &&&& &&&&&&&&&&&&&&&&&&&&&&&& "); 49 | Console.WriteLine(" &&&&&&&& &&&&&&&&& && && "); 50 | Console.WriteLine(" &&&&&&&& &&&&&&&&& && && "); 51 | Console.WriteLine(" &&&&&&&& &&&&&&&&& && && "); 52 | Console.WriteLine(" &&&&&&&& &&&&&&&&& && && Application developed by:"); 53 | Console.WriteLine(" &&&&&&&&&&&&&&&&&& && && João Ferreira"); 54 | Console.WriteLine(" &&& &&&&&&&&& https://teams.handsnontek.net/teamsdeck"); 55 | Console.WriteLine(" &&& &&& "); 56 | Console.WriteLine(" &&&&&&&&&&&&&& "); 57 | Console.WriteLine(" "); 58 | 59 | 60 | Console.ResetColor(); 61 | 62 | //Serial communication parameters 63 | Console.Write(" COM Port Number: "); 64 | string comPort = Console.ReadLine(); 65 | Console.Write(" Bound Rate: "); 66 | int boundRate = int.Parse(Console.ReadLine()); 67 | Console.Write(" Status: "); 68 | 69 | 70 | 71 | //Set the datareceived event handler 72 | try 73 | { 74 | sp = new SerialPort("COM" + comPort, boundRate, Parity.None, 8, StopBits.One); 75 | sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived); 76 | //Open the serial port 77 | sp.Open(); 78 | 79 | Console.ForegroundColor = ConsoleColor.DarkGreen; 80 | Console.WriteLine("Connected"); 81 | Console.ResetColor(); 82 | Console.WriteLine(""); 83 | Console.Write(" To control Microsoft Teams when the application is not in focus, keep this window open"); 84 | } 85 | catch(Exception ex) 86 | { 87 | Console.ForegroundColor = ConsoleColor.DarkRed; 88 | Console.WriteLine("Unable to connect to Free Touch Deck"); 89 | Console.ResetColor(); 90 | Console.WriteLine(""); 91 | Console.Write(" To learn how to connect to Free Touch Deck visit - https://teams.handsnontek.net/teamsdeck"); 92 | } 93 | 94 | 95 | 96 | //Read from the console, to stop it from closing. 97 | Console.Read(); 98 | 99 | } 100 | 101 | 102 | private void sp_DataReceived(object sender, SerialDataReceivedEventArgs e) 103 | { 104 | IntPtr currentWindow = GetForegroundWindow(); 105 | 106 | try 107 | { 108 | //Variables 109 | string serialValue = sp.ReadLine(); 110 | IntPtr teamsWindow = IntPtr.Zero; 111 | string menu = serialValue.Replace("\r", ""); 112 | 113 | 114 | //Get the main Teams process of Microsoft Teams 115 | Process[] processes = Process.GetProcessesByName("Teams"); 116 | for (int i = 0; i < processes.Length; i++) 117 | { 118 | if (processes[i].MainWindowHandle.ToString() != "0") 119 | { 120 | teamsWindow = processes[i].MainWindowHandle; 121 | if(currentWindow == teamsWindow) 122 | { 123 | //Teams is already the Window in focus 124 | return; 125 | } 126 | } 127 | } 128 | 129 | 130 | 131 | //Loop through the menu options to make and send the keys 132 | switch (menu) 133 | { 134 | case "Menu2": 135 | ShowWindowAsync(teamsWindow, 1); 136 | SetForegroundWindow(teamsWindow); 137 | break; 138 | case "Menu2-0": 139 | ShowWindowAsync(teamsWindow, 1); 140 | SetForegroundWindow(teamsWindow); 141 | SendKeys.SendWait("^+(M)"); 142 | break; 143 | case "Menu2-1": 144 | ShowWindowAsync(teamsWindow, 1); 145 | SetForegroundWindow(teamsWindow); 146 | SendKeys.SendWait("^+(O)"); 147 | break; 148 | case "Menu2-2": 149 | ShowWindowAsync(teamsWindow, 1); 150 | SetForegroundWindow(teamsWindow); 151 | SendKeys.SendWait("^+(E)"); 152 | break; 153 | case "Menu2-3": 154 | ShowWindowAsync(teamsWindow, 1); 155 | SetForegroundWindow(teamsWindow); 156 | SendKeys.SendWait("^+(K)"); 157 | break; 158 | case "Menu2-4": 159 | ShowWindowAsync(teamsWindow, 1); 160 | SetForegroundWindow(teamsWindow); 161 | SendKeys.SendWait("^+(B)"); 162 | break; 163 | } 164 | 165 | } 166 | catch (Exception ex) 167 | { 168 | //if there is no internet 169 | } 170 | } 171 | 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /ESP32 source code/Action.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @brief This function takes an int as an action and value. It uses 3 | a switch statement to determine which type of action to do. 4 | e.g. write, print, press. 5 | * 6 | * @param action int 7 | * @param value int 8 | * @param symbol char * 9 | * 10 | * @return none 11 | * 12 | * @note Case 9 is used for special functions, none bleKeyboard related. 13 | */ 14 | void bleKeyboardAction(int action, int value, char *symbol) 15 | { 16 | 17 | Serial.println("[INFO]: BLE Keyboard action received"); 18 | switch (action) 19 | { 20 | case 0: 21 | // No Action 22 | break; 23 | case 1: // Delay 24 | delay(value); 25 | break; 26 | case 2: // Send TAB ARROW etc 27 | switch (value) 28 | { 29 | case 1: 30 | bleKeyboard.write(KEY_UP_ARROW); 31 | break; 32 | case 2: 33 | bleKeyboard.write(KEY_DOWN_ARROW); 34 | break; 35 | case 3: 36 | bleKeyboard.write(KEY_LEFT_ARROW); 37 | break; 38 | case 4: 39 | bleKeyboard.write(KEY_RIGHT_ARROW); 40 | break; 41 | case 5: 42 | bleKeyboard.write(KEY_BACKSPACE); 43 | break; 44 | case 6: 45 | bleKeyboard.write(KEY_TAB); 46 | break; 47 | case 7: 48 | bleKeyboard.write(KEY_RETURN); 49 | break; 50 | case 8: 51 | bleKeyboard.write(KEY_PAGE_UP); 52 | break; 53 | case 9: 54 | bleKeyboard.write(KEY_PAGE_DOWN); 55 | break; 56 | default: 57 | //if nothing matches do nothing 58 | break; 59 | } 60 | break; 61 | case 3: // Send Media Key 62 | switch (value) 63 | { 64 | case 1: 65 | bleKeyboard.write(KEY_MEDIA_MUTE); 66 | break; 67 | case 2: 68 | bleKeyboard.write(KEY_MEDIA_VOLUME_DOWN); 69 | break; 70 | case 3: 71 | bleKeyboard.write(KEY_MEDIA_VOLUME_UP); 72 | break; 73 | case 4: 74 | bleKeyboard.write(KEY_MEDIA_PLAY_PAUSE); 75 | break; 76 | case 5: 77 | bleKeyboard.write(KEY_MEDIA_STOP); 78 | break; 79 | case 6: 80 | bleKeyboard.write(KEY_MEDIA_NEXT_TRACK); 81 | break; 82 | case 7: 83 | bleKeyboard.write(KEY_MEDIA_PREVIOUS_TRACK); 84 | break; 85 | default: 86 | //if nothing matches do nothing 87 | break; 88 | } 89 | break; 90 | case 4: // Send Character 91 | bleKeyboard.print(symbol); 92 | break; 93 | case 5: // Option Keys 94 | switch (value) 95 | { 96 | case 1: 97 | bleKeyboard.press(KEY_LEFT_CTRL); 98 | break; 99 | case 2: 100 | bleKeyboard.press(KEY_LEFT_SHIFT); 101 | break; 102 | case 3: 103 | bleKeyboard.press(KEY_LEFT_ALT); 104 | break; 105 | case 4: 106 | bleKeyboard.press(KEY_LEFT_GUI); 107 | break; 108 | case 5: 109 | bleKeyboard.press(KEY_RIGHT_CTRL); 110 | break; 111 | case 6: 112 | bleKeyboard.press(KEY_RIGHT_SHIFT); 113 | break; 114 | case 7: 115 | bleKeyboard.press(KEY_RIGHT_ALT); 116 | break; 117 | case 8: 118 | bleKeyboard.press(KEY_RIGHT_GUI); 119 | break; 120 | case 9: 121 | bleKeyboard.releaseAll(); 122 | break; 123 | default: 124 | //if nothing matches do nothing 125 | break; 126 | } 127 | break; 128 | case 6: // Function Keys 129 | switch (value) 130 | { 131 | case 1: 132 | bleKeyboard.press(KEY_F1); 133 | break; 134 | case 2: 135 | bleKeyboard.press(KEY_F2); 136 | break; 137 | case 3: 138 | bleKeyboard.press(KEY_F3); 139 | break; 140 | case 4: 141 | bleKeyboard.press(KEY_F4); 142 | break; 143 | case 5: 144 | bleKeyboard.press(KEY_F5); 145 | break; 146 | case 6: 147 | bleKeyboard.press(KEY_F6); 148 | break; 149 | case 7: 150 | bleKeyboard.press(KEY_F7); 151 | break; 152 | case 8: 153 | bleKeyboard.press(KEY_F8); 154 | break; 155 | case 9: 156 | bleKeyboard.press(KEY_F9); 157 | break; 158 | case 10: 159 | bleKeyboard.press(KEY_F10); 160 | break; 161 | case 11: 162 | bleKeyboard.press(KEY_F11); 163 | break; 164 | case 12: 165 | bleKeyboard.press(KEY_F12); 166 | break; 167 | case 13: 168 | bleKeyboard.press(KEY_F13); 169 | break; 170 | case 14: 171 | bleKeyboard.press(KEY_F14); 172 | break; 173 | case 15: 174 | bleKeyboard.press(KEY_F15); 175 | break; 176 | case 16: 177 | bleKeyboard.press(KEY_F16); 178 | break; 179 | case 17: 180 | bleKeyboard.press(KEY_F17); 181 | break; 182 | case 18: 183 | bleKeyboard.press(KEY_F18); 184 | break; 185 | case 19: 186 | bleKeyboard.press(KEY_F19); 187 | break; 188 | case 20: 189 | bleKeyboard.press(KEY_F20); 190 | break; 191 | case 21: 192 | bleKeyboard.press(KEY_F21); 193 | break; 194 | case 22: 195 | bleKeyboard.press(KEY_F22); 196 | break; 197 | case 23: 198 | bleKeyboard.press(KEY_F23); 199 | break; 200 | case 24: 201 | bleKeyboard.press(KEY_F24); 202 | break; 203 | default: 204 | //if nothing matches do nothing 205 | break; 206 | } 207 | break; 208 | case 7: // Send Number 209 | bleKeyboard.print(value); 210 | break; 211 | case 8: // Send Special Character 212 | bleKeyboard.print(symbol); 213 | break; 214 | case 9: // Combos 215 | switch (value) 216 | { 217 | case 1: 218 | bleKeyboard.press(KEY_LEFT_CTRL); 219 | bleKeyboard.press(KEY_LEFT_SHIFT); 220 | break; 221 | case 2: 222 | bleKeyboard.press(KEY_LEFT_ALT); 223 | bleKeyboard.press(KEY_LEFT_SHIFT); 224 | break; 225 | case 3: 226 | bleKeyboard.press(KEY_LEFT_GUI); 227 | bleKeyboard.press(KEY_LEFT_SHIFT); 228 | break; 229 | case 4: 230 | bleKeyboard.press(KEY_LEFT_CTRL); 231 | bleKeyboard.press(KEY_LEFT_GUI); 232 | break; 233 | case 5: 234 | bleKeyboard.press(KEY_LEFT_ALT); 235 | bleKeyboard.press(KEY_LEFT_GUI); 236 | break; 237 | case 6: 238 | bleKeyboard.press(KEY_LEFT_CTRL); 239 | bleKeyboard.press(KEY_LEFT_ALT); 240 | break; 241 | case 7: 242 | bleKeyboard.press(KEY_LEFT_CTRL); 243 | bleKeyboard.press(KEY_LEFT_ALT); 244 | bleKeyboard.press(KEY_LEFT_GUI); 245 | break; 246 | case 8: 247 | bleKeyboard.press(KEY_RIGHT_CTRL); 248 | bleKeyboard.press(KEY_RIGHT_SHIFT); 249 | break; 250 | case 9: 251 | bleKeyboard.press(KEY_RIGHT_ALT); 252 | bleKeyboard.press(KEY_RIGHT_SHIFT); 253 | break; 254 | case 10: 255 | bleKeyboard.press(KEY_RIGHT_GUI); 256 | bleKeyboard.press(KEY_RIGHT_SHIFT); 257 | break; 258 | case 11: 259 | bleKeyboard.press(KEY_RIGHT_CTRL); 260 | bleKeyboard.press(KEY_RIGHT_GUI); 261 | break; 262 | case 12: 263 | bleKeyboard.press(KEY_RIGHT_ALT); 264 | bleKeyboard.press(KEY_RIGHT_GUI); 265 | break; 266 | case 13: 267 | bleKeyboard.press(KEY_RIGHT_CTRL); 268 | bleKeyboard.press(KEY_RIGHT_ALT); 269 | break; 270 | case 14: 271 | bleKeyboard.press(KEY_RIGHT_CTRL); 272 | bleKeyboard.press(KEY_RIGHT_ALT); 273 | bleKeyboard.press(KEY_RIGHT_GUI); 274 | break; 275 | } 276 | break; 277 | case 10: // future feature 278 | break; 279 | case 11: // Special functions 280 | switch (value) 281 | { 282 | case 1: // Enter config mode 283 | pageNum = 7; // By setting pageNum to 7 284 | configmode(); 285 | drawKeypad(); // and calling drawKeypad() a new keypad is drawn with pageNum 7 286 | break; 287 | case 2: // Display Brightness Down 288 | if (ledBrightness > 25) 289 | { 290 | ledBrightness = ledBrightness - 25; 291 | ledcWrite(0, ledBrightness); 292 | } 293 | break; 294 | case 3: // Display Brightness Up 295 | if (ledBrightness < 230) 296 | { 297 | ledBrightness = ledBrightness + 25; 298 | ledcWrite(0, ledBrightness); 299 | } 300 | break; 301 | case 4: // Sleep Enabled 302 | if (wificonfig.sleepenable) 303 | { 304 | wificonfig.sleepenable = false; 305 | Serial.println("[INFO]: Sleep disabled."); 306 | } 307 | else 308 | { 309 | wificonfig.sleepenable = true; 310 | Interval = wificonfig.sleeptimer * 60000; 311 | Serial.println("[INFO]: Sleep enabled."); 312 | Serial.print("[INFO]: Timer set to: "); 313 | Serial.println(wificonfig.sleeptimer); 314 | } 315 | break; 316 | } 317 | break; 318 | default: 319 | //If nothing matches do nothing 320 | break; 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /ESP32 source code/user_setup.h Examples/Makerfabs_Capacitive_Touch_User_Setup.h: -------------------------------------------------------------------------------- 1 | // USER DEFINED SETTINGS 2 | // Set driver type, fonts to be loaded, pins used and SPI control method etc 3 | // 4 | // See the User_Setup_Select.h file if you wish to be able to define multiple 5 | // setups and then easily select which setup file is used by the compiler. 6 | // 7 | // If this file is edited correctly then all the library example sketches should 8 | // run without the need to make any more changes for a particular hardware setup! 9 | // Note that some sketches are designed for a particular TFT pixel width/height 10 | 11 | 12 | // ################################################################################## 13 | // 14 | // Section 1. Call up the right driver file and any options for it 15 | // 16 | // ################################################################################## 17 | 18 | // Define STM32 to invoke optimised processor support (only for STM32) 19 | //#define STM32 20 | 21 | // Defining the STM32 board allows the library to optimise the performance 22 | // for UNO compatible "MCUfriend" style shields 23 | //#define NUCLEO_64_TFT 24 | //#define NUCLEO_144_TFT 25 | 26 | // STM32 8 bit parallel only: 27 | // If STN32 Port A or B pins 0-7 are used for 8 bit parallel data bus bits 0-7 28 | // then this will improve rendering performance by a factor of ~8x 29 | //#define STM_PORTA_DATA_BUS 30 | //#define STM_PORTA_DATA_BUS 31 | 32 | // Tell the library to use 8 bit parallel mode (otherwise SPI is assumed) 33 | //#define TFT_PARALLEL_8_BIT 34 | 35 | // Display type - only define if RPi display 36 | //#define RPI_DISPLAY_TYPE // 20MHz maximum SPI 37 | 38 | // Only define one driver, the other ones must be commented out 39 | //#define ILI9341_DRIVER 40 | //#define ST7735_DRIVER // Define additional parameters below for this display 41 | //#define ILI9163_DRIVER // Define additional parameters below for this display 42 | //#define S6D02A1_DRIVER 43 | //#define RPI_ILI9486_DRIVER // 20MHz maximum SPI 44 | //#define HX8357D_DRIVER 45 | //#define ILI9481_DRIVER 46 | //#define ILI9486_DRIVER 47 | #define ILI9488_DRIVER // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high) 48 | //#define ST7789_DRIVER // Full configuration option, define additional parameters below for this display 49 | //#define ST7789_2_DRIVER // Minimal configuration option, define additional parameters below for this display 50 | //#define R61581_DRIVER 51 | //#define RM68140_DRIVER 52 | //#define ST7796_DRIVER 53 | 54 | // Some displays support SPI reads via the MISO pin, other displays have a single 55 | // bi-directional SDA pin and the library will try to read this via the MOSI line. 56 | // To use the SDA line for reading data from the TFT uncomment the following line: 57 | 58 | // #define TFT_SDA_READ // This option is for ESP32 ONLY, tested with ST7789 display only 59 | 60 | // For ST7789 and ILI9341 ONLY, define the colour order IF the blue and red are swapped on your display 61 | // Try ONE option at a time to find the correct colour order for your display 62 | 63 | // #define TFT_RGB_ORDER TFT_RGB // Colour order Red-Green-Blue 64 | // #define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red 65 | 66 | // For M5Stack ESP32 module with integrated ILI9341 display ONLY, remove // in line below 67 | 68 | // #define M5STACK 69 | 70 | // For ST7789, ST7735 and ILI9163 ONLY, define the pixel width and height in portrait orientation 71 | // #define TFT_WIDTH 80 72 | // #define TFT_WIDTH 128 73 | // #define TFT_WIDTH 240 // ST7789 240 x 240 and 240 x 320 74 | // #define TFT_HEIGHT 160 75 | // #define TFT_HEIGHT 128 76 | // #define TFT_HEIGHT 240 // ST7789 240 x 240 77 | // #define TFT_HEIGHT 320 // ST7789 240 x 320 78 | 79 | // For ST7735 ONLY, define the type of display, originally this was based on the 80 | // colour of the tab on the screen protector film but this is not always true, so try 81 | // out the different options below if the screen does not display graphics correctly, 82 | // e.g. colours wrong, mirror images, or tray pixels at the edges. 83 | // Comment out ALL BUT ONE of these options for a ST7735 display driver, save this 84 | // this User_Setup file, then rebuild and upload the sketch to the board again: 85 | 86 | // #define ST7735_INITB 87 | // #define ST7735_GREENTAB 88 | // #define ST7735_GREENTAB2 89 | // #define ST7735_GREENTAB3 90 | // #define ST7735_GREENTAB128 // For 128 x 128 display 91 | // #define ST7735_GREENTAB160x80 // For 160 x 80 display (BGR, inverted, 26 offset) 92 | // #define ST7735_REDTAB 93 | // #define ST7735_BLACKTAB 94 | // #define ST7735_REDTAB160x80 // For 160 x 80 display with 24 pixel offset 95 | 96 | // If colours are inverted (white shows as black) then uncomment one of the next 97 | // 2 lines try both options, one of the options should correct the inversion. 98 | 99 | // #define TFT_INVERSION_ON 100 | // #define TFT_INVERSION_OFF 101 | 102 | 103 | // ################################################################################## 104 | // 105 | // Section 2. Define the pins that are used to interface with the display here 106 | // 107 | // ################################################################################## 108 | 109 | // If a backlight control signal is available then define the TFT_BL pin in Section 2 110 | // below. The backlight will be turned ON when tft.begin() is called, but the library 111 | // needs to know if the LEDs are ON with the pin HIGH or LOW. If the LEDs are to be 112 | // driven with a PWM signal or turned OFF/ON then this must be handled by the user 113 | // sketch. e.g. with digitalWrite(TFT_BL, LOW); 114 | 115 | // #define TFT_BL 32 // LED back-light control pin 116 | // #define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW) 117 | 118 | 119 | 120 | // We must use hardware SPI, a minimum of 3 GPIO pins is needed. 121 | // Typical setup for ESP8266 NodeMCU ESP-12 is : 122 | // 123 | // Display SDO/MISO to NodeMCU pin D6 (or leave disconnected if not reading TFT) 124 | // Display LED to NodeMCU pin VIN (or 5V, see below) 125 | // Display SCK to NodeMCU pin D5 126 | // Display SDI/MOSI to NodeMCU pin D7 127 | // Display DC (RS/AO)to NodeMCU pin D3 128 | // Display RESET to NodeMCU pin D4 (or RST, see below) 129 | // Display CS to NodeMCU pin D8 (or GND, see below) 130 | // Display GND to NodeMCU pin GND (0V) 131 | // Display VCC to NodeMCU 5V or 3.3V 132 | // 133 | // The TFT RESET pin can be connected to the NodeMCU RST pin or 3.3V to free up a control pin 134 | // 135 | // The DC (Data Command) pin may be labeled AO or RS (Register Select) 136 | // 137 | // With some displays such as the ILI9341 the TFT CS pin can be connected to GND if no more 138 | // SPI devices (e.g. an SD Card) are connected, in this case comment out the #define TFT_CS 139 | // line below so it is NOT defined. Other displays such at the ST7735 require the TFT CS pin 140 | // to be toggled during setup, so in these cases the TFT_CS line must be defined and connected. 141 | // 142 | // The NodeMCU D0 pin can be used for RST 143 | // 144 | // 145 | // Note: only some versions of the NodeMCU provide the USB 5V on the VIN pin 146 | // If 5V is not available at a pin you can use 3.3V but backlight brightness 147 | // will be lower. 148 | 149 | 150 | // ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP8266 SETUP ###### 151 | 152 | // For NodeMCU - use pin numbers in the form PIN_Dx where Dx is the NodeMCU pin designation 153 | //#define TFT_CS PIN_D8 // Chip select control pin D8 154 | //#define TFT_DC PIN_D3 // Data Command control pin 155 | //#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line) 156 | //#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V 157 | 158 | //#define TFT_BL PIN_D1 // LED back-light (only for ST7789 with backlight control pin) 159 | 160 | //#define TOUCH_CS PIN_D2 // Chip select pin (T_CS) of touch screen 161 | 162 | //#define TFT_WR PIN_D2 // Write strobe for modified Raspberry Pi TFT only 163 | 164 | 165 | // ###### FOR ESP8266 OVERLAP MODE EDIT THE PIN NUMBERS IN THE FOLLOWING LINES ###### 166 | 167 | // Overlap mode shares the ESP8266 FLASH SPI bus with the TFT so has a performance impact 168 | // but saves pins for other functions. It is best not to connect MISO as some displays 169 | // do not tristate that line wjen chip select is high! 170 | // On NodeMCU 1.0 SD0=MISO, SD1=MOSI, CLK=SCLK to connect to TFT in overlap mode 171 | // On NodeMCU V3 S0 =MISO, S1 =MOSI, S2 =SCLK 172 | // In ESP8266 overlap mode the following must be defined 173 | 174 | //#define TFT_SPI_OVERLAP 175 | 176 | // In ESP8266 overlap mode the TFT chip select MUST connect to pin D3 177 | //#define TFT_CS PIN_D3 178 | //#define TFT_DC PIN_D5 // Data Command control pin 179 | //#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line) 180 | //#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V 181 | 182 | 183 | // ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP32 SETUP ###### 184 | 185 | // For ESP32 Dev board (only tested with ILI9341 display) 186 | // The hardware SPI can be mapped to any pins 187 | 188 | #define TFT_MISO 12 189 | #define TFT_MOSI 13 190 | #define TFT_SCLK 14 191 | #define TFT_CS 15 // Chip select control pin 192 | #define TFT_DC 33 // Data Command control pin 193 | //#define TFT_RST 26 // Reset pin (could connect to RST pin) 194 | #define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST 195 | 196 | #define TOUCH_CS 35 // Chip select pin (T_CS) of touch screen 197 | 198 | //#define TFT_WR 22 // Write strobe for modified Raspberry Pi TFT only 199 | 200 | // For the M5Stack module use these #define lines 201 | //#define TFT_MISO 19 202 | //#define TFT_MOSI 23 203 | //#define TFT_SCLK 18 204 | //#define TFT_CS 14 // Chip select control pin 205 | //#define TFT_DC 27 // Data Command control pin 206 | //#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin) 207 | //#define TFT_BL 32 // LED back-light (required for M5Stack) 208 | 209 | // ###### EDIT THE PINs BELOW TO SUIT YOUR ESP32 PARALLEL TFT SETUP ###### 210 | 211 | // The library supports 8 bit parallel TFTs with the ESP32, the pin 212 | // selection below is compatible with ESP32 boards in UNO format. 213 | // Wemos D32 boards need to be modified, see diagram in Tools folder. 214 | // Only ILI9481 and ILI9341 based displays have been tested! 215 | 216 | // Parallel bus is only supported for the STM32 and ESP32 217 | // Example below is for ESP32 Parallel interface with UNO displays 218 | 219 | // Tell the library to use 8 bit parallel mode (otherwise SPI is assumed) 220 | //#define TFT_PARALLEL_8_BIT 221 | 222 | // The ESP32 and TFT the pins used for testing are: 223 | //#define TFT_CS 33 // Chip select control pin (library pulls permanently low 224 | //#define TFT_DC 15 // Data Command control pin - must use a pin in the range 0-31 225 | //#define TFT_RST 32 // Reset pin, toggles on startup 226 | 227 | //#define TFT_WR 4 // Write strobe control pin - must use a pin in the range 0-31 228 | //#define TFT_RD 2 // Read strobe control pin 229 | 230 | //#define TFT_D0 12 // Must use pins in the range 0-31 for the data bus 231 | //#define TFT_D1 13 // so a single register write sets/clears all bits. 232 | //#define TFT_D2 26 // Pins can be randomly assigned, this does not affect 233 | //#define TFT_D3 25 // TFT screen update performance. 234 | //#define TFT_D4 17 235 | //#define TFT_D5 16 236 | //#define TFT_D6 27 237 | //#define TFT_D7 14 238 | 239 | 240 | // ################################################################################## 241 | // 242 | // Section 3. Define the fonts that are to be used here 243 | // 244 | // ################################################################################## 245 | 246 | // Comment out the #defines below with // to stop that font being loaded 247 | // The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not 248 | // normally necessary. If all fonts are loaded the extra FLASH space required is 249 | // about 17Kbytes. To save FLASH space only enable the fonts you need! 250 | 251 | #define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH 252 | #define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters 253 | #define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters 254 | #define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm 255 | #define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-. 256 | #define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-. 257 | //#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT 258 | #define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts 259 | 260 | // Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded 261 | // this will save ~20kbytes of FLASH 262 | #define SMOOTH_FONT 263 | 264 | 265 | // ################################################################################## 266 | // 267 | // Section 4. Other options 268 | // 269 | // ################################################################################## 270 | 271 | // Define the SPI clock frequency, this affects the graphics rendering speed. Too 272 | // fast and the TFT driver will not keep up and display corruption appears. 273 | // With an ILI9341 display 40MHz works OK, 80MHz sometimes fails 274 | // With a ST7735 display more than 27MHz may not work (spurious pixels and lines) 275 | // With an ILI9163 display 27 MHz works OK. 276 | 277 | // #define SPI_FREQUENCY 1000000 278 | // #define SPI_FREQUENCY 5000000 279 | // #define SPI_FREQUENCY 10000000 280 | // #define SPI_FREQUENCY 20000000 281 | #define SPI_FREQUENCY 27000000 // Actually sets it to 26.67MHz = 80/3 282 | // #define SPI_FREQUENCY 40000000 283 | // #define SPI_FREQUENCY 80000000 284 | 285 | // Optional reduced SPI frequency for reading TFT 286 | #define SPI_READ_FREQUENCY 20000000 287 | 288 | // The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here: 289 | #define SPI_TOUCH_FREQUENCY 2500000 290 | 291 | // The ESP32 has 2 free SPI ports i.e. VSPI and HSPI, the VSPI is the default. 292 | // If the VSPI port is in use and pins are not accessible (e.g. TTGO T-Beam) 293 | // then uncomment the following line: 294 | //#define USE_HSPI_PORT 295 | 296 | // Comment out the following #define if "SPI Transactions" do not need to be 297 | // supported. When commented out the code size will be smaller and sketches will 298 | // run slightly faster, so leave it commented out unless you need it! 299 | 300 | // Transaction support is needed to work with SD library but not needed with TFT_SdFat 301 | // Transaction support is required if other SPI devices are connected. 302 | 303 | // Transactions are automatically enabled by the library for an ESP32 (to use HAL mutex) 304 | // so changing it here has no effect 305 | 306 | // #define SUPPORT_TRANSACTIONS 307 | -------------------------------------------------------------------------------- /ESP32 source code/ScreenHelper.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @brief This function reads chuncks of 2 bytes of data from a 3 | file and returns the data. 4 | * 5 | * @param &f 6 | * 7 | * @return uint16_t 8 | * 9 | * @note litte-endian 10 | */ 11 | uint16_t read16(fs::File &f) 12 | { 13 | uint16_t result; 14 | ((uint8_t *)&result)[0] = f.read(); // LSB 15 | ((uint8_t *)&result)[1] = f.read(); // MSB 16 | return result; 17 | } 18 | 19 | /** 20 | * @brief This function reads chuncks of 4 bytes of data from a 21 | file and returns the data. 22 | * 23 | * @param &f 24 | * 25 | * @return uint32_t 26 | * 27 | * @note litte-endian 28 | */ 29 | uint32_t read32(fs::File &f) 30 | { 31 | uint32_t result; 32 | ((uint8_t *)&result)[0] = f.read(); // LSB 33 | ((uint8_t *)&result)[1] = f.read(); 34 | ((uint8_t *)&result)[2] = f.read(); 35 | ((uint8_t *)&result)[3] = f.read(); // MSB 36 | return result; 37 | } 38 | 39 | /** 40 | * @brief This functions accepts a HTML including the # colour code 41 | (eg. #FF00FF) and returns it in RGB888 format. 42 | * 43 | * @param *html char (including #) 44 | * 45 | * @return unsigned long 46 | * 47 | * @note none 48 | */ 49 | unsigned long convertHTMLtoRGB888(char *html) 50 | { 51 | char *hex = html + 1; // remove the # 52 | unsigned long rgb = strtoul(hex, NULL, 16); 53 | return rgb; 54 | } 55 | 56 | /** 57 | * @brief This function converts RGB888 to RGB565. 58 | * 59 | * @param rgb unsigned long 60 | * 61 | * @return unsigned int 62 | * 63 | * @note none 64 | */ 65 | unsigned int convertRGB888ToRGB565(unsigned long rgb) 66 | { 67 | return (((rgb & 0xf80000) >> 8) | ((rgb & 0xfc00) >> 5) | ((rgb & 0xf8) >> 3)); 68 | } 69 | 70 | /** 71 | * @brief This function draws a transparent BMP on the TFT screen according 72 | to the given x and y coordinates. 73 | * 74 | * @param *filename 75 | * @param x int16_t 76 | * @param y int16_t 77 | * 78 | * @return none 79 | * 80 | * @note A completely black pixel is transparent e.g. (0x0000) not drawn. 81 | */ 82 | void drawBmpTransparent(const char *filename, int16_t x, int16_t y) 83 | { 84 | 85 | if ((x >= tft.width()) || (y >= tft.height())) 86 | return; 87 | 88 | fs::File bmpFS; 89 | 90 | bmpFS = FILESYSTEM.open(filename, "r"); 91 | 92 | if (!bmpFS) 93 | { 94 | Serial.println("[WARNING]: Bitmap not found: "); 95 | Serial.println(filename); 96 | filename = "/logos/question.bmp"; 97 | bmpFS = FILESYSTEM.open(filename, "r"); 98 | } 99 | 100 | uint32_t seekOffset; 101 | uint16_t w, h, row; 102 | uint8_t r, g, b; 103 | 104 | if (read16(bmpFS) == 0x4D42) 105 | { 106 | read32(bmpFS); 107 | read32(bmpFS); 108 | seekOffset = read32(bmpFS); 109 | read32(bmpFS); 110 | w = read32(bmpFS); 111 | h = read32(bmpFS); 112 | 113 | if ((read16(bmpFS) == 1) && (read16(bmpFS) == 24) && (read32(bmpFS) == 0)) 114 | { 115 | y += h - 1; 116 | 117 | bool oldSwapBytes = tft.getSwapBytes(); 118 | tft.setSwapBytes(true); 119 | bmpFS.seek(seekOffset); 120 | 121 | uint16_t padding = (4 - ((w * 3) & 3)) & 3; 122 | uint8_t lineBuffer[w * 3 + padding]; 123 | 124 | for (row = 0; row < h; row++) 125 | { 126 | 127 | bmpFS.read(lineBuffer, sizeof(lineBuffer)); 128 | uint8_t *bptr = lineBuffer; 129 | uint16_t *tptr = (uint16_t *)lineBuffer; 130 | // Convert 24 to 16 bit colours 131 | for (uint16_t col = 0; col < w; col++) 132 | { 133 | b = *bptr++; 134 | g = *bptr++; 135 | r = *bptr++; 136 | *tptr++ = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); 137 | } 138 | 139 | // Push the pixel row to screen, pushImage will crop the line if needed 140 | // y is decremented as the BMP image is drawn bottom up 141 | tft.pushImage(x, y--, w, 1, (uint16_t *)lineBuffer, TFT_BLACK); 142 | } 143 | tft.setSwapBytes(oldSwapBytes); 144 | } 145 | else 146 | Serial.println("BMP format not recognized."); 147 | } 148 | bmpFS.close(); 149 | } 150 | 151 | /** 152 | * @brief This function draws a BMP on the TFT screen according 153 | to the given x and y coordinates. 154 | * 155 | * @param *filename 156 | * @param x int16_t 157 | * @param y int16_t 158 | * 159 | * @return none 160 | * 161 | * @note In contradiction to drawBmpTransparent() this does draw black pixels. 162 | */ 163 | void drawBmp(const char *filename, int16_t x, int16_t y) 164 | { 165 | 166 | if ((x >= tft.width()) || (y >= tft.height())) 167 | return; 168 | 169 | fs::File bmpFS; 170 | 171 | bmpFS = FILESYSTEM.open(filename, "r"); 172 | 173 | if (!bmpFS) 174 | { 175 | 176 | Serial.print("File not found:"); 177 | Serial.println(filename); 178 | return; 179 | } 180 | 181 | uint32_t seekOffset; 182 | uint16_t w, h, row; 183 | uint8_t r, g, b; 184 | 185 | if (read16(bmpFS) == 0x4D42) 186 | { 187 | read32(bmpFS); 188 | read32(bmpFS); 189 | seekOffset = read32(bmpFS); 190 | read32(bmpFS); 191 | w = read32(bmpFS); 192 | h = read32(bmpFS); 193 | 194 | if ((read16(bmpFS) == 1) && (read16(bmpFS) == 24) && (read32(bmpFS) == 0)) 195 | { 196 | y += h - 1; 197 | 198 | bool oldSwapBytes = tft.getSwapBytes(); 199 | tft.setSwapBytes(true); 200 | bmpFS.seek(seekOffset); 201 | 202 | uint16_t padding = (4 - ((w * 3) & 3)) & 3; 203 | uint8_t lineBuffer[w * 3 + padding]; 204 | 205 | for (row = 0; row < h; row++) 206 | { 207 | 208 | bmpFS.read(lineBuffer, sizeof(lineBuffer)); 209 | uint8_t *bptr = lineBuffer; 210 | uint16_t *tptr = (uint16_t *)lineBuffer; 211 | // Convert 24 to 16 bit colours 212 | for (uint16_t col = 0; col < w; col++) 213 | { 214 | b = *bptr++; 215 | g = *bptr++; 216 | r = *bptr++; 217 | *tptr++ = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); 218 | } 219 | 220 | // Push the pixel row to screen, pushImage will crop the line if needed 221 | // y is decremented as the BMP image is drawn bottom up 222 | tft.pushImage(x, y--, w, 1, (uint16_t *)lineBuffer); 223 | } 224 | tft.setSwapBytes(oldSwapBytes); 225 | } 226 | else 227 | Serial.println("[WARNING]: BMP format not recognized."); 228 | } 229 | bmpFS.close(); 230 | } 231 | 232 | /** 233 | * @brief This function reads a number of bytes from the given 234 | file at the given position. 235 | * 236 | * @param *p_file File 237 | * @param position int 238 | * @param nBytes byte 239 | * 240 | * @return int32_t 241 | * 242 | * @note none 243 | */ 244 | int32_t readNbytesInt(File *p_file, int position, byte nBytes) 245 | { 246 | if (nBytes > 4) 247 | return 0; 248 | 249 | p_file->seek(position); 250 | 251 | int32_t weight = 1; 252 | int32_t result = 0; 253 | for (; nBytes; nBytes--) 254 | { 255 | result += weight * p_file->read(); 256 | weight <<= 8; 257 | } 258 | return result; 259 | } 260 | 261 | /** 262 | * @brief This function reads the RGB565 colour of the first pixel for a 263 | given the logo number. The pagenumber is global. 264 | * 265 | * @param *filename const char 266 | * 267 | * @return uint16_t 268 | * 269 | * @note Uses readNbytesInt 270 | */ 271 | uint16_t getBMPColor(const char *filename) 272 | { 273 | 274 | // Open File 275 | File bmpImage; 276 | bmpImage = SPIFFS.open(filename, FILE_READ); 277 | 278 | int32_t dataStartingOffset = readNbytesInt(&bmpImage, 0x0A, 4); 279 | int16_t pixelsize = readNbytesInt(&bmpImage, 0x1C, 2); 280 | 281 | if (pixelsize != 24) 282 | { 283 | Serial.println("[WARNING]: getBMPColor: Image is not 24 bpp"); 284 | return 0x0000; 285 | } 286 | 287 | bmpImage.seek(dataStartingOffset); //skip bitmap header 288 | 289 | byte R, G, B; 290 | 291 | B = bmpImage.read(); 292 | G = bmpImage.read(); 293 | R = bmpImage.read(); 294 | 295 | bmpImage.close(); 296 | 297 | return tft.color565(R, G, B); 298 | } 299 | 300 | /** 301 | * @brief This function returns the RGB565 colour of the first pixel for a 302 | given the logo number. The pagenumber is global. 303 | * 304 | * @param logonumber int 305 | * 306 | * @return uint16_t 307 | * 308 | * @note Uses getBMPColor to read the actual image data. 309 | */ 310 | uint16_t getImageBG(int logonumber) 311 | { 312 | 313 | if (pageNum == 0) 314 | { 315 | if (logonumber == 0) 316 | { 317 | return getBMPColor(screen0.logo0); 318 | } 319 | else if (logonumber == 1) 320 | { 321 | return getBMPColor(screen0.logo1); 322 | } 323 | else if (logonumber == 2) 324 | { 325 | return getBMPColor(screen0.logo2); 326 | } 327 | else if (logonumber == 3) 328 | { 329 | return getBMPColor(screen0.logo3); 330 | } 331 | else if (logonumber == 4) 332 | { 333 | return getBMPColor(screen0.logo4); 334 | } 335 | else 336 | { 337 | return 0x0000; 338 | } 339 | } 340 | else if (pageNum == 1) 341 | { 342 | if (logonumber == 0) 343 | { 344 | return getBMPColor(screen1.logo0); 345 | } 346 | else if (logonumber == 1) 347 | { 348 | return getBMPColor(screen1.logo1); 349 | } 350 | else if (logonumber == 2) 351 | { 352 | return getBMPColor(screen1.logo2); 353 | } 354 | else if (logonumber == 3) 355 | { 356 | return getBMPColor(screen1.logo3); 357 | } 358 | else if (logonumber == 4) 359 | { 360 | return getBMPColor(screen1.logo4); 361 | } 362 | else 363 | { 364 | return 0x0000; 365 | } 366 | } 367 | else if (pageNum == 2) 368 | { 369 | if (logonumber == 0) 370 | { 371 | return getBMPColor(screen2.logo0); 372 | } 373 | else if (logonumber == 1) 374 | { 375 | return getBMPColor(screen2.logo1); 376 | } 377 | else if (logonumber == 2) 378 | { 379 | return getBMPColor(screen2.logo2); 380 | } 381 | else if (logonumber == 3) 382 | { 383 | return getBMPColor(screen2.logo3); 384 | } 385 | else if (logonumber == 4) 386 | { 387 | return getBMPColor(screen2.logo4); 388 | } 389 | else 390 | { 391 | return 0x0000; 392 | } 393 | } 394 | else if (pageNum == 3) 395 | { 396 | if (logonumber == 0) 397 | { 398 | return getBMPColor(screen3.logo0); 399 | } 400 | else if (logonumber == 1) 401 | { 402 | return getBMPColor(screen3.logo1); 403 | } 404 | else if (logonumber == 2) 405 | { 406 | return getBMPColor(screen3.logo2); 407 | } 408 | else if (logonumber == 3) 409 | { 410 | return getBMPColor(screen3.logo3); 411 | } 412 | else if (logonumber == 4) 413 | { 414 | return getBMPColor(screen3.logo4); 415 | } 416 | else 417 | { 418 | return 0x0000; 419 | } 420 | } 421 | else if (pageNum == 4) 422 | { 423 | if (logonumber == 0) 424 | { 425 | return getBMPColor(screen4.logo0); 426 | } 427 | else if (logonumber == 1) 428 | { 429 | return getBMPColor(screen4.logo1); 430 | } 431 | else if (logonumber == 2) 432 | { 433 | return getBMPColor(screen4.logo2); 434 | } 435 | else if (logonumber == 3) 436 | { 437 | return getBMPColor(screen4.logo3); 438 | } 439 | else if (logonumber == 4) 440 | { 441 | return getBMPColor(screen4.logo4); 442 | } 443 | else 444 | { 445 | return 0x0000; 446 | } 447 | } 448 | else if (pageNum == 5) 449 | { 450 | if (logonumber == 0) 451 | { 452 | return getBMPColor(screen5.logo0); 453 | } 454 | else if (logonumber == 1) 455 | { 456 | return getBMPColor(screen5.logo1); 457 | } 458 | else if (logonumber == 2) 459 | { 460 | return getBMPColor(screen5.logo2); 461 | } 462 | else if (logonumber == 3) 463 | { 464 | return getBMPColor(screen5.logo3); 465 | } 466 | else if (logonumber == 4) 467 | { 468 | return getBMPColor(screen5.logo4); 469 | } 470 | else 471 | { 472 | return 0x0000; 473 | } 474 | } 475 | else if (pageNum == 6) 476 | { 477 | return 0x0000; 478 | } 479 | else 480 | { 481 | return 0x0000; 482 | } 483 | } 484 | 485 | /** 486 | * @brief This function returns the RGB565 colour of the first pixel of the image which 487 | * is being latched to for a given the logo number. The pagenumber is global. 488 | * 489 | * @param logonumber int 490 | * 491 | * @return uint16_t 492 | * 493 | * @note Uses getBMPColor to read the actual image data. 494 | */ 495 | uint16_t getLatchImageBG(int logonumber) 496 | { 497 | 498 | if (pageNum == 1) 499 | { 500 | if (logonumber == 0) 501 | { 502 | if (strcmp(menu1.button0.latchlogo, "/logos/") == 0) 503 | { 504 | return getBMPColor(screen1.logo0); 505 | } 506 | return getBMPColor(menu1.button0.latchlogo); 507 | } 508 | else if (logonumber == 1) 509 | { 510 | if (strcmp(menu1.button1.latchlogo, "/logos/") == 0) 511 | { 512 | return getBMPColor(screen1.logo1); 513 | } 514 | return getBMPColor(menu1.button1.latchlogo); 515 | } 516 | else if (logonumber == 2) 517 | { 518 | if (strcmp(menu1.button2.latchlogo, "/logos/") == 0) 519 | { 520 | return getBMPColor(screen1.logo2); 521 | } 522 | return getBMPColor(menu1.button2.latchlogo); 523 | } 524 | else if (logonumber == 3) 525 | { 526 | if (strcmp(menu1.button3.latchlogo, "/logos/") == 0) 527 | { 528 | return getBMPColor(screen1.logo3); 529 | } 530 | return getBMPColor(menu1.button3.latchlogo); 531 | } 532 | else if (logonumber == 4) 533 | { 534 | if (strcmp(menu1.button4.latchlogo, "/logos/") == 0) 535 | { 536 | return getBMPColor(screen1.logo4); 537 | } 538 | return getBMPColor(menu1.button4.latchlogo); 539 | } 540 | else 541 | { 542 | return 0x0000; 543 | } 544 | } 545 | else if (pageNum == 2) 546 | { 547 | if (logonumber == 0) 548 | { 549 | if (strcmp(menu2.button0.latchlogo, "/logos/") == 0) 550 | { 551 | return getBMPColor(screen2.logo0); 552 | } 553 | return getBMPColor(menu2.button0.latchlogo); 554 | } 555 | else if (logonumber == 1) 556 | { 557 | if (strcmp(menu2.button1.latchlogo, "/logos/") == 0) 558 | { 559 | return getBMPColor(screen2.logo1); 560 | } 561 | return getBMPColor(menu2.button1.latchlogo); 562 | } 563 | else if (logonumber == 2) 564 | { 565 | if (strcmp(menu2.button2.latchlogo, "/logos/") == 0) 566 | { 567 | return getBMPColor(screen2.logo2); 568 | } 569 | return getBMPColor(menu2.button2.latchlogo); 570 | } 571 | else if (logonumber == 3) 572 | { 573 | if (strcmp(menu2.button3.latchlogo, "/logos/") == 0) 574 | { 575 | return getBMPColor(screen2.logo3); 576 | } 577 | return getBMPColor(menu2.button3.latchlogo); 578 | } 579 | else if (logonumber == 4) 580 | { 581 | if (strcmp(menu2.button4.latchlogo, "/logos/") == 0) 582 | { 583 | return getBMPColor(screen2.logo4); 584 | } 585 | return getBMPColor(menu2.button4.latchlogo); 586 | } 587 | else 588 | { 589 | return 0x0000; 590 | } 591 | } 592 | else if (pageNum == 3) 593 | { 594 | if (logonumber == 0) 595 | { 596 | if (strcmp(menu3.button0.latchlogo, "/logos/") == 0) 597 | { 598 | return getBMPColor(screen3.logo0); 599 | } 600 | return getBMPColor(menu3.button0.latchlogo); 601 | } 602 | else if (logonumber == 1) 603 | { 604 | if (strcmp(menu3.button1.latchlogo, "/logos/") == 0) 605 | { 606 | return getBMPColor(screen3.logo1); 607 | } 608 | return getBMPColor(menu3.button1.latchlogo); 609 | } 610 | else if (logonumber == 2) 611 | { 612 | if (strcmp(menu3.button2.latchlogo, "/logos/") == 0) 613 | { 614 | return getBMPColor(screen3.logo2); 615 | } 616 | return getBMPColor(menu3.button2.latchlogo); 617 | } 618 | else if (logonumber == 3) 619 | { 620 | if (strcmp(menu3.button3.latchlogo, "/logos/") == 0) 621 | { 622 | return getBMPColor(screen3.logo3); 623 | } 624 | return getBMPColor(menu3.button3.latchlogo); 625 | } 626 | else if (logonumber == 4) 627 | { 628 | if (strcmp(menu3.button4.latchlogo, "/logos/") == 0) 629 | { 630 | return getBMPColor(screen3.logo4); 631 | } 632 | return getBMPColor(menu3.button4.latchlogo); 633 | } 634 | else 635 | { 636 | return 0x0000; 637 | } 638 | } 639 | else if (pageNum == 4) 640 | { 641 | if (logonumber == 0) 642 | { 643 | if (strcmp(menu4.button0.latchlogo, "/logos/") == 0) 644 | { 645 | return getBMPColor(screen4.logo0); 646 | } 647 | return getBMPColor(menu4.button0.latchlogo); 648 | } 649 | else if (logonumber == 1) 650 | { 651 | if (strcmp(menu4.button1.latchlogo, "/logos/") == 0) 652 | { 653 | return getBMPColor(screen4.logo1); 654 | } 655 | return getBMPColor(menu4.button1.latchlogo); 656 | } 657 | else if (logonumber == 2) 658 | { 659 | if (strcmp(menu4.button2.latchlogo, "/logos/") == 0) 660 | { 661 | return getBMPColor(screen4.logo2); 662 | } 663 | return getBMPColor(menu4.button2.latchlogo); 664 | } 665 | else if (logonumber == 3) 666 | { 667 | if (strcmp(menu4.button3.latchlogo, "/logos/") == 0) 668 | { 669 | return getBMPColor(screen4.logo3); 670 | } 671 | return getBMPColor(menu4.button3.latchlogo); 672 | } 673 | else if (logonumber == 4) 674 | { 675 | if (strcmp(menu4.button4.latchlogo, "/logos/") == 0) 676 | { 677 | return getBMPColor(screen4.logo4); 678 | } 679 | return getBMPColor(menu4.button4.latchlogo); 680 | } 681 | else 682 | { 683 | return 0x0000; 684 | } 685 | } 686 | else if (pageNum == 5) 687 | { 688 | if (logonumber == 0) 689 | { 690 | if (strcmp(menu5.button0.latchlogo, "/logos/") == 0) 691 | { 692 | return getBMPColor(screen5.logo0); 693 | } 694 | return getBMPColor(menu5.button0.latchlogo); 695 | } 696 | else if (logonumber == 1) 697 | { 698 | if (strcmp(menu5.button1.latchlogo, "/logos/") == 0) 699 | { 700 | return getBMPColor(screen5.logo1); 701 | } 702 | return getBMPColor(menu5.button1.latchlogo); 703 | } 704 | else if (logonumber == 2) 705 | { 706 | if (strcmp(menu5.button2.latchlogo, "/logos/") == 0) 707 | { 708 | return getBMPColor(screen5.logo2); 709 | } 710 | return getBMPColor(menu5.button2.latchlogo); 711 | } 712 | else if (logonumber == 3) 713 | { 714 | if (strcmp(menu5.button3.latchlogo, "/logos/") == 0) 715 | { 716 | return getBMPColor(screen5.logo3); 717 | } 718 | return getBMPColor(menu5.button3.latchlogo); 719 | } 720 | else if (logonumber == 4) 721 | { 722 | if (strcmp(menu5.button4.latchlogo, "/logos/") == 0) 723 | { 724 | return getBMPColor(screen5.logo4); 725 | } 726 | return getBMPColor(menu5.button4.latchlogo); 727 | } 728 | else 729 | { 730 | return 0x0000; 731 | } 732 | } 733 | else if (pageNum == 6) 734 | { 735 | return 0x0000; 736 | } 737 | else 738 | { 739 | return 0x0000; 740 | } 741 | } 742 | -------------------------------------------------------------------------------- /ESP32 source code/FreeTouchDeck/FreeTouchDeck.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Author: Dustin Watts 3 | Date: 27-08-2020 4 | 5 | My thanks goes out to Brian Lough, Colin Hickey, and the people on my Discord server 6 | for helping me a lot with the code and troubleshooting! https://discord.gg/RE3XevS 7 | 8 | FreeTouchDeck is based on the FreeDeck idea by Koriwi. It uses the TFT_eSPI library 9 | by Bodmer for the display and touch functionality and it uses an ESP32-BLE-Keyboard fork 10 | with a few modifications. For saving and loading configuration it uses ArduinoJson V6. 11 | 12 | FreeTouchDeck uses some libraries from other sources. These must be installed for 13 | FreeTouchDeck to compile and run. 14 | 15 | These are those libraries: 16 | 17 | !----------------------------- Library Dependencies --------------------------- ! 18 | - Adafruit-GFX-Library (version 1.10.0), available through Library Manager 19 | - TFT_eSPI (version 2.2.14), available through Library Manager 20 | - ESP32-BLE-Keyboard (forked) (latest version) download from: https://github.com/DustinWatts/ESP32-BLE-Keyboard 21 | - ESPAsyncWebserver (latest version) download from: https://github.com/me-no-dev/ESPAsyncWebServer 22 | - AsyncTCP (latest version) download from: https://github.com/me-no-dev/AsyncTCP 23 | - ArduinoJson (version 6.16.1), available through Library Manager 24 | 25 | --- If you use Capacitive touch --- 26 | - Dustin Watts FT6236 Library (version 1.0.1), https://github.com/DustinWatts/FT6236 27 | 28 | The FILESYSTEM (SPI FLASH filing system) is used to hold touch screen calibration data. 29 | It has to be runs at least once when using resistive touch. After that you can set 30 | REPEAT_CAL to false (default). 31 | 32 | !-- Make sure you have setup your TFT display and ESP setup correctly in TFT_eSPI/user_setup.h --! 33 | 34 | Select the right screen driver and the board (ESP32 is the only one tested) you are 35 | using. Also make sure TOUCH_CS is defined correctly. TFT_BL is also be needed! 36 | 37 | You can find examples of User_Setup.h in the "user_setup.h Examples" folder. 38 | 39 | */ 40 | 41 | // ------- Uncomment the next line if you use capacitive touch ------- 42 | //#define USECAPTOUCH 43 | 44 | // ------- Uncomment and populate the following if your cap touch uses custom i2c pins ------- 45 | //#define CUSTOM_TOUCH_SDA 26 46 | //#define CUSTOM_TOUCH_SCL 27 47 | 48 | // PAY ATTENTION! Even if resistive touch is not used, the TOUCH pin has to be defined! 49 | // It can be a random unused pin. 50 | // TODO: Find a way around this! 51 | 52 | // ------- Uncomment the define below if you want to use SLEEP and wake up on touch ------- 53 | // The pin where the IRQ from the touch screen is connected uses ESP-style GPIO_NUM_* instead of just pinnumber 54 | #define touchInterruptPin GPIO_NUM_27 55 | 56 | // ------- Uncomment the define below if you want to use a piezo buzzer and specify the pin where the speaker is connected ------- 57 | //#define speakerPin 26 58 | 59 | const char *versionnumber = "0.9.7"; 60 | 61 | /* Version 0.9.7 Bug fix: Changing colour causes reboot when entering config mode. "Combos" dissapeared and are now back. 62 | * Move the FreeTouchDeck logo to the "logos" folder so it can be deleted to create more space. 63 | * Fixed the latching dot to fall within the boundaries of a button when using a 320 * 240 screen. 64 | * When updating: remember to re-upload the data folder ! ! 65 | */ 66 | 67 | #include // PROGMEM support header 68 | #include // Filesystem support header 69 | #include // Filesystem support header 70 | 71 | #include // The TFT_eSPI library 72 | 73 | #include // BleKeyboard is used to communicate over BLE 74 | #include "BLEDevice.h" // Additional BLE functionaity 75 | #include "BLEUtils.h" // Additional BLE functionaity 76 | #include "BLEBeacon.h" // Additional BLE functionaity 77 | #include "esp_sleep.h" // Additional BLE functionaity 78 | 79 | #include "esp_bt_main.h" // Additional BLE functionaity 80 | #include "esp_bt_device.h" // Additional BLE functionaity 81 | 82 | #include // Using ArduinoJson to read and write config files 83 | 84 | #include // Wifi support 85 | 86 | #include //Async Webserver support header 87 | #include //Async Webserver support header 88 | 89 | #include // DNS functionality 90 | 91 | #ifdef USECAPTOUCH 92 | #include 93 | #include 94 | FT6236 ts = FT6236(); 95 | #endif 96 | 97 | BleKeyboard bleKeyboard("FreeTouchDeck", "Made by me"); 98 | 99 | AsyncWebServer webserver(80); 100 | 101 | TFT_eSPI tft = TFT_eSPI(); 102 | 103 | // Define the storage to be used. For now just SPIFFS. 104 | #define FILESYSTEM SPIFFS 105 | 106 | // This is the file name used to store the calibration data 107 | // You can change this to create new calibration files. 108 | // The FILESYSTEM file name must start with "/". 109 | #define CALIBRATION_FILE "/TouchCalData" 110 | 111 | // Set REPEAT_CAL to true instead of false to run calibration 112 | // again, otherwise it will only be done once. 113 | // Repeat calibration if you change the screen rotation. 114 | #define REPEAT_CAL false 115 | 116 | // Set the width and height of your screen here: 117 | #define SCREEN_WIDTH 480 118 | #define SCREEN_HEIGHT 320 119 | 120 | // Keypad start position, centre of the first button 121 | #define KEY_X SCREEN_WIDTH / 6 122 | #define KEY_Y SCREEN_HEIGHT / 4 123 | 124 | // Gaps between buttons 125 | #define KEY_SPACING_X SCREEN_WIDTH / 24 126 | #define KEY_SPACING_Y SCREEN_HEIGHT / 16 127 | 128 | // Width and height of a button 129 | #define KEY_W (SCREEN_WIDTH / 3) - KEY_SPACING_X 130 | #define KEY_H (SCREEN_WIDTH / 3) - KEY_SPACING_Y 131 | 132 | // Font size multiplier 133 | #define KEY_TEXTSIZE 1 134 | 135 | // Text Button Label Font 136 | #define LABEL_FONT &FreeSansBold12pt7b 137 | 138 | // placeholder for the pagenumber we are on (0 indicates home) 139 | int pageNum = 0; 140 | 141 | // Initial LED brightness 142 | int ledBrightness = 255; 143 | 144 | // Every button has a row associated with it 145 | uint8_t rowArray[6] = {0, 0, 0, 1, 1, 1}; 146 | // Every button has a column associated with it 147 | uint8_t colArray[6] = {0, 1, 2, 0, 1, 2}; 148 | 149 | //path to the directory the logo are in ! including leading AND trailing / ! 150 | char logopath[64] = "/logos/"; 151 | 152 | // templogopath is used to hold the complete path of an image. It is empty for now. 153 | char templogopath[64] = ""; 154 | 155 | // Struct to hold the logos per screen 156 | struct Logos 157 | { 158 | char logo0[32]; 159 | char logo1[32]; 160 | char logo2[32]; 161 | char logo3[32]; 162 | char logo4[32]; 163 | char logo5[32]; 164 | }; 165 | 166 | // Struct Action: 3 actions and 3 values per button 167 | struct Actions 168 | { 169 | uint8_t action0; 170 | uint8_t value0; 171 | char symbol0[64]; 172 | uint8_t action1; 173 | uint8_t value1; 174 | char symbol1[64]; 175 | uint8_t action2; 176 | uint8_t value2; 177 | char symbol2[64]; 178 | }; 179 | 180 | // Each button has an action struct in it 181 | struct Button 182 | { 183 | struct Actions actions; 184 | bool latch; 185 | char latchlogo[32]; 186 | }; 187 | 188 | // Each menu has 6 buttons 189 | struct Menu 190 | { 191 | struct Button button0; 192 | struct Button button1; 193 | struct Button button2; 194 | struct Button button3; 195 | struct Button button4; 196 | struct Button button5; 197 | }; 198 | 199 | // Struct to hold the general logos. 200 | struct Generallogos 201 | { 202 | char homebutton[64]; 203 | char configurator[64]; 204 | }; 205 | 206 | //Struct to hold the general config like colours. 207 | struct Config 208 | { 209 | uint16_t menuButtonColour; 210 | uint16_t functionButtonColour; 211 | uint16_t backgroundColour; 212 | uint16_t latchedColour; 213 | }; 214 | 215 | struct Wificonfig 216 | { 217 | char ssid[64]; 218 | char password[64]; 219 | char wifimode[9]; 220 | char hostname[64]; 221 | bool sleepenable; 222 | uint16_t sleeptimer; 223 | }; 224 | 225 | // Array to hold all the latching statuses 226 | bool islatched[30] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 227 | 228 | // Create instances of the structs 229 | Wificonfig wificonfig; 230 | 231 | Config generalconfig; 232 | 233 | Generallogos generallogo; 234 | 235 | Logos screen0; 236 | Logos screen1; 237 | Logos screen2; 238 | Logos screen3; 239 | Logos screen4; 240 | Logos screen5; 241 | Logos screen6; 242 | 243 | Menu menu1; 244 | Menu menu2; 245 | Menu menu3; 246 | Menu menu4; 247 | Menu menu5; 248 | Menu menu6; 249 | 250 | unsigned long previousMillis = 0; 251 | unsigned long Interval = 0; 252 | bool displayinginfo; 253 | 254 | // Invoke the TFT_eSPI button class and create all the button objects 255 | TFT_eSPI_Button key[6]; 256 | 257 | // Checking for BLE Keyboard version 258 | #ifndef BLE_KEYBOARD_VERSION 259 | #warning Old BLE Keyboard version detected. Please update. 260 | #define BLE_KEYBOARD_VERSION "Outdated" 261 | #endif 262 | 263 | //--------- Internal references ------------ 264 | // (this needs to be below all structs etc..) 265 | #include "ScreenHelper.h" 266 | #include "ConfigLoad.h" 267 | #include "DrawHelper.h" 268 | #include "ConfigHelper.h" 269 | #include "Action.h" 270 | #include "Webserver.h" 271 | #include "Touch.h" 272 | 273 | //-------------------------------- SETUP -------------------------------------------------------------- 274 | 275 | void setup() 276 | { 277 | 278 | // Use serial port 279 | Serial.begin(9600); 280 | Serial.setDebugOutput(true); 281 | Serial.println(""); 282 | 283 | #ifdef USECAPTOUCH 284 | #ifdef CUSTOM_TOUCH_SDA 285 | if (!ts.begin(40, CUSTOM_TOUCH_SDA, CUSTOM_TOUCH_SCL)) 286 | #else 287 | if (!ts.begin(40)) 288 | #endif 289 | { 290 | Serial.println("[WARNING]: Unable to start the capacitive touchscreen."); 291 | } 292 | else 293 | { 294 | Serial.println("[INFO]: Capacitive touch started!"); 295 | } 296 | #endif 297 | 298 | // Setup PWM channel and attach pin 32 299 | ledcSetup(0, 5000, 8); 300 | #ifdef TFT_BL 301 | ledcAttachPin(TFT_BL, 0); 302 | #endif 303 | ledcWrite(0, ledBrightness); // Start @ initial Brightness 304 | 305 | // Setup PWM channel for Piezo speaker 306 | 307 | #ifdef speakerPin 308 | ledcSetup(1, 500, 8); 309 | 310 | ledcAttachPin(speakerPin, 0); 311 | ledcWriteTone(1, 600); 312 | delay(150); 313 | ledcDetachPin(speakerPin); 314 | ledcWrite(1, 0); 315 | 316 | ledcAttachPin(speakerPin, 0); 317 | ledcWriteTone(1, 800); 318 | delay(150); 319 | ledcDetachPin(speakerPin); 320 | ledcWrite(1, 0); 321 | 322 | ledcAttachPin(speakerPin, 0); 323 | ledcWriteTone(1, 1200); 324 | delay(150); 325 | ledcDetachPin(speakerPin); 326 | ledcWrite(1, 0); 327 | 328 | #endif 329 | 330 | if (!FILESYSTEM.begin()) 331 | { 332 | Serial.println("[WARNING]: SPIFFS initialisation failed!"); 333 | while (1) 334 | yield(); // We stop here 335 | } 336 | Serial.println("[INFO]: SPIFFS initialised."); 337 | 338 | // Check for free space 339 | 340 | Serial.print("[INFO]: Free Space: "); 341 | Serial.println(SPIFFS.totalBytes() - SPIFFS.usedBytes()); 342 | 343 | //------------------ Load Wifi Config ---------------------------------------------- 344 | 345 | Serial.println("[INFO]: Loading Wifi Config"); 346 | if (!loadMainConfig()) 347 | { 348 | Serial.println("[WARNING]: Failed to load WiFi Credentials!"); 349 | } 350 | else 351 | { 352 | Serial.println("[INFO]: WiFi Credentials Loaded"); 353 | } 354 | 355 | // ---- Load webserver ------------------------------- 356 | 357 | handlerSetup(); 358 | 359 | //------------------TFT/Touch Initialization ------------------------------------------------------------------------ 360 | 361 | // Initialise the TFT screen 362 | tft.init(); 363 | 364 | // Set the rotation before we calibrate 365 | tft.setRotation(1); 366 | 367 | // Clear the screen 368 | tft.fillScreen(TFT_BLACK); 369 | 370 | esp_sleep_wakeup_cause_t wakeup_reason; 371 | wakeup_reason = esp_sleep_get_wakeup_cause(); 372 | 373 | // If we are woken up we do not need the splash screen 374 | if (wakeup_reason > 0) 375 | { 376 | // But we do draw something to indicate we are waking up 377 | tft.setTextFont(2); 378 | tft.println(" Waking up..."); 379 | } 380 | else 381 | { 382 | 383 | // Draw a splash screen 384 | drawBmp("/logos/freetouchdeck_logo.bmp", 0, 0); 385 | tft.setCursor(1, 3); 386 | tft.setTextFont(2); 387 | tft.setTextSize(1); 388 | tft.setTextColor(TFT_WHITE, TFT_BLACK); 389 | tft.printf("Loading version %s\n", versionnumber); 390 | Serial.printf("[INFO]: Loading version %s\n", versionnumber); 391 | } 392 | 393 | // Calibrate the touch screen and retrieve the scaling factors 394 | #ifndef USECAPTOUCH 395 | touch_calibrate(); 396 | #endif 397 | 398 | // Let's first check if all the files we need exist 399 | if (!checkfile("/config/colors.json")) 400 | { 401 | Serial.println("[ERROR]: /config/colors.json not found!"); 402 | while (1) 403 | yield(); // Stop! 404 | } 405 | 406 | if (!checkfile("/config/homescreen.json")) 407 | { 408 | Serial.println("[ERROR]: /config/homescreen.json not found!"); 409 | while (1) 410 | yield(); // Stop! 411 | } 412 | 413 | if (!checkfile("/config/menu1.json")) 414 | { 415 | Serial.println("[ERROR]: /config/menu1.json not found!"); 416 | while (1) 417 | yield(); // Stop! 418 | } 419 | 420 | if (!checkfile("/config/menu2.json")) 421 | { 422 | Serial.println("[ERROR]: /config/menu2.json not found!"); 423 | while (1) 424 | yield(); // Stop! 425 | } 426 | 427 | if (!checkfile("/config/menu3.json")) 428 | { 429 | Serial.println("[ERROR]: /config/menu3.json not found!"); 430 | while (1) 431 | yield(); // Stop! 432 | } 433 | 434 | if (!checkfile("/config/menu4.json")) 435 | { 436 | Serial.println("[ERROR]: /config/menu4.json not found!"); 437 | while (1) 438 | yield(); // Stop! 439 | } 440 | 441 | if (!checkfile("/config/menu5.json")) 442 | { 443 | Serial.println("[ERROR]: /config/menu5.json not found!"); 444 | while (1) 445 | yield(); // Stop! 446 | } 447 | 448 | // Load the all the configuration 449 | loadConfig("colors"); 450 | loadConfig("homescreen"); 451 | loadConfig("menu1"); 452 | loadConfig("menu2"); 453 | loadConfig("menu3"); 454 | loadConfig("menu4"); 455 | loadConfig("menu5"); 456 | Serial.println("[INFO]: All configs loaded"); 457 | 458 | strcpy(generallogo.homebutton, "/logos/home.bmp"); 459 | strcpy(generallogo.configurator, "/logos/wifi.bmp"); 460 | Serial.println("[INFO]: General logos loaded."); 461 | 462 | // Setup the Font used for plain text 463 | tft.setFreeFont(LABEL_FONT); 464 | 465 | //------------------BLE Initialization ------------------------------------------------------------------------ 466 | 467 | Serial.println("[INFO]: Starting BLE"); 468 | bleKeyboard.begin(); 469 | 470 | // ---------------- Printing version numbers ----------------------------------------------- 471 | Serial.print("[INFO]: BLE Keyboard version: "); 472 | Serial.println(BLE_KEYBOARD_VERSION); 473 | Serial.print("[INFO]: ArduinoJson version: "); 474 | Serial.println(ARDUINOJSON_VERSION); 475 | Serial.print("[INFO]: TFT_eSPI version: "); 476 | Serial.println(TFT_ESPI_VERSION); 477 | 478 | // ---------------- Start the first keypad ------------- 479 | 480 | // Draw background 481 | tft.fillScreen(generalconfig.backgroundColour); 482 | 483 | // Draw keypad 484 | Serial.println("[INFO]: Drawing keypad"); 485 | drawKeypad(); 486 | 487 | #ifdef touchInterruptPin 488 | if (wificonfig.sleepenable) 489 | { 490 | pinMode(touchInterruptPin, INPUT_PULLUP); 491 | Interval = wificonfig.sleeptimer * 60000; 492 | Serial.println("[INFO]: Sleep enabled."); 493 | Serial.print("[INFO]: Sleep timer = "); 494 | Serial.print(wificonfig.sleeptimer); 495 | Serial.println(" minutes"); 496 | islatched[28] = 1; 497 | } 498 | #endif 499 | } 500 | 501 | //--------------------- LOOP --------------------------------------------------------------------- 502 | 503 | void loop(void) 504 | { 505 | 506 | // Check if there is data available on the serial input that needs to be handled. 507 | 508 | if (Serial.available()) 509 | { 510 | 511 | String command = Serial.readStringUntil(' '); 512 | 513 | if (command == "cal") 514 | { 515 | FILESYSTEM.remove(CALIBRATION_FILE); 516 | ESP.restart(); 517 | } 518 | else if (command == "setssid") 519 | { 520 | 521 | String value = Serial.readString(); 522 | if (saveWifiSSID(value)) 523 | { 524 | Serial.printf("[INFO]: Saved new SSID: %s\n", value.c_str()); 525 | loadMainConfig(); 526 | Serial.println("[INFO]: New configuration loaded"); 527 | } 528 | } 529 | else if (command == "setpassword") 530 | { 531 | String value = Serial.readString(); 532 | if (saveWifiPW(value)) 533 | { 534 | Serial.printf("[INFO]: Saved new Password: %s\n", value.c_str()); 535 | loadMainConfig(); 536 | Serial.println("[INFO]: New configuration loaded"); 537 | } 538 | } 539 | else if (command == "setwifimode") 540 | { 541 | String value = Serial.readString(); 542 | if (saveWifiMode(value)) 543 | { 544 | Serial.printf("[INFO]: Saved new WiFi Mode: %s\n", value.c_str()); 545 | loadMainConfig(); 546 | Serial.println("[INFO]: New configuration loaded"); 547 | } 548 | } 549 | else if (command == "restart") 550 | { 551 | Serial.println("[WARNING]: Restarting"); 552 | ESP.restart(); 553 | } 554 | } 555 | 556 | if (pageNum == 7) 557 | { 558 | 559 | // If the pageNum is set to 7, do not draw anything on screen or check for touch 560 | // and start handeling incomming web requests. 561 | } 562 | else if (pageNum == 8) 563 | { 564 | 565 | if (!displayinginfo) 566 | { 567 | printinfo(); 568 | } 569 | 570 | uint16_t t_x = 0, t_y = 0; 571 | 572 | //At the beginning of a new loop, make sure we do not use last loop's touch. 573 | boolean pressed = false; 574 | 575 | #ifdef USECAPTOUCH 576 | if (ts.touched()) 577 | { 578 | 579 | // Retrieve a point 580 | TS_Point p = ts.getPoint(); 581 | 582 | //Flip things around so it matches our screen rotation 583 | p.x = map(p.x, 0, 320, 320, 0); 584 | t_y = p.x; 585 | t_x = p.y; 586 | 587 | pressed = true; 588 | } 589 | 590 | #else 591 | 592 | pressed = tft.getTouch(&t_x, &t_y); 593 | 594 | #endif 595 | 596 | if (pressed) 597 | { 598 | displayinginfo = false; 599 | pageNum = 6; 600 | tft.fillScreen(generalconfig.backgroundColour); 601 | drawKeypad(); 602 | } 603 | } 604 | else 605 | { 606 | 607 | // Check if sleep is enabled and if our timer has ended. 608 | 609 | #ifdef touchInterruptPin 610 | if (wificonfig.sleepenable) 611 | { 612 | if (millis() > previousMillis + Interval) 613 | { 614 | 615 | // The timer has ended and we are going to sleep . 616 | tft.fillScreen(TFT_BLACK); 617 | Serial.println("[INFO]: Going to sleep."); 618 | #ifdef speakerPin 619 | ledcAttachPin(speakerPin, 0); 620 | ledcWriteTone(1, 1200); 621 | delay(150); 622 | ledcDetachPin(speakerPin); 623 | ledcWrite(1, 0); 624 | 625 | ledcAttachPin(speakerPin, 0); 626 | ledcWriteTone(1, 800); 627 | delay(150); 628 | ledcDetachPin(speakerPin); 629 | ledcWrite(1, 0); 630 | 631 | ledcAttachPin(speakerPin, 0); 632 | ledcWriteTone(1, 600); 633 | delay(150); 634 | ledcDetachPin(speakerPin); 635 | ledcWrite(1, 0); 636 | #endif 637 | 638 | esp_sleep_enable_ext0_wakeup(touchInterruptPin, 0); 639 | esp_deep_sleep_start(); 640 | } 641 | } 642 | #endif 643 | 644 | // Touch coordinates are stored here 645 | uint16_t t_x = 0, t_y = 0; 646 | 647 | //At the beginning of a new loop, make sure we do not use last loop's touch. 648 | boolean pressed = false; 649 | 650 | #ifdef USECAPTOUCH 651 | if (ts.touched()) 652 | { 653 | 654 | // Retrieve a point 655 | TS_Point p = ts.getPoint(); 656 | 657 | //Flip things around so it matches our screen rotation 658 | p.x = map(p.x, 0, 320, 320, 0); 659 | t_y = p.x; 660 | t_x = p.y; 661 | 662 | pressed = true; 663 | } 664 | 665 | #else 666 | 667 | pressed = tft.getTouch(&t_x, &t_y); 668 | 669 | #endif 670 | 671 | // Check if the X and Y coordinates of the touch are within one of our buttons 672 | for (uint8_t b = 0; b < 6; b++) 673 | { 674 | if (pressed && key[b].contains(t_x, t_y)) 675 | { 676 | key[b].press(true); // tell the button it is pressed 677 | 678 | // After receiving a valid touch reset the sleep timer 679 | previousMillis = millis(); 680 | // Beep 681 | #ifdef speakerPin 682 | ledcAttachPin(speakerPin, 0); 683 | ledcWriteTone(1, 600); 684 | delay(50); 685 | ledcDetachPin(speakerPin); 686 | ledcWrite(1, 0); 687 | #endif 688 | } 689 | else 690 | { 691 | key[b].press(false); // tell the button it is NOT pressed 692 | } 693 | } 694 | 695 | // Check if any key has changed state 696 | for (uint8_t b = 0; b < 6; b++) 697 | { 698 | if (key[b].justReleased()) 699 | { 700 | 701 | // Draw normal button space (non inverted) 702 | 703 | int col, row; 704 | 705 | if (b == 0) 706 | { 707 | col = 0; 708 | row = 0; 709 | } 710 | else if (b == 1) 711 | { 712 | col = 1; 713 | row = 0; 714 | } 715 | else if (b == 2) 716 | { 717 | col = 2; 718 | row = 0; 719 | } 720 | else if (b == 3) 721 | { 722 | col = 0; 723 | row = 1; 724 | } 725 | else if (b == 4) 726 | { 727 | col = 1; 728 | row = 1; 729 | } 730 | else if (b == 5) 731 | { 732 | col = 2; 733 | row = 1; 734 | } 735 | 736 | int index; 737 | 738 | if (pageNum == 2) 739 | { 740 | index = b + 5; 741 | } 742 | else if (pageNum == 3) 743 | { 744 | index = b + 10; 745 | } 746 | else if (pageNum == 4) 747 | { 748 | index = b + 15; 749 | } 750 | else if (pageNum == 5) 751 | { 752 | index = b + 20; 753 | } 754 | else if (pageNum == 6) 755 | { 756 | index = b + 25; 757 | } 758 | else 759 | { 760 | index = b; 761 | } 762 | 763 | uint16_t buttonBG; 764 | bool drawTransparent; 765 | 766 | uint16_t imageBGColor; 767 | if (islatched[index] && b < 5) 768 | { 769 | imageBGColor = getLatchImageBG(b); 770 | } 771 | else 772 | { 773 | imageBGColor = getImageBG(b); 774 | } 775 | 776 | if (imageBGColor > 0) 777 | { 778 | buttonBG = imageBGColor; 779 | drawTransparent = false; 780 | } 781 | else 782 | { 783 | if (pageNum == 0) 784 | { 785 | buttonBG = generalconfig.menuButtonColour; 786 | drawTransparent = true; 787 | } 788 | else 789 | { 790 | if (pageNum == 6 && b == 5) 791 | { 792 | buttonBG = generalconfig.menuButtonColour; 793 | drawTransparent = true; 794 | } 795 | else 796 | { 797 | buttonBG = generalconfig.functionButtonColour; 798 | drawTransparent = true; 799 | } 800 | } 801 | } 802 | tft.setFreeFont(LABEL_FONT); 803 | key[b].initButton(&tft, KEY_X + col * (KEY_W + KEY_SPACING_X), 804 | KEY_Y + row * (KEY_H + KEY_SPACING_Y), // x, y, w, h, outline, fill, text 805 | KEY_W, KEY_H, TFT_WHITE, buttonBG, TFT_WHITE, 806 | "", KEY_TEXTSIZE); 807 | key[b].drawButton(); 808 | 809 | // After drawing the button outline we call this to draw a logo. 810 | if (islatched[index] && b < 5) 811 | { 812 | drawlogo(b, col, row, drawTransparent, true); 813 | } 814 | else 815 | { 816 | drawlogo(b, col, row, drawTransparent, false); 817 | } 818 | } 819 | 820 | if (key[b].justPressed()) 821 | { 822 | int col, row; 823 | 824 | if (b == 0) 825 | { 826 | col = 0; 827 | row = 0; 828 | } 829 | else if (b == 1) 830 | { 831 | col = 1; 832 | row = 0; 833 | } 834 | else if (b == 2) 835 | { 836 | col = 2; 837 | row = 0; 838 | } 839 | else if (b == 3) 840 | { 841 | col = 0; 842 | row = 1; 843 | } 844 | else if (b == 4) 845 | { 846 | col = 1; 847 | row = 1; 848 | } 849 | else if (b == 5) 850 | { 851 | col = 2; 852 | row = 1; 853 | } 854 | 855 | tft.setFreeFont(LABEL_FONT); 856 | key[b].initButton(&tft, KEY_X + col * (KEY_W + KEY_SPACING_X), 857 | KEY_Y + row * (KEY_H + KEY_SPACING_Y), // x, y, w, h, outline, fill, text 858 | KEY_W, KEY_H, TFT_WHITE, TFT_WHITE, TFT_WHITE, 859 | "", KEY_TEXTSIZE); 860 | key[b].drawButton(); 861 | 862 | //---------------------------------------- Button press handeling -------------------------------------------------- 863 | 864 | if (pageNum == 0) //Home menu 865 | { 866 | if (b == 0) // Button 0 867 | { 868 | pageNum = 1; 869 | drawKeypad(); 870 | } 871 | else if (b == 1) // Button 1 872 | { 873 | pageNum = 2; 874 | drawKeypad(); 875 | } 876 | else if (b == 2) // Button 2 877 | { 878 | pageNum = 3; 879 | drawKeypad(); 880 | } 881 | else if (b == 3) // Button 3 882 | { 883 | pageNum = 4; 884 | drawKeypad(); 885 | } 886 | else if (b == 4) // Button 4 887 | { 888 | pageNum = 5; 889 | drawKeypad(); 890 | } 891 | else if (b == 5) // Button 5 892 | { 893 | pageNum = 6; 894 | drawKeypad(); 895 | } 896 | } 897 | 898 | else if (pageNum == 1) // Menu 1 899 | { 900 | if (b == 0) // Button 0 901 | { 902 | bleKeyboardAction(menu1.button0.actions.action0, menu1.button0.actions.value0, menu1.button0.actions.symbol0); 903 | bleKeyboardAction(menu1.button0.actions.action1, menu1.button0.actions.value1, menu1.button0.actions.symbol1); 904 | bleKeyboardAction(menu1.button0.actions.action2, menu1.button0.actions.value2, menu1.button0.actions.symbol2); 905 | bleKeyboard.releaseAll(); 906 | if (menu1.button0.latch) 907 | { 908 | if (islatched[0]) 909 | { 910 | islatched[0] = 0; 911 | } 912 | else 913 | { 914 | islatched[0] = 1; 915 | } 916 | } 917 | } 918 | else if (b == 1) // Button 1 919 | { 920 | bleKeyboardAction(menu1.button1.actions.action0, menu1.button1.actions.value0, menu1.button1.actions.symbol0); 921 | bleKeyboardAction(menu1.button1.actions.action1, menu1.button1.actions.value1, menu1.button1.actions.symbol1); 922 | bleKeyboardAction(menu1.button1.actions.action2, menu1.button1.actions.value2, menu1.button1.actions.symbol2); 923 | bleKeyboard.releaseAll(); 924 | if (menu1.button1.latch) 925 | { 926 | if (islatched[1]) 927 | { 928 | islatched[1] = 0; 929 | } 930 | else 931 | { 932 | islatched[1] = 1; 933 | } 934 | } 935 | } 936 | else if (b == 2) // Button 2 937 | { 938 | bleKeyboardAction(menu1.button2.actions.action0, menu1.button2.actions.value0, menu1.button2.actions.symbol0); 939 | bleKeyboardAction(menu1.button2.actions.action1, menu1.button2.actions.value1, menu1.button2.actions.symbol1); 940 | bleKeyboardAction(menu1.button2.actions.action2, menu1.button2.actions.value2, menu1.button2.actions.symbol2); 941 | bleKeyboard.releaseAll(); 942 | if (menu1.button2.latch) 943 | { 944 | if (islatched[2]) 945 | { 946 | islatched[2] = 0; 947 | } 948 | else 949 | { 950 | islatched[2] = 1; 951 | } 952 | } 953 | } 954 | else if (b == 3) // Button 3 955 | { 956 | bleKeyboardAction(menu1.button3.actions.action0, menu1.button3.actions.value0, menu1.button3.actions.symbol0); 957 | bleKeyboardAction(menu1.button3.actions.action1, menu1.button3.actions.value1, menu1.button3.actions.symbol1); 958 | bleKeyboardAction(menu1.button3.actions.action2, menu1.button3.actions.value2, menu1.button3.actions.symbol2); 959 | bleKeyboard.releaseAll(); 960 | if (menu1.button3.latch) 961 | { 962 | if (islatched[3]) 963 | { 964 | islatched[3] = 0; 965 | } 966 | else 967 | { 968 | islatched[3] = 1; 969 | } 970 | } 971 | } 972 | else if (b == 4) // Button 4 973 | { 974 | bleKeyboardAction(menu1.button4.actions.action0, menu1.button4.actions.value0, menu1.button4.actions.symbol0); 975 | bleKeyboardAction(menu1.button4.actions.action1, menu1.button4.actions.value1, menu1.button4.actions.symbol1); 976 | bleKeyboardAction(menu1.button4.actions.action2, menu1.button4.actions.value2, menu1.button4.actions.symbol2); 977 | bleKeyboard.releaseAll(); 978 | if (menu1.button4.latch) 979 | { 980 | if (islatched[4]) 981 | { 982 | islatched[4] = 0; 983 | } 984 | else 985 | { 986 | islatched[4] = 1; 987 | } 988 | } 989 | } 990 | else if (b == 5) // Button 5 / Back home 991 | { 992 | pageNum = 0; 993 | drawKeypad(); 994 | } 995 | } 996 | 997 | else if (pageNum == 2) // Menu 2 998 | { 999 | if (b == 0) // Button 0 1000 | { 1001 | bleKeyboardAction(menu2.button0.actions.action0, menu2.button0.actions.value0, menu2.button0.actions.symbol0); 1002 | bleKeyboardAction(menu2.button0.actions.action1, menu2.button0.actions.value1, menu2.button0.actions.symbol1); 1003 | bleKeyboardAction(menu2.button0.actions.action2, menu2.button0.actions.value2, menu2.button0.actions.symbol2); 1004 | bleKeyboard.releaseAll(); 1005 | if (menu2.button0.latch) 1006 | { 1007 | if (islatched[5]) 1008 | { 1009 | islatched[5] = 0; 1010 | } 1011 | else 1012 | { 1013 | islatched[5] = 1; 1014 | } 1015 | } 1016 | } 1017 | else if (b == 1) // Button 1 1018 | { 1019 | bleKeyboardAction(menu2.button1.actions.action0, menu2.button1.actions.value0, menu2.button1.actions.symbol0); 1020 | bleKeyboardAction(menu2.button1.actions.action1, menu2.button1.actions.value1, menu2.button1.actions.symbol1); 1021 | bleKeyboardAction(menu2.button1.actions.action2, menu2.button1.actions.value2, menu2.button1.actions.symbol2); 1022 | bleKeyboard.releaseAll(); 1023 | if (menu2.button1.latch) 1024 | { 1025 | if (islatched[6]) 1026 | { 1027 | islatched[6] = 0; 1028 | } 1029 | else 1030 | { 1031 | islatched[6] = 1; 1032 | } 1033 | } 1034 | } 1035 | else if (b == 2) // Button 2 1036 | { 1037 | bleKeyboardAction(menu2.button2.actions.action0, menu2.button2.actions.value0, menu2.button2.actions.symbol0); 1038 | bleKeyboardAction(menu2.button2.actions.action1, menu2.button2.actions.value1, menu2.button2.actions.symbol1); 1039 | bleKeyboardAction(menu2.button2.actions.action2, menu2.button2.actions.value2, menu2.button2.actions.symbol2); 1040 | bleKeyboard.releaseAll(); 1041 | if (menu2.button2.latch) 1042 | { 1043 | if (islatched[7]) 1044 | { 1045 | islatched[7] = 0; 1046 | } 1047 | else 1048 | { 1049 | islatched[7] = 1; 1050 | } 1051 | } 1052 | } 1053 | else if (b == 3) // Button 3 1054 | { 1055 | bleKeyboardAction(menu2.button3.actions.action0, menu2.button3.actions.value0, menu2.button3.actions.symbol0); 1056 | bleKeyboardAction(menu2.button3.actions.action1, menu2.button3.actions.value1, menu2.button3.actions.symbol1); 1057 | bleKeyboardAction(menu2.button3.actions.action2, menu2.button3.actions.value2, menu2.button3.actions.symbol2); 1058 | bleKeyboard.releaseAll(); 1059 | if (menu2.button3.latch) 1060 | { 1061 | if (islatched[8]) 1062 | { 1063 | islatched[8] = 0; 1064 | } 1065 | else 1066 | { 1067 | islatched[8] = 1; 1068 | } 1069 | } 1070 | } 1071 | else if (b == 4) // Button 4 1072 | { 1073 | bleKeyboardAction(menu2.button4.actions.action0, menu2.button4.actions.value0, menu2.button4.actions.symbol0); 1074 | bleKeyboardAction(menu2.button4.actions.action1, menu2.button4.actions.value1, menu2.button4.actions.symbol1); 1075 | bleKeyboardAction(menu2.button4.actions.action2, menu2.button4.actions.value2, menu2.button4.actions.symbol2); 1076 | bleKeyboard.releaseAll(); 1077 | if (menu2.button4.latch) 1078 | { 1079 | if (islatched[9]) 1080 | { 1081 | islatched[9] = 0; 1082 | } 1083 | else 1084 | { 1085 | islatched[9] = 1; 1086 | } 1087 | } 1088 | } 1089 | else if (b == 5) // Button 5 / Back home 1090 | { 1091 | pageNum = 0; 1092 | drawKeypad(); 1093 | } 1094 | } 1095 | 1096 | else if (pageNum == 3) // Menu 3 1097 | { 1098 | if (b == 0) // Button 0 1099 | { 1100 | bleKeyboardAction(menu3.button0.actions.action0, menu3.button0.actions.value0, menu3.button0.actions.symbol0); 1101 | bleKeyboardAction(menu3.button0.actions.action1, menu3.button0.actions.value1, menu3.button0.actions.symbol1); 1102 | bleKeyboardAction(menu3.button0.actions.action2, menu3.button0.actions.value2, menu3.button0.actions.symbol2); 1103 | bleKeyboard.releaseAll(); 1104 | if (menu3.button0.latch) 1105 | { 1106 | if (islatched[10]) 1107 | { 1108 | islatched[10] = 0; 1109 | } 1110 | else 1111 | { 1112 | islatched[10] = 1; 1113 | } 1114 | } 1115 | } 1116 | else if (b == 1) // Button 1 1117 | { 1118 | bleKeyboardAction(menu3.button1.actions.action0, menu3.button1.actions.value0, menu3.button1.actions.symbol0); 1119 | bleKeyboardAction(menu3.button1.actions.action1, menu3.button1.actions.value1, menu3.button1.actions.symbol1); 1120 | bleKeyboardAction(menu3.button1.actions.action2, menu3.button1.actions.value2, menu3.button1.actions.symbol2); 1121 | bleKeyboard.releaseAll(); 1122 | if (menu3.button1.latch) 1123 | { 1124 | if (islatched[11]) 1125 | { 1126 | islatched[11] = 0; 1127 | } 1128 | else 1129 | { 1130 | islatched[11] = 1; 1131 | } 1132 | } 1133 | } 1134 | else if (b == 2) // Button 2 1135 | { 1136 | bleKeyboardAction(menu3.button2.actions.action0, menu3.button2.actions.value0, menu3.button2.actions.symbol0); 1137 | bleKeyboardAction(menu3.button2.actions.action1, menu3.button2.actions.value1, menu3.button2.actions.symbol1); 1138 | bleKeyboardAction(menu3.button2.actions.action2, menu3.button2.actions.value2, menu3.button2.actions.symbol2); 1139 | bleKeyboard.releaseAll(); 1140 | if (menu3.button2.latch) 1141 | { 1142 | if (islatched[12]) 1143 | { 1144 | islatched[12] = 0; 1145 | } 1146 | else 1147 | { 1148 | islatched[12] = 1; 1149 | } 1150 | } 1151 | } 1152 | else if (b == 3) // Button 3 1153 | { 1154 | bleKeyboardAction(menu3.button3.actions.action0, menu3.button3.actions.value0, menu3.button3.actions.symbol0); 1155 | bleKeyboardAction(menu3.button3.actions.action1, menu3.button3.actions.value1, menu3.button3.actions.symbol1); 1156 | bleKeyboardAction(menu3.button3.actions.action2, menu3.button3.actions.value2, menu3.button3.actions.symbol2); 1157 | bleKeyboard.releaseAll(); 1158 | if (menu3.button3.latch) 1159 | { 1160 | if (islatched[13]) 1161 | { 1162 | islatched[13] = 0; 1163 | } 1164 | else 1165 | { 1166 | islatched[13] = 1; 1167 | } 1168 | } 1169 | } 1170 | else if (b == 4) // Button 4 1171 | { 1172 | bleKeyboardAction(menu3.button4.actions.action0, menu3.button4.actions.value0, menu3.button4.actions.symbol0); 1173 | bleKeyboardAction(menu3.button4.actions.action1, menu3.button4.actions.value1, menu3.button4.actions.symbol1); 1174 | bleKeyboardAction(menu3.button4.actions.action2, menu3.button4.actions.value2, menu3.button4.actions.symbol2); 1175 | bleKeyboard.releaseAll(); 1176 | if (menu3.button4.latch) 1177 | { 1178 | if (islatched[14]) 1179 | { 1180 | islatched[14] = 0; 1181 | } 1182 | else 1183 | { 1184 | islatched[14] = 1; 1185 | } 1186 | } 1187 | } 1188 | else if (b == 5) // Button 5 / Back home 1189 | { 1190 | pageNum = 0; 1191 | drawKeypad(); 1192 | } 1193 | } 1194 | 1195 | else if (pageNum == 4) // Menu 4 1196 | { 1197 | if (b == 0) // Button 0 1198 | { 1199 | bleKeyboardAction(menu4.button0.actions.action0, menu4.button0.actions.value0, menu4.button0.actions.symbol0); 1200 | bleKeyboardAction(menu4.button0.actions.action1, menu4.button0.actions.value1, menu4.button0.actions.symbol1); 1201 | bleKeyboardAction(menu4.button0.actions.action2, menu4.button0.actions.value2, menu4.button0.actions.symbol2); 1202 | bleKeyboard.releaseAll(); 1203 | if (menu4.button0.latch) 1204 | { 1205 | if (islatched[15]) 1206 | { 1207 | islatched[15] = 0; 1208 | } 1209 | else 1210 | { 1211 | islatched[15] = 1; 1212 | } 1213 | } 1214 | } 1215 | else if (b == 1) // Button 1 1216 | { 1217 | bleKeyboardAction(menu4.button1.actions.action0, menu4.button1.actions.value0, menu4.button1.actions.symbol0); 1218 | bleKeyboardAction(menu4.button1.actions.action1, menu4.button1.actions.value1, menu4.button1.actions.symbol1); 1219 | bleKeyboardAction(menu4.button1.actions.action2, menu4.button1.actions.value2, menu4.button1.actions.symbol2); 1220 | bleKeyboard.releaseAll(); 1221 | if (menu4.button1.latch) 1222 | { 1223 | if (islatched[16]) 1224 | { 1225 | islatched[16] = 0; 1226 | } 1227 | else 1228 | { 1229 | islatched[16] = 1; 1230 | } 1231 | } 1232 | } 1233 | else if (b == 2) // Button 2 1234 | { 1235 | bleKeyboardAction(menu4.button2.actions.action0, menu4.button2.actions.value0, menu4.button2.actions.symbol0); 1236 | bleKeyboardAction(menu4.button2.actions.action1, menu4.button2.actions.value1, menu4.button2.actions.symbol1); 1237 | bleKeyboardAction(menu4.button2.actions.action2, menu4.button2.actions.value2, menu4.button2.actions.symbol2); 1238 | bleKeyboard.releaseAll(); 1239 | if (menu4.button2.latch) 1240 | { 1241 | if (islatched[17]) 1242 | { 1243 | islatched[17] = 0; 1244 | } 1245 | else 1246 | { 1247 | islatched[17] = 1; 1248 | } 1249 | } 1250 | } 1251 | else if (b == 3) // Button 3 1252 | { 1253 | bleKeyboardAction(menu4.button3.actions.action0, menu4.button3.actions.value0, menu4.button3.actions.symbol0); 1254 | bleKeyboardAction(menu4.button3.actions.action1, menu4.button3.actions.value1, menu4.button3.actions.symbol1); 1255 | bleKeyboardAction(menu4.button3.actions.action2, menu4.button3.actions.value2, menu4.button3.actions.symbol2); 1256 | bleKeyboard.releaseAll(); 1257 | if (menu4.button3.latch) 1258 | { 1259 | if (islatched[18]) 1260 | { 1261 | islatched[18] = 0; 1262 | } 1263 | else 1264 | { 1265 | islatched[18] = 1; 1266 | } 1267 | } 1268 | } 1269 | else if (b == 4) // Button 4 1270 | { 1271 | bleKeyboardAction(menu4.button4.actions.action0, menu4.button4.actions.value0, menu4.button4.actions.symbol0); 1272 | bleKeyboardAction(menu4.button4.actions.action1, menu4.button4.actions.value1, menu4.button4.actions.symbol1); 1273 | bleKeyboardAction(menu4.button4.actions.action2, menu4.button4.actions.value2, menu4.button4.actions.symbol2); 1274 | bleKeyboard.releaseAll(); 1275 | if (menu4.button4.latch) 1276 | { 1277 | if (islatched[19]) 1278 | { 1279 | islatched[19] = 0; 1280 | } 1281 | else 1282 | { 1283 | islatched[19] = 1; 1284 | } 1285 | } 1286 | } 1287 | else if (b == 5) // Button 5 / Back home 1288 | { 1289 | pageNum = 0; 1290 | drawKeypad(); 1291 | } 1292 | } 1293 | 1294 | else if (pageNum == 5) // Menu 5 1295 | { 1296 | if (b == 0) // Button 0 1297 | { 1298 | bleKeyboardAction(menu5.button0.actions.action0, menu5.button0.actions.value0, menu5.button0.actions.symbol0); 1299 | bleKeyboardAction(menu5.button0.actions.action1, menu5.button0.actions.value1, menu5.button0.actions.symbol1); 1300 | bleKeyboardAction(menu5.button0.actions.action2, menu5.button0.actions.value2, menu5.button0.actions.symbol2); 1301 | bleKeyboard.releaseAll(); 1302 | if (menu5.button0.latch) 1303 | { 1304 | if (islatched[20]) 1305 | { 1306 | islatched[20] = 0; 1307 | } 1308 | else 1309 | { 1310 | islatched[20] = 1; 1311 | } 1312 | } 1313 | } 1314 | else if (b == 1) // Button 1 1315 | { 1316 | bleKeyboardAction(menu5.button1.actions.action0, menu5.button1.actions.value0, menu5.button1.actions.symbol0); 1317 | bleKeyboardAction(menu5.button1.actions.action1, menu5.button1.actions.value1, menu5.button1.actions.symbol1); 1318 | bleKeyboardAction(menu5.button1.actions.action2, menu5.button1.actions.value2, menu5.button1.actions.symbol2); 1319 | bleKeyboard.releaseAll(); 1320 | if (menu5.button1.latch) 1321 | { 1322 | if (islatched[21]) 1323 | { 1324 | islatched[21] = 0; 1325 | } 1326 | else 1327 | { 1328 | islatched[21] = 1; 1329 | } 1330 | } 1331 | } 1332 | else if (b == 2) // Button 2 1333 | { 1334 | bleKeyboardAction(menu5.button2.actions.action0, menu5.button2.actions.value0, menu5.button2.actions.symbol0); 1335 | bleKeyboardAction(menu5.button2.actions.action1, menu5.button2.actions.value1, menu5.button2.actions.symbol1); 1336 | bleKeyboardAction(menu5.button2.actions.action2, menu5.button2.actions.value2, menu5.button2.actions.symbol2); 1337 | bleKeyboard.releaseAll(); 1338 | if (menu5.button2.latch) 1339 | { 1340 | if (islatched[22]) 1341 | { 1342 | islatched[22] = 0; 1343 | } 1344 | else 1345 | { 1346 | islatched[22] = 1; 1347 | } 1348 | } 1349 | } 1350 | else if (b == 3) // Button 3 1351 | { 1352 | bleKeyboardAction(menu5.button3.actions.action0, menu5.button3.actions.value0, menu5.button3.actions.symbol0); 1353 | bleKeyboardAction(menu5.button3.actions.action1, menu5.button3.actions.value1, menu5.button3.actions.symbol1); 1354 | bleKeyboardAction(menu5.button3.actions.action2, menu5.button3.actions.value2, menu5.button3.actions.symbol2); 1355 | bleKeyboard.releaseAll(); 1356 | if (menu5.button3.latch) 1357 | { 1358 | if (islatched[23]) 1359 | { 1360 | islatched[23] = 0; 1361 | } 1362 | else 1363 | { 1364 | islatched[23] = 1; 1365 | } 1366 | } 1367 | } 1368 | else if (b == 4) // Button 4 1369 | { 1370 | bleKeyboardAction(menu5.button4.actions.action0, menu5.button4.actions.value0, menu5.button4.actions.symbol0); 1371 | bleKeyboardAction(menu5.button4.actions.action1, menu5.button4.actions.value1, menu5.button4.actions.symbol1); 1372 | bleKeyboardAction(menu5.button4.actions.action2, menu5.button4.actions.value2, menu5.button4.actions.symbol2); 1373 | bleKeyboard.releaseAll(); 1374 | if (menu5.button4.latch) 1375 | { 1376 | if (islatched[24]) 1377 | { 1378 | islatched[24] = 0; 1379 | } 1380 | else 1381 | { 1382 | islatched[24] = 1; 1383 | } 1384 | } 1385 | } 1386 | else if (b == 5) // Button 5 / Back home 1387 | { 1388 | pageNum = 0; 1389 | drawKeypad(); 1390 | } 1391 | } 1392 | 1393 | else if (pageNum == 6) // Settings page 1394 | { 1395 | if (b == 0) // Button 0 1396 | { 1397 | bleKeyboardAction(11, 1, 0); 1398 | } 1399 | else if (b == 1) // Button 1 1400 | { 1401 | bleKeyboardAction(11, 2, 0); 1402 | } 1403 | else if (b == 2) // Button 2 1404 | { 1405 | bleKeyboardAction(11, 3, 0); 1406 | } 1407 | else if (b == 3) // Button 3 1408 | { 1409 | bleKeyboardAction(11, 4, 0); 1410 | if (islatched[28]) 1411 | { 1412 | islatched[28] = 0; 1413 | } 1414 | else 1415 | { 1416 | islatched[28] = 1; 1417 | } 1418 | } 1419 | else if (b == 4) // Button 4 1420 | { 1421 | pageNum = 8; 1422 | drawKeypad(); 1423 | } 1424 | else if (b == 5) 1425 | { 1426 | pageNum = 0; 1427 | drawKeypad(); 1428 | } 1429 | } 1430 | 1431 | delay(10); // UI debouncing 1432 | } 1433 | } 1434 | } 1435 | } 1436 | --------------------------------------------------------------------------------