├── .cproject ├── .gitignore ├── .project ├── LICENSE ├── Makefile ├── README.md ├── components ├── .gitignore └── cpp_utils ├── docs ├── design.md ├── images │ ├── FileSystem.png │ └── System.png └── purpose.md ├── fatfs_data ├── ESP32Explorer.html ├── ESP32Explorer.js ├── images │ ├── check.png │ ├── cross.png │ ├── in.png │ ├── info.png │ └── out.png ├── jQuery-File-Upload-9.18.0 │ ├── .gitignore │ ├── .jshintrc │ ├── .npmignore │ ├── CONTRIBUTING.md │ ├── LICENSE │ ├── README.md │ ├── angularjs.html │ ├── basic-plus.html │ ├── basic.html │ ├── bower-version-update.js │ ├── bower.json │ ├── cors │ │ ├── postmessage.html │ │ └── result.html │ ├── css │ │ ├── demo-ie8.css │ │ ├── demo.css │ │ ├── jquery.fileupload-noscript.css │ │ ├── jquery.fileupload-ui-noscript.css │ │ ├── jquery.fileupload-ui.css │ │ ├── jquery.fileupload.css │ │ └── style.css │ ├── img │ │ ├── loading.gif │ │ └── progressbar.gif │ ├── index.html │ ├── jquery-ui.html │ ├── js │ │ ├── app.js │ │ ├── cors │ │ │ ├── jquery.postmessage-transport.js │ │ │ └── jquery.xdr-transport.js │ │ ├── jquery.fileupload-angular.js │ │ ├── jquery.fileupload-audio.js │ │ ├── jquery.fileupload-image.js │ │ ├── jquery.fileupload-jquery-ui.js │ │ ├── jquery.fileupload-process.js │ │ ├── jquery.fileupload-ui.js │ │ ├── jquery.fileupload-validate.js │ │ ├── jquery.fileupload-video.js │ │ ├── jquery.fileupload.js │ │ ├── jquery.iframe-transport.js │ │ ├── main.js │ │ └── vendor │ │ │ └── jquery.ui.widget.js │ ├── package.json │ ├── server │ │ ├── gae-go │ │ │ ├── app.yaml │ │ │ ├── app │ │ │ │ └── main.go │ │ │ └── static │ │ │ │ ├── favicon.ico │ │ │ │ └── robots.txt │ │ ├── gae-python │ │ │ ├── app.yaml │ │ │ ├── main.py │ │ │ └── static │ │ │ │ ├── favicon.ico │ │ │ │ └── robots.txt │ │ └── php │ │ │ ├── Dockerfile │ │ │ ├── UploadHandler.php │ │ │ ├── docker-compose.yml │ │ │ ├── files │ │ │ ├── .gitignore │ │ │ └── .htaccess │ │ │ └── index.php │ └── test │ │ ├── index.html │ │ └── test.js ├── jquery │ └── jquery-3.2.1.min.js ├── jqueryui │ ├── AUTHORS.txt │ ├── LICENSE.txt │ ├── external │ │ └── jquery │ │ │ └── jquery.js │ ├── images │ │ ├── ui-icons_444444_256x240.png │ │ ├── ui-icons_555555_256x240.png │ │ ├── ui-icons_777620_256x240.png │ │ ├── ui-icons_777777_256x240.png │ │ ├── ui-icons_cc0000_256x240.png │ │ └── ui-icons_ffffff_256x240.png │ ├── index.html │ ├── jquery-ui.css │ ├── jquery-ui.js │ ├── jquery-ui.min.css │ ├── jquery-ui.min.js │ ├── jquery-ui.structure.css │ ├── jquery-ui.structure.min.css │ ├── jquery-ui.theme.css │ ├── jquery-ui.theme.min.css │ └── package.json └── jstree │ ├── jstree.min.js │ └── themes │ ├── default-dark │ ├── 32px.png │ ├── 40px.png │ ├── style.css │ ├── style.min.css │ └── throbber.gif │ └── default │ ├── 32px.png │ ├── 40px.png │ ├── style.css │ ├── style.min.css │ └── throbber.gif ├── main ├── BLEExplorer.cpp ├── BLEExplorer.h ├── BootWiFi.cpp ├── BootWiFi.h ├── ESP32Explorer.cpp ├── ESP32Explorer.h ├── FILESYSTEM_JSON.cpp ├── GPIO_JSON.cpp ├── I2C_COMMANDS.cpp ├── I2C_SCAN.cpp ├── I2S_JSON.cpp ├── SYSTEM_JSON.cpp ├── WIFI_JSON.cpp ├── common.h ├── component.mk ├── main.cpp └── selectAP.h ├── partitions.csv └── sdkconfig /.cproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | sdkconfig.old 3 | .cproject 4 | .project 5 | .settings/ 6 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | ESP32_Explorer 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | org.eclipse.cdt.core.cnature 23 | org.eclipse.cdt.core.ccnature 24 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 25 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 26 | 27 | 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a 3 | # project subdirectory. 4 | # 5 | 6 | PROJECT_NAME := app-template 7 | 8 | include $(IDF_PATH)/make/project.mk 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## ESP32 Explorer 2 | 3 | ** WARNING!! - VERY EARLY CODE ** 4 | 5 | A utility library / application for investigating the ESP32. 6 | 7 | Locked within an ESP32 at runtime is a wealth of information. This includes: 8 | 9 | * Your availabile memory 10 | * Your WiFi connections 11 | * Your GPIO status 12 | * The files on your flash file system 13 | * The status of your logging enablement 14 | * The partitions in use 15 | * The state of FreeRTOS tasks 16 | * and *much* more ... 17 | 18 | As I wrote applications to run on the ESP32, I found that from time to time I would need this information or wish to tweak some settings at runtime. I would inject code into my application, perform those tests and then remove it. As I wrote more applications, I found that I was repeating these steps over and over again. This notion became the kernel of this project. 19 | 20 | The purpose of the project is to produce a library which, when linked with your own application can reveal the content of your ESP32 at runtime **and** allow you to tweak settings. 21 | 22 | When linked with your application, it will start listening as a network endpoint (an HTTP server) to accept external calls for information and receive external calls to change state and data. In addition to the library you link with your ESP32 app, there is a web page that can be opened which presents the information in a series of tabbed pages. 23 | 24 | ![](docs/images/System.png) 25 | 26 | Some pages have additional tabs on them. 27 | 28 | ## File System 29 | The File System page shows the file system found on the ESP32. From here you can see if the files you expect to be available are present. You also have the opportunity to upload new and updated files. 30 | 31 | ![](docs/images/FileSystem.png) -------------------------------------------------------------------------------- /components/.gitignore: -------------------------------------------------------------------------------- 1 | /cpp_utils/ 2 | -------------------------------------------------------------------------------- /components/cpp_utils: -------------------------------------------------------------------------------- 1 | /home/esp32/synchro/esp32-snippets/cpp_utils/ -------------------------------------------------------------------------------- /docs/design.md: -------------------------------------------------------------------------------- 1 | ## Design 2 | The library will run a Web Server. The files served by the Web Server will come from a file system contained 3 | in a partition. The files are supplied as part of the solution and are a mixture of HTML and JavaScript. When 4 | a browser connects to the ESP32 hosted Web Server, it is these files that are brought back to the browser and 5 | executed. The files will then present an attractive user interface for the user to navigate across the distinct 6 | parts of the ESP32 environment. 7 | 8 | 9 | ### File system 10 | The file system used is the FATFS supplied as part of ESP-IDF. 11 | 12 | ### Browser UI 13 | The browser UI is built from a mixture of HTML5, JavaScript, jQuery and jQuery UI. Additional open source components 14 | are used for specialized visualization including: 15 | 16 | * jstree 17 | 18 | 19 | ## Components 20 | 21 | ### File system 22 | The file system examination story uses standard IO functions to examine the file system directory structures. A 23 | JSON representation of the file system is built and sent back to the browser. The browser then examines the JSON 24 | data received and visualizes it through the "jstree" library, 25 | 26 | -------------------------------------------------------------------------------- /docs/images/FileSystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/docs/images/FileSystem.png -------------------------------------------------------------------------------- /docs/images/System.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/docs/images/System.png -------------------------------------------------------------------------------- /docs/purpose.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | The core notion is that the library will expose a Web Server that will serve up information about the operation 3 | of the ESP32. 4 | 5 | The ESP32 can be thought of as having multiple separate internal functional areas. These include: 6 | 7 | * WiFi 8 | * GPIO 9 | * File systems 10 | * I2S 11 | 12 | In addition there is the ESP32 "System" itself which includes memory management, flash partitions and more. 13 | 14 | As an application that you may have written runs on the ESP32, we don't necessarily have good visibility into the state. 15 | We can, of course, attach debuggers and other useful tools but they pretty much give us insight into the operation 16 | and logic of your own application, and not the environment in which your application runs. This library can be linked 17 | with your own application to present the information you might otherwise not see. -------------------------------------------------------------------------------- /fatfs_data/images/check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/images/check.png -------------------------------------------------------------------------------- /fatfs_data/images/cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/images/cross.png -------------------------------------------------------------------------------- /fatfs_data/images/in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/images/in.png -------------------------------------------------------------------------------- /fatfs_data/images/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/images/info.png -------------------------------------------------------------------------------- /fatfs_data/images/out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/images/out.png -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | node_modules 4 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.) 3 | "camelcase" : true, // true: Identifiers must be in camelCase 4 | "curly" : true, // true: Require {} for every new block or scope 5 | "eqeqeq" : true, // true: Require triple equals (===) for comparison 6 | "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty() 7 | "immed" : true, // true: Require immediate invocations to be wrapped in parens 8 | // e.g. `(function () { } ());` 9 | "indent" : 4, // {int} Number of spaces to use for indentation 10 | "latedef" : true, // true: Require variables/functions to be defined before being used 11 | "newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()` 12 | "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` 13 | "noempty" : true, // true: Prohibit use of empty blocks 14 | "nonew" : true, // true: Prohibit use of constructors for side-effects (without assignment) 15 | "plusplus" : false, // true: Prohibit use of `++` & `--` 16 | "quotmark" : "single", // Quotation mark consistency: 17 | // false : do nothing (default) 18 | // true : ensure whatever is used is consistent 19 | // "single" : require single quotes 20 | // "double" : require double quotes 21 | "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) 22 | "unused" : true, // true: Require all defined variables be used 23 | "strict" : true, // true: Requires all functions run in ES5 Strict Mode 24 | "trailing" : true, // true: Prohibit trailing whitespaces 25 | "maxparams" : false, // {int} Max number of formal params allowed per function 26 | "maxdepth" : false, // {int} Max depth of nested blocks (within functions) 27 | "maxstatements" : false, // {int} Max number statements per function 28 | "maxcomplexity" : false, // {int} Max cyclomatic complexity per function 29 | "maxlen" : false, // {int} Max number of characters per line 30 | 31 | // Relaxing 32 | "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) 33 | "boss" : false, // true: Tolerate assignments where comparisons would be expected 34 | "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. 35 | "eqnull" : false, // true: Tolerate use of `== null` 36 | "es5" : false, // true: Allow ES5 syntax (ex: getters and setters) 37 | "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`) 38 | "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features) 39 | // (ex: `for each`, multiple try/catch, function expression…) 40 | "evil" : false, // true: Tolerate use of `eval` and `new Function()` 41 | "expr" : false, // true: Tolerate `ExpressionStatement` as Programs 42 | "funcscope" : false, // true: Tolerate defining variables inside control statements" 43 | "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict') 44 | "iterator" : false, // true: Tolerate using the `__iterator__` property 45 | "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block 46 | "laxbreak" : false, // true: Tolerate possibly unsafe line breakings 47 | "laxcomma" : false, // true: Tolerate comma-first style coding 48 | "loopfunc" : false, // true: Tolerate functions being defined in loops 49 | "multistr" : false, // true: Tolerate multi-line strings 50 | "proto" : false, // true: Tolerate using the `__proto__` property 51 | "scripturl" : false, // true: Tolerate script-targeted URLs 52 | "smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment 53 | "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` 54 | "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation 55 | "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` 56 | "validthis" : false, // true: Tolerate using this in a non-constructor function 57 | 58 | // Environments 59 | "browser" : false, // Web Browser (window, document, etc) 60 | "couch" : false, // CouchDB 61 | "devel" : false, // Development/debugging (alert, confirm, etc) 62 | "dojo" : false, // Dojo Toolkit 63 | "jquery" : false, // jQuery 64 | "mootools" : false, // MooTools 65 | "node" : false, // Node.js 66 | "nonstandard" : false, // Widely adopted globals (escape, unescape, etc) 67 | "prototypejs" : false, // Prototype and Scriptaculous 68 | "rhino" : false, // Rhino 69 | "worker" : false, // Web Workers 70 | "wsh" : false, // Windows Scripting Host 71 | "yui" : false, // Yahoo User Interface 72 | 73 | // Legacy 74 | "nomen" : true, // true: Prohibit dangling `_` in variables 75 | "onevar" : true, // true: Allow only one `var` statement per function 76 | "passfail" : false, // true: Stop on first error 77 | "white" : true, // true: Check against strict whitespace and indentation rules 78 | 79 | // Custom Globals 80 | "globals" : {} // additional predefined global variables 81 | } 82 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | !css/jquery.fileupload-noscript.css 3 | !css/jquery.fileupload-ui-noscript.css 4 | !css/jquery.fileupload-ui.css 5 | !css/jquery.fileupload.css 6 | !img/loading.gif 7 | !img/progressbar.gif 8 | !js/cors/jquery.postmessage-transport.js 9 | !js/cors/jquery.xdr-transport.js 10 | !js/vendor/jquery.ui.widget.js 11 | !js/jquery.fileupload-angular.js 12 | !js/jquery.fileupload-audio.js 13 | !js/jquery.fileupload-image.js 14 | !js/jquery.fileupload-jquery-ui.js 15 | !js/jquery.fileupload-process.js 16 | !js/jquery.fileupload-ui.js 17 | !js/jquery.fileupload-validate.js 18 | !js/jquery.fileupload-video.js 19 | !js/jquery.fileupload.js 20 | !js/jquery.iframe-transport.js 21 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Please follow these pull request guidelines: 2 | 3 | 1. Update your fork to the latest upstream version. 4 | 5 | 2. Follow the coding conventions of the original source files (indentation, spaces, brackets layout). 6 | 7 | 3. Code changes must pass JSHint validation with the `.jshintrc` settings of this project. 8 | 9 | 4. Code changes must pass the QUnit tests defined in the `test` folder. 10 | 11 | 5. New features should be covered by accompanying QUnit tests. 12 | 13 | 6. Keep your commits as atomic as possible, i.e. create a new commit for every single bug fix or feature added. 14 | 15 | 7. Always add meaningful commit messages. 16 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 jQuery-File-Upload Authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/README.md: -------------------------------------------------------------------------------- 1 | # jQuery File Upload Plugin 2 | 3 | ## Demo 4 | [Demo File Upload](https://blueimp.github.io/jQuery-File-Upload/) 5 | 6 | ## Description 7 | File Upload widget with multiple file selection, drag&drop support, progress bars, validation and preview images, audio and video for jQuery. 8 | Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads. 9 | 10 | ## Setup 11 | * [How to setup the plugin on your website](https://github.com/blueimp/jQuery-File-Upload/wiki/Setup) 12 | * [How to use only the basic plugin (minimal setup guide).](https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin) 13 | 14 | ## Features 15 | * **Multiple file upload:** 16 | Allows to select multiple files at once and upload them simultaneously. 17 | * **Drag & Drop support:** 18 | Allows to upload files by dragging them from your desktop or filemanager and dropping them on your browser window. 19 | * **Upload progress bar:** 20 | Shows a progress bar indicating the upload progress for individual files and for all uploads combined. 21 | * **Cancelable uploads:** 22 | Individual file uploads can be canceled to stop the upload progress. 23 | * **Resumable uploads:** 24 | Aborted uploads can be resumed with browsers supporting the Blob API. 25 | * **Chunked uploads:** 26 | Large files can be uploaded in smaller chunks with browsers supporting the Blob API. 27 | * **Client-side image resizing:** 28 | Images can be automatically resized on client-side with browsers supporting the required JS APIs. 29 | * **Preview images, audio and video:** 30 | A preview of image, audio and video files can be displayed before uploading with browsers supporting the required APIs. 31 | * **No browser plugins (e.g. Adobe Flash) required:** 32 | The implementation is based on open standards like HTML5 and JavaScript and requires no additional browser plugins. 33 | * **Graceful fallback for legacy browsers:** 34 | Uploads files via XMLHttpRequests if supported and uses iframes as fallback for legacy browsers. 35 | * **HTML file upload form fallback:** 36 | Allows progressive enhancement by using a standard HTML file upload form as widget element. 37 | * **Cross-site file uploads:** 38 | Supports uploading files to a different domain with cross-site XMLHttpRequests or iframe redirects. 39 | * **Multiple plugin instances:** 40 | Allows to use multiple plugin instances on the same webpage. 41 | * **Customizable and extensible:** 42 | Provides an API to set individual options and define callBack methods for various upload events. 43 | * **Multipart and file contents stream uploads:** 44 | Files can be uploaded as standard "multipart/form-data" or file contents stream (HTTP PUT file upload). 45 | * **Compatible with any server-side application platform:** 46 | Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads. 47 | 48 | ## Requirements 49 | 50 | ### Mandatory requirements 51 | * [jQuery](https://jquery.com/) v. 1.6+ 52 | * [jQuery UI widget factory](https://api.jqueryui.com/jQuery.widget/) v. 1.9+ (included): Required for the basic File Upload plugin, but very lightweight without any other dependencies from the jQuery UI suite. 53 | * [jQuery Iframe Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/jquery.iframe-transport.js) (included): Required for [browsers without XHR file upload support](https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support). 54 | 55 | ### Optional requirements 56 | * [JavaScript Templates engine](https://github.com/blueimp/JavaScript-Templates) v. 2.5.4+: Used to render the selected and uploaded files for the Basic Plus UI and jQuery UI versions. 57 | * [JavaScript Load Image library](https://github.com/blueimp/JavaScript-Load-Image) v. 1.13.0+: Required for the image previews and resizing functionality. 58 | * [JavaScript Canvas to Blob polyfill](https://github.com/blueimp/JavaScript-Canvas-to-Blob) v. 2.1.1+:Required for the image previews and resizing functionality. 59 | * [blueimp Gallery](https://github.com/blueimp/Gallery) v. 2.15.1+: Used to display the uploaded images in a lightbox. 60 | * [Bootstrap](http://getbootstrap.com/) v. 3.2.0+ 61 | * [Glyphicons](http://glyphicons.com/) 62 | 63 | The user interface of all versions except the jQuery UI version is built with [Bootstrap](http://getbootstrap.com/) and icons from [Glyphicons](http://glyphicons.com/). 64 | 65 | ### Cross-domain requirements 66 | [Cross-domain File Uploads](https://github.com/blueimp/jQuery-File-Upload/wiki/Cross-domain-uploads) using the [Iframe Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/jquery.iframe-transport.js) require a redirect back to the origin server to retrieve the upload results. The [example implementation](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/main.js) makes use of [result.html](https://github.com/blueimp/jQuery-File-Upload/blob/master/cors/result.html) as a static redirect page for the origin server. 67 | 68 | The repository also includes the [jQuery XDomainRequest Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/cors/jquery.xdr-transport.js), which enables limited cross-domain AJAX requests in Microsoft Internet Explorer 8 and 9 (IE 10 supports cross-domain XHR requests). 69 | The XDomainRequest object allows GET and POST requests only and doesn't support file uploads. It is used on the [Demo](https://blueimp.github.io/jQuery-File-Upload/) to delete uploaded files from the cross-domain demo file upload service. 70 | 71 | ### Custom Backends 72 | 73 | You can add support for various backends by adhering to the specification [outlined here](https://github.com/blueimp/jQuery-File-Upload/wiki/JSON-Response). 74 | 75 | ## Browsers 76 | 77 | ### Desktop browsers 78 | The File Upload plugin is regularly tested with the latest browser versions and supports the following minimal versions: 79 | 80 | * Google Chrome 81 | * Apple Safari 4.0+ 82 | * Mozilla Firefox 3.0+ 83 | * Opera 11.0+ 84 | * Microsoft Internet Explorer 6.0+ 85 | 86 | ### Mobile browsers 87 | The File Upload plugin has been tested with and supports the following mobile browsers: 88 | 89 | * Apple Safari on iOS 6.0+ 90 | * Google Chrome on iOS 6.0+ 91 | * Google Chrome on Android 4.0+ 92 | * Default Browser on Android 2.3+ 93 | * Opera Mobile 12.0+ 94 | 95 | ### Supported features 96 | For a detailed overview of the features supported by each browser version, please have a look at the [Extended browser support information](https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support). 97 | 98 | ## Contributing 99 | **Bug fixes** and **new features** can be proposed using [pull requests](https://github.com/blueimp/jQuery-File-Upload/pulls). 100 | Please read the [contribution guidelines](https://github.com/blueimp/jQuery-File-Upload/blob/master/CONTRIBUTING.md) before submitting a pull request. 101 | 102 | ## Support 103 | This project is actively maintained, but there is no official support channel. 104 | If you have a question that another developer might help you with, please post to [Stack Overflow](http://stackoverflow.com/questions/tagged/blueimp+jquery+file-upload) and tag your question with `blueimp jquery file upload`. 105 | 106 | ## License 107 | Released under the [MIT license](https://opensource.org/licenses/MIT). 108 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/basic-plus.html: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 17 | 18 | 19 | jQuery File Upload Demo - Basic Plus version 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 50 |
51 |

jQuery File Upload Demo

52 |

Basic Plus version

53 | 60 |
61 |
62 |

File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery.
63 | Supports cross-domain, chunked and resumable file uploads and client-side image resizing.
64 | Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.

65 |
66 |
67 | 68 | 69 | 70 | Add files... 71 | 72 | 73 | 74 |
75 |
76 | 77 |
78 |
79 |
80 | 81 |
82 |
83 |
84 |
85 |

Demo Notes

86 |
87 |
88 |
    89 |
  • The maximum file size for uploads in this demo is 999 KB (default file size is unlimited).
  • 90 |
  • Only image files (JPG, GIF, PNG) are allowed in this demo (by default there is no file type restriction).
  • 91 |
  • Uploaded files will be deleted automatically after 5 minutes or less (demo files are stored in memory).
  • 92 |
  • You can drag & drop files from your desktop on this webpage (see Browser support).
  • 93 |
  • Please refer to the project website and documentation for more information.
  • 94 |
  • Built with the Bootstrap CSS framework and Icons from Glyphicons.
  • 95 |
96 |
97 |
98 |
99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 225 | 226 | 227 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/basic.html: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 17 | 18 | 19 | jQuery File Upload Demo - Basic version 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 50 |
51 |

jQuery File Upload Demo

52 |

Basic version

53 | 60 |
61 |
62 |

File Upload widget with multiple file selection, drag&drop support and progress bar for jQuery.
63 | Supports cross-domain, chunked and resumable file uploads.
64 | Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.

65 |
66 |
67 | 68 | 69 | 70 | Select files... 71 | 72 | 73 | 74 |
75 |
76 | 77 |
78 |
79 |
80 | 81 |
82 |
83 |
84 |
85 |

Demo Notes

86 |
87 |
88 |
    89 |
  • The maximum file size for uploads in this demo is 999 KB (default file size is unlimited).
  • 90 |
  • Only image files (JPG, GIF, PNG) are allowed in this demo (by default there is no file type restriction).
  • 91 |
  • Uploaded files will be deleted automatically after 5 minutes or less (demo files are stored in memory).
  • 92 |
  • You can drag & drop files from your desktop on this webpage (see Browser support).
  • 93 |
  • Please refer to the project website and documentation for more information.
  • 94 |
  • Built with the Bootstrap CSS framework and Icons from Glyphicons.
  • 95 |
96 |
97 |
98 |
99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/bower-version-update.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | var path = require('path'); 6 | var packageJSON = require(path.join(__dirname, 'package.json')); 7 | var bowerFile = path.join(__dirname, 'bower.json'); 8 | var bowerJSON = require('bower-json').parse( 9 | require(bowerFile), 10 | {normalize: true} 11 | ); 12 | bowerJSON.version = packageJSON.version; 13 | require('fs').writeFileSync( 14 | bowerFile, 15 | JSON.stringify(bowerJSON, null, 2) + '\n' 16 | ); 17 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blueimp-file-upload", 3 | "version": "9.18.0", 4 | "title": "jQuery File Upload", 5 | "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images.", 6 | "keywords": [ 7 | "jquery", 8 | "file", 9 | "upload", 10 | "widget", 11 | "multiple", 12 | "selection", 13 | "drag", 14 | "drop", 15 | "progress", 16 | "preview", 17 | "cross-domain", 18 | "cross-site", 19 | "chunk", 20 | "resume", 21 | "gae", 22 | "go", 23 | "python", 24 | "php", 25 | "bootstrap" 26 | ], 27 | "homepage": "https://github.com/blueimp/jQuery-File-Upload", 28 | "author": { 29 | "name": "Sebastian Tschan", 30 | "url": "https://blueimp.net" 31 | }, 32 | "maintainers": [ 33 | { 34 | "name": "Sebastian Tschan", 35 | "url": "https://blueimp.net" 36 | } 37 | ], 38 | "repository": { 39 | "type": "git", 40 | "url": "git://github.com/blueimp/jQuery-File-Upload.git" 41 | }, 42 | "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues", 43 | "license": "MIT", 44 | "dependencies": { 45 | "jquery": ">=1.6", 46 | "blueimp-tmpl": ">=2.5.4", 47 | "blueimp-load-image": ">=1.13.0", 48 | "blueimp-canvas-to-blob": ">=2.1.1" 49 | }, 50 | "main": [ 51 | "js/jquery.fileupload.js" 52 | ], 53 | "ignore": [ 54 | "/*.*", 55 | "/cors", 56 | "css/demo-ie8.css", 57 | "css/demo.css", 58 | "css/style.css", 59 | "js/app.js", 60 | "js/main.js", 61 | "server", 62 | "test" 63 | ] 64 | } 65 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/cors/postmessage.html: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 17 | jQuery File Upload Plugin postMessage API 18 | 19 | 20 | 21 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/cors/result.html: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 17 | jQuery Iframe Transport Plugin Redirect Page 18 | 19 | 20 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/css/demo-ie8.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | /* 3 | * jQuery File Upload Demo CSS Fixes for IE<9 4 | * https://github.com/blueimp/jQuery-File-Upload 5 | * 6 | * Copyright 2013, Sebastian Tschan 7 | * https://blueimp.net 8 | * 9 | * Licensed under the MIT license: 10 | * https://opensource.org/licenses/MIT 11 | */ 12 | 13 | .navigation { 14 | list-style: none; 15 | padding: 0; 16 | margin: 1em 0; 17 | } 18 | .navigation li { 19 | display: inline; 20 | margin-right: 10px; 21 | } 22 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/css/demo.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | /* 3 | * jQuery File Upload Demo CSS 4 | * https://github.com/blueimp/jQuery-File-Upload 5 | * 6 | * Copyright 2013, Sebastian Tschan 7 | * https://blueimp.net 8 | * 9 | * Licensed under the MIT license: 10 | * https://opensource.org/licenses/MIT 11 | */ 12 | 13 | body { 14 | max-width: 750px; 15 | margin: 0 auto; 16 | padding: 1em; 17 | font-family: "Lucida Grande", "Lucida Sans Unicode", Arial, sans-serif; 18 | font-size: 1em; 19 | line-height: 1.4em; 20 | background: #222; 21 | color: #fff; 22 | -webkit-text-size-adjust: 100%; 23 | -ms-text-size-adjust: 100%; 24 | } 25 | a { 26 | color: orange; 27 | text-decoration: none; 28 | } 29 | img { 30 | border: 0; 31 | vertical-align: middle; 32 | } 33 | h1 { 34 | line-height: 1em; 35 | } 36 | blockquote { 37 | padding: 0 0 0 15px; 38 | margin: 0 0 20px; 39 | border-left: 5px solid #eee; 40 | } 41 | table { 42 | width: 100%; 43 | margin: 10px 0; 44 | } 45 | 46 | .fileupload-progress { 47 | margin: 10px 0; 48 | } 49 | .fileupload-progress .progress-extended { 50 | margin-top: 5px; 51 | } 52 | .error { 53 | color: red; 54 | } 55 | 56 | @media (min-width: 481px) { 57 | .navigation { 58 | list-style: none; 59 | padding: 0; 60 | } 61 | .navigation li { 62 | display: inline-block; 63 | } 64 | .navigation li:not(:first-child):before { 65 | content: "| "; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/css/jquery.fileupload-noscript.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | /* 3 | * jQuery File Upload Plugin NoScript CSS 4 | * https://github.com/blueimp/jQuery-File-Upload 5 | * 6 | * Copyright 2013, Sebastian Tschan 7 | * https://blueimp.net 8 | * 9 | * Licensed under the MIT license: 10 | * https://opensource.org/licenses/MIT 11 | */ 12 | 13 | .fileinput-button input { 14 | position: static; 15 | opacity: 1; 16 | filter: none; 17 | font-size: inherit !important; 18 | direction: inherit; 19 | } 20 | .fileinput-button span { 21 | display: none; 22 | } 23 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/css/jquery.fileupload-ui-noscript.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | /* 3 | * jQuery File Upload UI Plugin NoScript CSS 4 | * https://github.com/blueimp/jQuery-File-Upload 5 | * 6 | * Copyright 2012, Sebastian Tschan 7 | * https://blueimp.net 8 | * 9 | * Licensed under the MIT license: 10 | * https://opensource.org/licenses/MIT 11 | */ 12 | 13 | .fileinput-button i, 14 | .fileupload-buttonbar .delete, 15 | .fileupload-buttonbar .toggle { 16 | display: none; 17 | } 18 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/css/jquery.fileupload-ui.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | /* 3 | * jQuery File Upload UI Plugin CSS 4 | * https://github.com/blueimp/jQuery-File-Upload 5 | * 6 | * Copyright 2010, Sebastian Tschan 7 | * https://blueimp.net 8 | * 9 | * Licensed under the MIT license: 10 | * https://opensource.org/licenses/MIT 11 | */ 12 | 13 | .fileupload-buttonbar .btn, 14 | .fileupload-buttonbar .toggle { 15 | margin-bottom: 5px; 16 | } 17 | .progress-animated .progress-bar, 18 | .progress-animated .bar { 19 | background: url("../img/progressbar.gif") !important; 20 | filter: none; 21 | } 22 | .fileupload-process { 23 | float: right; 24 | display: none; 25 | } 26 | .fileupload-processing .fileupload-process, 27 | .files .processing .preview { 28 | display: block; 29 | width: 32px; 30 | height: 32px; 31 | background: url("../img/loading.gif") center no-repeat; 32 | background-size: contain; 33 | } 34 | .files audio, 35 | .files video { 36 | max-width: 300px; 37 | } 38 | 39 | @media (max-width: 767px) { 40 | .fileupload-buttonbar .toggle, 41 | .files .toggle, 42 | .files .btn span { 43 | display: none; 44 | } 45 | .files .name { 46 | width: 80px; 47 | word-wrap: break-word; 48 | } 49 | .files audio, 50 | .files video { 51 | max-width: 80px; 52 | } 53 | .files img, 54 | .files canvas { 55 | max-width: 100%; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/css/jquery.fileupload.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | /* 3 | * jQuery File Upload Plugin CSS 4 | * https://github.com/blueimp/jQuery-File-Upload 5 | * 6 | * Copyright 2013, Sebastian Tschan 7 | * https://blueimp.net 8 | * 9 | * Licensed under the MIT license: 10 | * https://opensource.org/licenses/MIT 11 | */ 12 | 13 | .fileinput-button { 14 | position: relative; 15 | overflow: hidden; 16 | display: inline-block; 17 | } 18 | .fileinput-button input { 19 | position: absolute; 20 | top: 0; 21 | right: 0; 22 | margin: 0; 23 | opacity: 0; 24 | -ms-filter: 'alpha(opacity=0)'; 25 | font-size: 200px !important; 26 | direction: ltr; 27 | cursor: pointer; 28 | } 29 | 30 | /* Fixes for IE < 8 */ 31 | @media screen\9 { 32 | .fileinput-button input { 33 | filter: alpha(opacity=0); 34 | font-size: 100%; 35 | height: 100%; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/css/style.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | /* 3 | * jQuery File Upload Plugin CSS Example 4 | * https://github.com/blueimp/jQuery-File-Upload 5 | * 6 | * Copyright 2013, Sebastian Tschan 7 | * https://blueimp.net 8 | * 9 | * Licensed under the MIT license: 10 | * https://opensource.org/licenses/MIT 11 | */ 12 | 13 | body { 14 | padding-top: 60px; 15 | } 16 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/jQuery-File-Upload-9.18.0/img/loading.gif -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/img/progressbar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/jQuery-File-Upload-9.18.0/img/progressbar.gif -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/js/app.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery File Upload Plugin Angular JS Example 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2013, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* jshint nomen:false */ 13 | /* global window, angular */ 14 | 15 | ;(function () { 16 | 'use strict'; 17 | 18 | var isOnGitHub = window.location.hostname === 'blueimp.github.io', 19 | url = isOnGitHub ? '//jquery-file-upload.appspot.com/' : 'server/php/'; 20 | 21 | angular.module('demo', [ 22 | 'blueimp.fileupload' 23 | ]) 24 | .config([ 25 | '$httpProvider', 'fileUploadProvider', 26 | function ($httpProvider, fileUploadProvider) { 27 | delete $httpProvider.defaults.headers.common['X-Requested-With']; 28 | fileUploadProvider.defaults.redirect = window.location.href.replace( 29 | /\/[^\/]*$/, 30 | '/cors/result.html?%s' 31 | ); 32 | if (isOnGitHub) { 33 | // Demo settings: 34 | angular.extend(fileUploadProvider.defaults, { 35 | // Enable image resizing, except for Android and Opera, 36 | // which actually support image resizing, but fail to 37 | // send Blob objects via XHR requests: 38 | disableImageResize: /Android(?!.*Chrome)|Opera/ 39 | .test(window.navigator.userAgent), 40 | maxFileSize: 999000, 41 | acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i 42 | }); 43 | } 44 | } 45 | ]) 46 | 47 | .controller('DemoFileUploadController', [ 48 | '$scope', '$http', '$filter', '$window', 49 | function ($scope, $http) { 50 | $scope.options = { 51 | url: url 52 | }; 53 | if (!isOnGitHub) { 54 | $scope.loadingFiles = true; 55 | $http.get(url) 56 | .then( 57 | function (response) { 58 | $scope.loadingFiles = false; 59 | $scope.queue = response.data.files || []; 60 | }, 61 | function () { 62 | $scope.loadingFiles = false; 63 | } 64 | ); 65 | } 66 | } 67 | ]) 68 | 69 | .controller('FileDestroyController', [ 70 | '$scope', '$http', 71 | function ($scope, $http) { 72 | var file = $scope.file, 73 | state; 74 | if (file.url) { 75 | file.$state = function () { 76 | return state; 77 | }; 78 | file.$destroy = function () { 79 | state = 'pending'; 80 | return $http({ 81 | url: file.deleteUrl, 82 | method: file.deleteType 83 | }).then( 84 | function () { 85 | state = 'resolved'; 86 | $scope.clear(file); 87 | }, 88 | function () { 89 | state = 'rejected'; 90 | } 91 | ); 92 | }; 93 | } else if (!file.$cancel && !file._index) { 94 | file.$cancel = function () { 95 | $scope.clear(file); 96 | }; 97 | } 98 | } 99 | ]); 100 | 101 | }()); 102 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/js/cors/jquery.postmessage-transport.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery postMessage Transport Plugin 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2011, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* global define, require, window, document */ 13 | 14 | ;(function (factory) { 15 | 'use strict'; 16 | if (typeof define === 'function' && define.amd) { 17 | // Register as an anonymous AMD module: 18 | define(['jquery'], factory); 19 | } else if (typeof exports === 'object') { 20 | // Node/CommonJS: 21 | factory(require('jquery')); 22 | } else { 23 | // Browser globals: 24 | factory(window.jQuery); 25 | } 26 | }(function ($) { 27 | 'use strict'; 28 | 29 | var counter = 0, 30 | names = [ 31 | 'accepts', 32 | 'cache', 33 | 'contents', 34 | 'contentType', 35 | 'crossDomain', 36 | 'data', 37 | 'dataType', 38 | 'headers', 39 | 'ifModified', 40 | 'mimeType', 41 | 'password', 42 | 'processData', 43 | 'timeout', 44 | 'traditional', 45 | 'type', 46 | 'url', 47 | 'username' 48 | ], 49 | convert = function (p) { 50 | return p; 51 | }; 52 | 53 | $.ajaxSetup({ 54 | converters: { 55 | 'postmessage text': convert, 56 | 'postmessage json': convert, 57 | 'postmessage html': convert 58 | } 59 | }); 60 | 61 | $.ajaxTransport('postmessage', function (options) { 62 | if (options.postMessage && window.postMessage) { 63 | var iframe, 64 | loc = $('').prop('href', options.postMessage)[0], 65 | target = loc.protocol + '//' + loc.host, 66 | xhrUpload = options.xhr().upload; 67 | // IE always includes the port for the host property of a link 68 | // element, but not in the location.host or origin property for the 69 | // default http port 80 and https port 443, so we strip it: 70 | if (/^(http:\/\/.+:80)|(https:\/\/.+:443)$/.test(target)) { 71 | target = target.replace(/:(80|443)$/, ''); 72 | } 73 | return { 74 | send: function (_, completeCallback) { 75 | counter += 1; 76 | var message = { 77 | id: 'postmessage-transport-' + counter 78 | }, 79 | eventName = 'message.' + message.id; 80 | iframe = $( 81 | '' 84 | ).bind('load', function () { 85 | $.each(names, function (i, name) { 86 | message[name] = options[name]; 87 | }); 88 | message.dataType = message.dataType.replace('postmessage ', ''); 89 | $(window).bind(eventName, function (e) { 90 | e = e.originalEvent; 91 | var data = e.data, 92 | ev; 93 | if (e.origin === target && data.id === message.id) { 94 | if (data.type === 'progress') { 95 | ev = document.createEvent('Event'); 96 | ev.initEvent(data.type, false, true); 97 | $.extend(ev, data); 98 | xhrUpload.dispatchEvent(ev); 99 | } else { 100 | completeCallback( 101 | data.status, 102 | data.statusText, 103 | {postmessage: data.result}, 104 | data.headers 105 | ); 106 | iframe.remove(); 107 | $(window).unbind(eventName); 108 | } 109 | } 110 | }); 111 | iframe[0].contentWindow.postMessage( 112 | message, 113 | target 114 | ); 115 | }).appendTo(document.body); 116 | }, 117 | abort: function () { 118 | if (iframe) { 119 | iframe.remove(); 120 | } 121 | } 122 | }; 123 | } 124 | }); 125 | 126 | })); 127 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/js/cors/jquery.xdr-transport.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery XDomainRequest Transport Plugin 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2011, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | * 11 | * Based on Julian Aubourg's ajaxHooks xdr.js: 12 | * https://github.com/jaubourg/ajaxHooks/ 13 | */ 14 | 15 | /* global define, require, window, XDomainRequest */ 16 | 17 | ;(function (factory) { 18 | 'use strict'; 19 | if (typeof define === 'function' && define.amd) { 20 | // Register as an anonymous AMD module: 21 | define(['jquery'], factory); 22 | } else if (typeof exports === 'object') { 23 | // Node/CommonJS: 24 | factory(require('jquery')); 25 | } else { 26 | // Browser globals: 27 | factory(window.jQuery); 28 | } 29 | }(function ($) { 30 | 'use strict'; 31 | if (window.XDomainRequest && !$.support.cors) { 32 | $.ajaxTransport(function (s) { 33 | if (s.crossDomain && s.async) { 34 | if (s.timeout) { 35 | s.xdrTimeout = s.timeout; 36 | delete s.timeout; 37 | } 38 | var xdr; 39 | return { 40 | send: function (headers, completeCallback) { 41 | var addParamChar = /\?/.test(s.url) ? '&' : '?'; 42 | function callback(status, statusText, responses, responseHeaders) { 43 | xdr.onload = xdr.onerror = xdr.ontimeout = $.noop; 44 | xdr = null; 45 | completeCallback(status, statusText, responses, responseHeaders); 46 | } 47 | xdr = new XDomainRequest(); 48 | // XDomainRequest only supports GET and POST: 49 | if (s.type === 'DELETE') { 50 | s.url = s.url + addParamChar + '_method=DELETE'; 51 | s.type = 'POST'; 52 | } else if (s.type === 'PUT') { 53 | s.url = s.url + addParamChar + '_method=PUT'; 54 | s.type = 'POST'; 55 | } else if (s.type === 'PATCH') { 56 | s.url = s.url + addParamChar + '_method=PATCH'; 57 | s.type = 'POST'; 58 | } 59 | xdr.open(s.type, s.url); 60 | xdr.onload = function () { 61 | callback( 62 | 200, 63 | 'OK', 64 | {text: xdr.responseText}, 65 | 'Content-Type: ' + xdr.contentType 66 | ); 67 | }; 68 | xdr.onerror = function () { 69 | callback(404, 'Not Found'); 70 | }; 71 | if (s.xdrTimeout) { 72 | xdr.ontimeout = function () { 73 | callback(0, 'timeout'); 74 | }; 75 | xdr.timeout = s.xdrTimeout; 76 | } 77 | xdr.send((s.hasContent && s.data) || null); 78 | }, 79 | abort: function () { 80 | if (xdr) { 81 | xdr.onerror = $.noop(); 82 | xdr.abort(); 83 | } 84 | } 85 | }; 86 | } 87 | }); 88 | } 89 | })); 90 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/js/jquery.fileupload-audio.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery File Upload Audio Preview Plugin 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2013, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* jshint nomen:false */ 13 | /* global define, require, window, document */ 14 | 15 | ;(function (factory) { 16 | 'use strict'; 17 | if (typeof define === 'function' && define.amd) { 18 | // Register as an anonymous AMD module: 19 | define([ 20 | 'jquery', 21 | 'load-image', 22 | './jquery.fileupload-process' 23 | ], factory); 24 | } else if (typeof exports === 'object') { 25 | // Node/CommonJS: 26 | factory( 27 | require('jquery'), 28 | require('blueimp-load-image/js/load-image'), 29 | require('./jquery.fileupload-process') 30 | ); 31 | } else { 32 | // Browser globals: 33 | factory( 34 | window.jQuery, 35 | window.loadImage 36 | ); 37 | } 38 | }(function ($, loadImage) { 39 | 'use strict'; 40 | 41 | // Prepend to the default processQueue: 42 | $.blueimp.fileupload.prototype.options.processQueue.unshift( 43 | { 44 | action: 'loadAudio', 45 | // Use the action as prefix for the "@" options: 46 | prefix: true, 47 | fileTypes: '@', 48 | maxFileSize: '@', 49 | disabled: '@disableAudioPreview' 50 | }, 51 | { 52 | action: 'setAudio', 53 | name: '@audioPreviewName', 54 | disabled: '@disableAudioPreview' 55 | } 56 | ); 57 | 58 | // The File Upload Audio Preview plugin extends the fileupload widget 59 | // with audio preview functionality: 60 | $.widget('blueimp.fileupload', $.blueimp.fileupload, { 61 | 62 | options: { 63 | // The regular expression for the types of audio files to load, 64 | // matched against the file type: 65 | loadAudioFileTypes: /^audio\/.*$/ 66 | }, 67 | 68 | _audioElement: document.createElement('audio'), 69 | 70 | processActions: { 71 | 72 | // Loads the audio file given via data.files and data.index 73 | // as audio element if the browser supports playing it. 74 | // Accepts the options fileTypes (regular expression) 75 | // and maxFileSize (integer) to limit the files to load: 76 | loadAudio: function (data, options) { 77 | if (options.disabled) { 78 | return data; 79 | } 80 | var file = data.files[data.index], 81 | url, 82 | audio; 83 | if (this._audioElement.canPlayType && 84 | this._audioElement.canPlayType(file.type) && 85 | ($.type(options.maxFileSize) !== 'number' || 86 | file.size <= options.maxFileSize) && 87 | (!options.fileTypes || 88 | options.fileTypes.test(file.type))) { 89 | url = loadImage.createObjectURL(file); 90 | if (url) { 91 | audio = this._audioElement.cloneNode(false); 92 | audio.src = url; 93 | audio.controls = true; 94 | data.audio = audio; 95 | return data; 96 | } 97 | } 98 | return data; 99 | }, 100 | 101 | // Sets the audio element as a property of the file object: 102 | setAudio: function (data, options) { 103 | if (data.audio && !options.disabled) { 104 | data.files[data.index][options.name || 'preview'] = data.audio; 105 | } 106 | return data; 107 | } 108 | 109 | } 110 | 111 | }); 112 | 113 | })); 114 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/js/jquery.fileupload-jquery-ui.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery File Upload jQuery UI Plugin 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2013, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* jshint nomen:false */ 13 | /* global define, require, window */ 14 | 15 | ;(function (factory) { 16 | 'use strict'; 17 | if (typeof define === 'function' && define.amd) { 18 | // Register as an anonymous AMD module: 19 | define([ 20 | 'jquery', 21 | './jquery.fileupload-ui' 22 | ], factory); 23 | } else if (typeof exports === 'object') { 24 | // Node/CommonJS: 25 | factory( 26 | require('jquery'), 27 | require('./jquery.fileupload-ui') 28 | ); 29 | } else { 30 | // Browser globals: 31 | factory(window.jQuery); 32 | } 33 | }(function ($) { 34 | 'use strict'; 35 | 36 | $.widget('blueimp.fileupload', $.blueimp.fileupload, { 37 | 38 | options: { 39 | processdone: function (e, data) { 40 | data.context.find('.start').button('enable'); 41 | }, 42 | progress: function (e, data) { 43 | if (data.context) { 44 | data.context.find('.progress').progressbar( 45 | 'option', 46 | 'value', 47 | parseInt(data.loaded / data.total * 100, 10) 48 | ); 49 | } 50 | }, 51 | progressall: function (e, data) { 52 | var $this = $(this); 53 | $this.find('.fileupload-progress') 54 | .find('.progress').progressbar( 55 | 'option', 56 | 'value', 57 | parseInt(data.loaded / data.total * 100, 10) 58 | ).end() 59 | .find('.progress-extended').each(function () { 60 | $(this).html( 61 | ($this.data('blueimp-fileupload') || 62 | $this.data('fileupload')) 63 | ._renderExtendedProgress(data) 64 | ); 65 | }); 66 | } 67 | }, 68 | 69 | _renderUpload: function (func, files) { 70 | var node = this._super(func, files), 71 | showIconText = $(window).width() > 480; 72 | node.find('.progress').empty().progressbar(); 73 | node.find('.start').button({ 74 | icons: {primary: 'ui-icon-circle-arrow-e'}, 75 | text: showIconText 76 | }); 77 | node.find('.cancel').button({ 78 | icons: {primary: 'ui-icon-cancel'}, 79 | text: showIconText 80 | }); 81 | if (node.hasClass('fade')) { 82 | node.hide(); 83 | } 84 | return node; 85 | }, 86 | 87 | _renderDownload: function (func, files) { 88 | var node = this._super(func, files), 89 | showIconText = $(window).width() > 480; 90 | node.find('.delete').button({ 91 | icons: {primary: 'ui-icon-trash'}, 92 | text: showIconText 93 | }); 94 | if (node.hasClass('fade')) { 95 | node.hide(); 96 | } 97 | return node; 98 | }, 99 | 100 | _startHandler: function (e) { 101 | $(e.currentTarget).button('disable'); 102 | this._super(e); 103 | }, 104 | 105 | _transition: function (node) { 106 | var deferred = $.Deferred(); 107 | if (node.hasClass('fade')) { 108 | node.fadeToggle( 109 | this.options.transitionDuration, 110 | this.options.transitionEasing, 111 | function () { 112 | deferred.resolveWith(node); 113 | } 114 | ); 115 | } else { 116 | deferred.resolveWith(node); 117 | } 118 | return deferred; 119 | }, 120 | 121 | _create: function () { 122 | this._super(); 123 | this.element 124 | .find('.fileupload-buttonbar') 125 | .find('.fileinput-button').each(function () { 126 | var input = $(this).find('input:file').detach(); 127 | $(this) 128 | .button({icons: {primary: 'ui-icon-plusthick'}}) 129 | .append(input); 130 | }) 131 | .end().find('.start') 132 | .button({icons: {primary: 'ui-icon-circle-arrow-e'}}) 133 | .end().find('.cancel') 134 | .button({icons: {primary: 'ui-icon-cancel'}}) 135 | .end().find('.delete') 136 | .button({icons: {primary: 'ui-icon-trash'}}) 137 | .end().find('.progress').progressbar(); 138 | }, 139 | 140 | _destroy: function () { 141 | this.element 142 | .find('.fileupload-buttonbar') 143 | .find('.fileinput-button').each(function () { 144 | var input = $(this).find('input:file').detach(); 145 | $(this) 146 | .button('destroy') 147 | .append(input); 148 | }) 149 | .end().find('.start') 150 | .button('destroy') 151 | .end().find('.cancel') 152 | .button('destroy') 153 | .end().find('.delete') 154 | .button('destroy') 155 | .end().find('.progress').progressbar('destroy'); 156 | this._super(); 157 | } 158 | 159 | }); 160 | 161 | })); 162 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/js/jquery.fileupload-process.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery File Upload Processing Plugin 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2012, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* jshint nomen:false */ 13 | /* global define, require, window */ 14 | 15 | ;(function (factory) { 16 | 'use strict'; 17 | if (typeof define === 'function' && define.amd) { 18 | // Register as an anonymous AMD module: 19 | define([ 20 | 'jquery', 21 | './jquery.fileupload' 22 | ], factory); 23 | } else if (typeof exports === 'object') { 24 | // Node/CommonJS: 25 | factory( 26 | require('jquery'), 27 | require('./jquery.fileupload') 28 | ); 29 | } else { 30 | // Browser globals: 31 | factory( 32 | window.jQuery 33 | ); 34 | } 35 | }(function ($) { 36 | 'use strict'; 37 | 38 | var originalAdd = $.blueimp.fileupload.prototype.options.add; 39 | 40 | // The File Upload Processing plugin extends the fileupload widget 41 | // with file processing functionality: 42 | $.widget('blueimp.fileupload', $.blueimp.fileupload, { 43 | 44 | options: { 45 | // The list of processing actions: 46 | processQueue: [ 47 | /* 48 | { 49 | action: 'log', 50 | type: 'debug' 51 | } 52 | */ 53 | ], 54 | add: function (e, data) { 55 | var $this = $(this); 56 | data.process(function () { 57 | return $this.fileupload('process', data); 58 | }); 59 | originalAdd.call(this, e, data); 60 | } 61 | }, 62 | 63 | processActions: { 64 | /* 65 | log: function (data, options) { 66 | console[options.type]( 67 | 'Processing "' + data.files[data.index].name + '"' 68 | ); 69 | } 70 | */ 71 | }, 72 | 73 | _processFile: function (data, originalData) { 74 | var that = this, 75 | dfd = $.Deferred().resolveWith(that, [data]), 76 | chain = dfd.promise(); 77 | this._trigger('process', null, data); 78 | $.each(data.processQueue, function (i, settings) { 79 | var func = function (data) { 80 | if (originalData.errorThrown) { 81 | return $.Deferred() 82 | .rejectWith(that, [originalData]).promise(); 83 | } 84 | return that.processActions[settings.action].call( 85 | that, 86 | data, 87 | settings 88 | ); 89 | }; 90 | chain = chain.then(func, settings.always && func); 91 | }); 92 | chain 93 | .done(function () { 94 | that._trigger('processdone', null, data); 95 | that._trigger('processalways', null, data); 96 | }) 97 | .fail(function () { 98 | that._trigger('processfail', null, data); 99 | that._trigger('processalways', null, data); 100 | }); 101 | return chain; 102 | }, 103 | 104 | // Replaces the settings of each processQueue item that 105 | // are strings starting with an "@", using the remaining 106 | // substring as key for the option map, 107 | // e.g. "@autoUpload" is replaced with options.autoUpload: 108 | _transformProcessQueue: function (options) { 109 | var processQueue = []; 110 | $.each(options.processQueue, function () { 111 | var settings = {}, 112 | action = this.action, 113 | prefix = this.prefix === true ? action : this.prefix; 114 | $.each(this, function (key, value) { 115 | if ($.type(value) === 'string' && 116 | value.charAt(0) === '@') { 117 | settings[key] = options[ 118 | value.slice(1) || (prefix ? prefix + 119 | key.charAt(0).toUpperCase() + key.slice(1) : key) 120 | ]; 121 | } else { 122 | settings[key] = value; 123 | } 124 | 125 | }); 126 | processQueue.push(settings); 127 | }); 128 | options.processQueue = processQueue; 129 | }, 130 | 131 | // Returns the number of files currently in the processsing queue: 132 | processing: function () { 133 | return this._processing; 134 | }, 135 | 136 | // Processes the files given as files property of the data parameter, 137 | // returns a Promise object that allows to bind callbacks: 138 | process: function (data) { 139 | var that = this, 140 | options = $.extend({}, this.options, data); 141 | if (options.processQueue && options.processQueue.length) { 142 | this._transformProcessQueue(options); 143 | if (this._processing === 0) { 144 | this._trigger('processstart'); 145 | } 146 | $.each(data.files, function (index) { 147 | var opts = index ? $.extend({}, options) : options, 148 | func = function () { 149 | if (data.errorThrown) { 150 | return $.Deferred() 151 | .rejectWith(that, [data]).promise(); 152 | } 153 | return that._processFile(opts, data); 154 | }; 155 | opts.index = index; 156 | that._processing += 1; 157 | that._processingQueue = that._processingQueue.then(func, func) 158 | .always(function () { 159 | that._processing -= 1; 160 | if (that._processing === 0) { 161 | that._trigger('processstop'); 162 | } 163 | }); 164 | }); 165 | } 166 | return this._processingQueue; 167 | }, 168 | 169 | _create: function () { 170 | this._super(); 171 | this._processing = 0; 172 | this._processingQueue = $.Deferred().resolveWith(this) 173 | .promise(); 174 | } 175 | 176 | }); 177 | 178 | })); 179 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/js/jquery.fileupload-validate.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery File Upload Validation Plugin 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2013, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* global define, require, window */ 13 | 14 | ;(function (factory) { 15 | 'use strict'; 16 | if (typeof define === 'function' && define.amd) { 17 | // Register as an anonymous AMD module: 18 | define([ 19 | 'jquery', 20 | './jquery.fileupload-process' 21 | ], factory); 22 | } else if (typeof exports === 'object') { 23 | // Node/CommonJS: 24 | factory( 25 | require('jquery'), 26 | require('./jquery.fileupload-process') 27 | ); 28 | } else { 29 | // Browser globals: 30 | factory( 31 | window.jQuery 32 | ); 33 | } 34 | }(function ($) { 35 | 'use strict'; 36 | 37 | // Append to the default processQueue: 38 | $.blueimp.fileupload.prototype.options.processQueue.push( 39 | { 40 | action: 'validate', 41 | // Always trigger this action, 42 | // even if the previous action was rejected: 43 | always: true, 44 | // Options taken from the global options map: 45 | acceptFileTypes: '@', 46 | maxFileSize: '@', 47 | minFileSize: '@', 48 | maxNumberOfFiles: '@', 49 | disabled: '@disableValidation' 50 | } 51 | ); 52 | 53 | // The File Upload Validation plugin extends the fileupload widget 54 | // with file validation functionality: 55 | $.widget('blueimp.fileupload', $.blueimp.fileupload, { 56 | 57 | options: { 58 | /* 59 | // The regular expression for allowed file types, matches 60 | // against either file type or file name: 61 | acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i, 62 | // The maximum allowed file size in bytes: 63 | maxFileSize: 10000000, // 10 MB 64 | // The minimum allowed file size in bytes: 65 | minFileSize: undefined, // No minimal file size 66 | // The limit of files to be uploaded: 67 | maxNumberOfFiles: 10, 68 | */ 69 | 70 | // Function returning the current number of files, 71 | // has to be overriden for maxNumberOfFiles validation: 72 | getNumberOfFiles: $.noop, 73 | 74 | // Error and info messages: 75 | messages: { 76 | maxNumberOfFiles: 'Maximum number of files exceeded', 77 | acceptFileTypes: 'File type not allowed', 78 | maxFileSize: 'File is too large', 79 | minFileSize: 'File is too small' 80 | } 81 | }, 82 | 83 | processActions: { 84 | 85 | validate: function (data, options) { 86 | if (options.disabled) { 87 | return data; 88 | } 89 | var dfd = $.Deferred(), 90 | settings = this.options, 91 | file = data.files[data.index], 92 | fileSize; 93 | if (options.minFileSize || options.maxFileSize) { 94 | fileSize = file.size; 95 | } 96 | if ($.type(options.maxNumberOfFiles) === 'number' && 97 | (settings.getNumberOfFiles() || 0) + data.files.length > 98 | options.maxNumberOfFiles) { 99 | file.error = settings.i18n('maxNumberOfFiles'); 100 | } else if (options.acceptFileTypes && 101 | !(options.acceptFileTypes.test(file.type) || 102 | options.acceptFileTypes.test(file.name))) { 103 | file.error = settings.i18n('acceptFileTypes'); 104 | } else if (fileSize > options.maxFileSize) { 105 | file.error = settings.i18n('maxFileSize'); 106 | } else if ($.type(fileSize) === 'number' && 107 | fileSize < options.minFileSize) { 108 | file.error = settings.i18n('minFileSize'); 109 | } else { 110 | delete file.error; 111 | } 112 | if (file.error || data.files.error) { 113 | data.files.error = true; 114 | dfd.rejectWith(this, [data]); 115 | } else { 116 | dfd.resolveWith(this, [data]); 117 | } 118 | return dfd.promise(); 119 | } 120 | 121 | } 122 | 123 | }); 124 | 125 | })); 126 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/js/jquery.fileupload-video.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery File Upload Video Preview Plugin 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2013, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* jshint nomen:false */ 13 | /* global define, require, window, document */ 14 | 15 | ;(function (factory) { 16 | 'use strict'; 17 | if (typeof define === 'function' && define.amd) { 18 | // Register as an anonymous AMD module: 19 | define([ 20 | 'jquery', 21 | 'load-image', 22 | './jquery.fileupload-process' 23 | ], factory); 24 | } else if (typeof exports === 'object') { 25 | // Node/CommonJS: 26 | factory( 27 | require('jquery'), 28 | require('blueimp-load-image/js/load-image'), 29 | require('./jquery.fileupload-process') 30 | ); 31 | } else { 32 | // Browser globals: 33 | factory( 34 | window.jQuery, 35 | window.loadImage 36 | ); 37 | } 38 | }(function ($, loadImage) { 39 | 'use strict'; 40 | 41 | // Prepend to the default processQueue: 42 | $.blueimp.fileupload.prototype.options.processQueue.unshift( 43 | { 44 | action: 'loadVideo', 45 | // Use the action as prefix for the "@" options: 46 | prefix: true, 47 | fileTypes: '@', 48 | maxFileSize: '@', 49 | disabled: '@disableVideoPreview' 50 | }, 51 | { 52 | action: 'setVideo', 53 | name: '@videoPreviewName', 54 | disabled: '@disableVideoPreview' 55 | } 56 | ); 57 | 58 | // The File Upload Video Preview plugin extends the fileupload widget 59 | // with video preview functionality: 60 | $.widget('blueimp.fileupload', $.blueimp.fileupload, { 61 | 62 | options: { 63 | // The regular expression for the types of video files to load, 64 | // matched against the file type: 65 | loadVideoFileTypes: /^video\/.*$/ 66 | }, 67 | 68 | _videoElement: document.createElement('video'), 69 | 70 | processActions: { 71 | 72 | // Loads the video file given via data.files and data.index 73 | // as video element if the browser supports playing it. 74 | // Accepts the options fileTypes (regular expression) 75 | // and maxFileSize (integer) to limit the files to load: 76 | loadVideo: function (data, options) { 77 | if (options.disabled) { 78 | return data; 79 | } 80 | var file = data.files[data.index], 81 | url, 82 | video; 83 | if (this._videoElement.canPlayType && 84 | this._videoElement.canPlayType(file.type) && 85 | ($.type(options.maxFileSize) !== 'number' || 86 | file.size <= options.maxFileSize) && 87 | (!options.fileTypes || 88 | options.fileTypes.test(file.type))) { 89 | url = loadImage.createObjectURL(file); 90 | if (url) { 91 | video = this._videoElement.cloneNode(false); 92 | video.src = url; 93 | video.controls = true; 94 | data.video = video; 95 | return data; 96 | } 97 | } 98 | return data; 99 | }, 100 | 101 | // Sets the video element as a property of the file object: 102 | setVideo: function (data, options) { 103 | if (data.video && !options.disabled) { 104 | data.files[data.index][options.name || 'preview'] = data.video; 105 | } 106 | return data; 107 | } 108 | 109 | } 110 | 111 | }); 112 | 113 | })); 114 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/js/jquery.iframe-transport.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Iframe Transport Plugin 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2011, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* global define, require, window, document, JSON */ 13 | 14 | ;(function (factory) { 15 | 'use strict'; 16 | if (typeof define === 'function' && define.amd) { 17 | // Register as an anonymous AMD module: 18 | define(['jquery'], factory); 19 | } else if (typeof exports === 'object') { 20 | // Node/CommonJS: 21 | factory(require('jquery')); 22 | } else { 23 | // Browser globals: 24 | factory(window.jQuery); 25 | } 26 | }(function ($) { 27 | 'use strict'; 28 | 29 | // Helper variable to create unique names for the transport iframes: 30 | var counter = 0, 31 | jsonAPI = $, 32 | jsonParse = 'parseJSON'; 33 | 34 | if ('JSON' in window && 'parse' in JSON) { 35 | jsonAPI = JSON; 36 | jsonParse = 'parse'; 37 | } 38 | 39 | // The iframe transport accepts four additional options: 40 | // options.fileInput: a jQuery collection of file input fields 41 | // options.paramName: the parameter name for the file form data, 42 | // overrides the name property of the file input field(s), 43 | // can be a string or an array of strings. 44 | // options.formData: an array of objects with name and value properties, 45 | // equivalent to the return data of .serializeArray(), e.g.: 46 | // [{name: 'a', value: 1}, {name: 'b', value: 2}] 47 | // options.initialIframeSrc: the URL of the initial iframe src, 48 | // by default set to "javascript:false;" 49 | $.ajaxTransport('iframe', function (options) { 50 | if (options.async) { 51 | // javascript:false as initial iframe src 52 | // prevents warning popups on HTTPS in IE6: 53 | /*jshint scripturl: true */ 54 | var initialIframeSrc = options.initialIframeSrc || 'javascript:false;', 55 | /*jshint scripturl: false */ 56 | form, 57 | iframe, 58 | addParamChar; 59 | return { 60 | send: function (_, completeCallback) { 61 | form = $('
'); 62 | form.attr('accept-charset', options.formAcceptCharset); 63 | addParamChar = /\?/.test(options.url) ? '&' : '?'; 64 | // XDomainRequest only supports GET and POST: 65 | if (options.type === 'DELETE') { 66 | options.url = options.url + addParamChar + '_method=DELETE'; 67 | options.type = 'POST'; 68 | } else if (options.type === 'PUT') { 69 | options.url = options.url + addParamChar + '_method=PUT'; 70 | options.type = 'POST'; 71 | } else if (options.type === 'PATCH') { 72 | options.url = options.url + addParamChar + '_method=PATCH'; 73 | options.type = 'POST'; 74 | } 75 | // IE versions below IE8 cannot set the name property of 76 | // elements that have already been added to the DOM, 77 | // so we set the name along with the iframe HTML markup: 78 | counter += 1; 79 | iframe = $( 80 | '' 82 | ).bind('load', function () { 83 | var fileInputClones, 84 | paramNames = $.isArray(options.paramName) ? 85 | options.paramName : [options.paramName]; 86 | iframe 87 | .unbind('load') 88 | .bind('load', function () { 89 | var response; 90 | // Wrap in a try/catch block to catch exceptions thrown 91 | // when trying to access cross-domain iframe contents: 92 | try { 93 | response = iframe.contents(); 94 | // Google Chrome and Firefox do not throw an 95 | // exception when calling iframe.contents() on 96 | // cross-domain requests, so we unify the response: 97 | if (!response.length || !response[0].firstChild) { 98 | throw new Error(); 99 | } 100 | } catch (e) { 101 | response = undefined; 102 | } 103 | // The complete callback returns the 104 | // iframe content document as response object: 105 | completeCallback( 106 | 200, 107 | 'success', 108 | {'iframe': response} 109 | ); 110 | // Fix for IE endless progress bar activity bug 111 | // (happens on form submits to iframe targets): 112 | $('') 113 | .appendTo(form); 114 | window.setTimeout(function () { 115 | // Removing the form in a setTimeout call 116 | // allows Chrome's developer tools to display 117 | // the response result 118 | form.remove(); 119 | }, 0); 120 | }); 121 | form 122 | .prop('target', iframe.prop('name')) 123 | .prop('action', options.url) 124 | .prop('method', options.type); 125 | if (options.formData) { 126 | $.each(options.formData, function (index, field) { 127 | $('') 128 | .prop('name', field.name) 129 | .val(field.value) 130 | .appendTo(form); 131 | }); 132 | } 133 | if (options.fileInput && options.fileInput.length && 134 | options.type === 'POST') { 135 | fileInputClones = options.fileInput.clone(); 136 | // Insert a clone for each file input field: 137 | options.fileInput.after(function (index) { 138 | return fileInputClones[index]; 139 | }); 140 | if (options.paramName) { 141 | options.fileInput.each(function (index) { 142 | $(this).prop( 143 | 'name', 144 | paramNames[index] || options.paramName 145 | ); 146 | }); 147 | } 148 | // Appending the file input fields to the hidden form 149 | // removes them from their original location: 150 | form 151 | .append(options.fileInput) 152 | .prop('enctype', 'multipart/form-data') 153 | // enctype must be set as encoding for IE: 154 | .prop('encoding', 'multipart/form-data'); 155 | // Remove the HTML5 form attribute from the input(s): 156 | options.fileInput.removeAttr('form'); 157 | } 158 | form.submit(); 159 | // Insert the file input fields at their original location 160 | // by replacing the clones with the originals: 161 | if (fileInputClones && fileInputClones.length) { 162 | options.fileInput.each(function (index, input) { 163 | var clone = $(fileInputClones[index]); 164 | // Restore the original name and form properties: 165 | $(input) 166 | .prop('name', clone.prop('name')) 167 | .attr('form', clone.attr('form')); 168 | clone.replaceWith(input); 169 | }); 170 | } 171 | }); 172 | form.append(iframe).appendTo(document.body); 173 | }, 174 | abort: function () { 175 | if (iframe) { 176 | // javascript:false as iframe src aborts the request 177 | // and prevents warning popups on HTTPS in IE6. 178 | // concat is used to avoid the "Script URL" JSLint error: 179 | iframe 180 | .unbind('load') 181 | .prop('src', initialIframeSrc); 182 | } 183 | if (form) { 184 | form.remove(); 185 | } 186 | } 187 | }; 188 | } 189 | }); 190 | 191 | // The iframe transport returns the iframe content document as response. 192 | // The following adds converters from iframe to text, json, html, xml 193 | // and script. 194 | // Please note that the Content-Type for JSON responses has to be text/plain 195 | // or text/html, if the browser doesn't include application/json in the 196 | // Accept header, else IE will show a download dialog. 197 | // The Content-Type for XML responses on the other hand has to be always 198 | // application/xml or text/xml, so IE properly parses the XML response. 199 | // See also 200 | // https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#content-type-negotiation 201 | $.ajaxSetup({ 202 | converters: { 203 | 'iframe text': function (iframe) { 204 | return iframe && $(iframe[0].body).text(); 205 | }, 206 | 'iframe json': function (iframe) { 207 | return iframe && jsonAPI[jsonParse]($(iframe[0].body).text()); 208 | }, 209 | 'iframe html': function (iframe) { 210 | return iframe && $(iframe[0].body).html(); 211 | }, 212 | 'iframe xml': function (iframe) { 213 | var xmlDoc = iframe && iframe[0]; 214 | return xmlDoc && $.isXMLDoc(xmlDoc) ? xmlDoc : 215 | $.parseXML((xmlDoc.XMLDocument && xmlDoc.XMLDocument.xml) || 216 | $(xmlDoc.body).html()); 217 | }, 218 | 'iframe script': function (iframe) { 219 | return iframe && $.globalEval($(iframe[0].body).text()); 220 | } 221 | } 222 | }); 223 | 224 | })); 225 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/js/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery File Upload Plugin JS Example 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2010, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* global $, window */ 13 | 14 | $(function () { 15 | 'use strict'; 16 | 17 | // Initialize the jQuery File Upload widget: 18 | $('#fileupload').fileupload({ 19 | // Uncomment the following to send cross-domain cookies: 20 | //xhrFields: {withCredentials: true}, 21 | url: 'server/php/' 22 | }); 23 | 24 | // Enable iframe cross-domain access via redirect option: 25 | $('#fileupload').fileupload( 26 | 'option', 27 | 'redirect', 28 | window.location.href.replace( 29 | /\/[^\/]*$/, 30 | '/cors/result.html?%s' 31 | ) 32 | ); 33 | 34 | if (window.location.hostname === 'blueimp.github.io') { 35 | // Demo settings: 36 | $('#fileupload').fileupload('option', { 37 | url: '//jquery-file-upload.appspot.com/', 38 | // Enable image resizing, except for Android and Opera, 39 | // which actually support image resizing, but fail to 40 | // send Blob objects via XHR requests: 41 | disableImageResize: /Android(?!.*Chrome)|Opera/ 42 | .test(window.navigator.userAgent), 43 | maxFileSize: 999000, 44 | acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i 45 | }); 46 | // Upload server status check for browsers with CORS support: 47 | if ($.support.cors) { 48 | $.ajax({ 49 | url: '//jquery-file-upload.appspot.com/', 50 | type: 'HEAD' 51 | }).fail(function () { 52 | $('
') 53 | .text('Upload server currently unavailable - ' + 54 | new Date()) 55 | .appendTo('#fileupload'); 56 | }); 57 | } 58 | } else { 59 | // Load existing files: 60 | $('#fileupload').addClass('fileupload-processing'); 61 | $.ajax({ 62 | // Uncomment the following to send cross-domain cookies: 63 | //xhrFields: {withCredentials: true}, 64 | url: $('#fileupload').fileupload('option', 'url'), 65 | dataType: 'json', 66 | context: $('#fileupload')[0] 67 | }).always(function () { 68 | $(this).removeClass('fileupload-processing'); 69 | }).done(function (result) { 70 | $(this).fileupload('option', 'done') 71 | .call(this, $.Event('done'), {result: result}); 72 | }); 73 | } 74 | 75 | }); 76 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blueimp-file-upload", 3 | "version": "9.18.0", 4 | "title": "jQuery File Upload", 5 | "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.", 6 | "keywords": [ 7 | "jquery", 8 | "file", 9 | "upload", 10 | "widget", 11 | "multiple", 12 | "selection", 13 | "drag", 14 | "drop", 15 | "progress", 16 | "preview", 17 | "cross-domain", 18 | "cross-site", 19 | "chunk", 20 | "resume", 21 | "gae", 22 | "go", 23 | "python", 24 | "php", 25 | "bootstrap" 26 | ], 27 | "homepage": "https://github.com/blueimp/jQuery-File-Upload", 28 | "author": { 29 | "name": "Sebastian Tschan", 30 | "url": "https://blueimp.net" 31 | }, 32 | "repository": { 33 | "type": "git", 34 | "url": "git://github.com/blueimp/jQuery-File-Upload.git" 35 | }, 36 | "license": "MIT", 37 | "optionalDependencies": { 38 | "blueimp-canvas-to-blob": "3.5.0", 39 | "blueimp-load-image": "2.12.2", 40 | "blueimp-tmpl": "3.6.0" 41 | }, 42 | "devDependencies": { 43 | "bower-json": "0.8.1", 44 | "jshint": "2.9.3" 45 | }, 46 | "scripts": { 47 | "bower-version-update": "./bower-version-update.js", 48 | "lint": "jshint *.js js/*.js js/cors/*.js", 49 | "test": "npm run lint", 50 | "preversion": "npm test", 51 | "version": "npm run bower-version-update && git add bower.json", 52 | "postversion": "git push --tags origin master && npm publish" 53 | }, 54 | "main": "js/jquery.fileupload.js" 55 | } 56 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/server/gae-go/app.yaml: -------------------------------------------------------------------------------- 1 | application: jquery-file-upload 2 | version: 2 3 | runtime: go 4 | api_version: go1 5 | 6 | handlers: 7 | - url: /(favicon\.ico|robots\.txt) 8 | static_files: static/\1 9 | upload: static/(.*) 10 | expiration: '1d' 11 | - url: /.* 12 | script: _go_app 13 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/server/gae-go/app/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery File Upload Plugin GAE Go Example 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2011, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | package app 13 | 14 | import ( 15 | "bufio" 16 | "bytes" 17 | "encoding/json" 18 | "fmt" 19 | "github.com/disintegration/gift" 20 | "golang.org/x/net/context" 21 | "google.golang.org/appengine" 22 | "google.golang.org/appengine/memcache" 23 | "hash/crc32" 24 | "image" 25 | "image/gif" 26 | "image/jpeg" 27 | "image/png" 28 | "io" 29 | "log" 30 | "mime/multipart" 31 | "net/http" 32 | "net/url" 33 | "path/filepath" 34 | "regexp" 35 | "strings" 36 | ) 37 | 38 | const ( 39 | WEBSITE = "https://blueimp.github.io/jQuery-File-Upload/" 40 | MIN_FILE_SIZE = 1 // bytes 41 | // Max file size is memcache limit (1MB) minus key size minus overhead: 42 | MAX_FILE_SIZE = 999000 // bytes 43 | IMAGE_TYPES = "image/(gif|p?jpeg|(x-)?png)" 44 | ACCEPT_FILE_TYPES = IMAGE_TYPES 45 | THUMB_MAX_WIDTH = 80 46 | THUMB_MAX_HEIGHT = 80 47 | EXPIRATION_TIME = 300 // seconds 48 | // If empty, only allow redirects to the referer protocol+host. 49 | // Set to a regexp string for custom pattern matching: 50 | REDIRECT_ALLOW_TARGET = "" 51 | ) 52 | 53 | var ( 54 | imageTypes = regexp.MustCompile(IMAGE_TYPES) 55 | acceptFileTypes = regexp.MustCompile(ACCEPT_FILE_TYPES) 56 | thumbSuffix = "." + fmt.Sprint(THUMB_MAX_WIDTH) + "x" + 57 | fmt.Sprint(THUMB_MAX_HEIGHT) 58 | ) 59 | 60 | func escape(s string) string { 61 | return strings.Replace(url.QueryEscape(s), "+", "%20", -1) 62 | } 63 | 64 | func extractKey(r *http.Request) string { 65 | // Use RequestURI instead of r.URL.Path, as we need the encoded form: 66 | path := strings.Split(r.RequestURI, "?")[0] 67 | // Also adjust double encoded slashes: 68 | return strings.Replace(path[1:], "%252F", "%2F", -1) 69 | } 70 | 71 | func check(err error) { 72 | if err != nil { 73 | panic(err) 74 | } 75 | } 76 | 77 | type FileInfo struct { 78 | Key string `json:"-"` 79 | ThumbnailKey string `json:"-"` 80 | Url string `json:"url,omitempty"` 81 | ThumbnailUrl string `json:"thumbnailUrl,omitempty"` 82 | Name string `json:"name"` 83 | Type string `json:"type"` 84 | Size int64 `json:"size"` 85 | Error string `json:"error,omitempty"` 86 | DeleteUrl string `json:"deleteUrl,omitempty"` 87 | DeleteType string `json:"deleteType,omitempty"` 88 | } 89 | 90 | func (fi *FileInfo) ValidateType() (valid bool) { 91 | if acceptFileTypes.MatchString(fi.Type) { 92 | return true 93 | } 94 | fi.Error = "Filetype not allowed" 95 | return false 96 | } 97 | 98 | func (fi *FileInfo) ValidateSize() (valid bool) { 99 | if fi.Size < MIN_FILE_SIZE { 100 | fi.Error = "File is too small" 101 | } else if fi.Size > MAX_FILE_SIZE { 102 | fi.Error = "File is too big" 103 | } else { 104 | return true 105 | } 106 | return false 107 | } 108 | 109 | func (fi *FileInfo) CreateUrls(r *http.Request, c context.Context) { 110 | u := &url.URL{ 111 | Scheme: r.URL.Scheme, 112 | Host: appengine.DefaultVersionHostname(c), 113 | Path: "/", 114 | } 115 | uString := u.String() 116 | fi.Url = uString + fi.Key 117 | fi.DeleteUrl = fi.Url 118 | fi.DeleteType = "DELETE" 119 | if fi.ThumbnailKey != "" { 120 | fi.ThumbnailUrl = uString + fi.ThumbnailKey 121 | } 122 | } 123 | 124 | func (fi *FileInfo) SetKey(checksum uint32) { 125 | fi.Key = escape(string(fi.Type)) + "/" + 126 | escape(fmt.Sprint(checksum)) + "/" + 127 | escape(string(fi.Name)) 128 | } 129 | 130 | func (fi *FileInfo) createThumb(buffer *bytes.Buffer, c context.Context) { 131 | if imageTypes.MatchString(fi.Type) { 132 | src, _, err := image.Decode(bytes.NewReader(buffer.Bytes())) 133 | check(err) 134 | filter := gift.New(gift.ResizeToFit( 135 | THUMB_MAX_WIDTH, 136 | THUMB_MAX_HEIGHT, 137 | gift.LanczosResampling, 138 | )) 139 | dst := image.NewNRGBA(filter.Bounds(src.Bounds())) 140 | filter.Draw(dst, src) 141 | buffer.Reset() 142 | bWriter := bufio.NewWriter(buffer) 143 | switch fi.Type { 144 | case "image/jpeg", "image/pjpeg": 145 | err = jpeg.Encode(bWriter, dst, nil) 146 | case "image/gif": 147 | err = gif.Encode(bWriter, dst, nil) 148 | default: 149 | err = png.Encode(bWriter, dst) 150 | } 151 | check(err) 152 | bWriter.Flush() 153 | thumbnailKey := fi.Key + thumbSuffix + filepath.Ext(fi.Name) 154 | item := &memcache.Item{ 155 | Key: thumbnailKey, 156 | Value: buffer.Bytes(), 157 | } 158 | err = memcache.Set(c, item) 159 | check(err) 160 | fi.ThumbnailKey = thumbnailKey 161 | } 162 | } 163 | 164 | func handleUpload(r *http.Request, p *multipart.Part) (fi *FileInfo) { 165 | fi = &FileInfo{ 166 | Name: p.FileName(), 167 | Type: p.Header.Get("Content-Type"), 168 | } 169 | if !fi.ValidateType() { 170 | return 171 | } 172 | defer func() { 173 | if rec := recover(); rec != nil { 174 | log.Println(rec) 175 | fi.Error = rec.(error).Error() 176 | } 177 | }() 178 | var buffer bytes.Buffer 179 | hash := crc32.NewIEEE() 180 | mw := io.MultiWriter(&buffer, hash) 181 | lr := &io.LimitedReader{R: p, N: MAX_FILE_SIZE + 1} 182 | _, err := io.Copy(mw, lr) 183 | check(err) 184 | fi.Size = MAX_FILE_SIZE + 1 - lr.N 185 | if !fi.ValidateSize() { 186 | return 187 | } 188 | fi.SetKey(hash.Sum32()) 189 | item := &memcache.Item{ 190 | Key: fi.Key, 191 | Value: buffer.Bytes(), 192 | } 193 | context := appengine.NewContext(r) 194 | err = memcache.Set(context, item) 195 | check(err) 196 | fi.createThumb(&buffer, context) 197 | fi.CreateUrls(r, context) 198 | return 199 | } 200 | 201 | func getFormValue(p *multipart.Part) string { 202 | var b bytes.Buffer 203 | io.CopyN(&b, p, int64(1<<20)) // Copy max: 1 MiB 204 | return b.String() 205 | } 206 | 207 | func handleUploads(r *http.Request) (fileInfos []*FileInfo) { 208 | fileInfos = make([]*FileInfo, 0) 209 | mr, err := r.MultipartReader() 210 | check(err) 211 | r.Form, err = url.ParseQuery(r.URL.RawQuery) 212 | check(err) 213 | part, err := mr.NextPart() 214 | for err == nil { 215 | if name := part.FormName(); name != "" { 216 | if part.FileName() != "" { 217 | fileInfos = append(fileInfos, handleUpload(r, part)) 218 | } else { 219 | r.Form[name] = append(r.Form[name], getFormValue(part)) 220 | } 221 | } 222 | part, err = mr.NextPart() 223 | } 224 | return 225 | } 226 | 227 | func validateRedirect(r *http.Request, redirect string) bool { 228 | if redirect != "" { 229 | var redirectAllowTarget *regexp.Regexp 230 | if REDIRECT_ALLOW_TARGET != "" { 231 | redirectAllowTarget = regexp.MustCompile(REDIRECT_ALLOW_TARGET) 232 | } else { 233 | referer := r.Referer() 234 | if referer == "" { 235 | return false 236 | } 237 | refererUrl, err := url.Parse(referer) 238 | if err != nil { 239 | return false 240 | } 241 | redirectAllowTarget = regexp.MustCompile("^" + regexp.QuoteMeta( 242 | refererUrl.Scheme+"://"+refererUrl.Host+"/", 243 | )) 244 | } 245 | return redirectAllowTarget.MatchString(redirect) 246 | } 247 | return false 248 | } 249 | 250 | func get(w http.ResponseWriter, r *http.Request) { 251 | if r.URL.Path == "/" { 252 | http.Redirect(w, r, WEBSITE, http.StatusFound) 253 | return 254 | } 255 | // Use RequestURI instead of r.URL.Path, as we need the encoded form: 256 | key := extractKey(r) 257 | parts := strings.Split(key, "/") 258 | if len(parts) == 3 { 259 | context := appengine.NewContext(r) 260 | item, err := memcache.Get(context, key) 261 | if err == nil { 262 | w.Header().Add("X-Content-Type-Options", "nosniff") 263 | contentType, _ := url.QueryUnescape(parts[0]) 264 | if !imageTypes.MatchString(contentType) { 265 | contentType = "application/octet-stream" 266 | } 267 | w.Header().Add("Content-Type", contentType) 268 | w.Header().Add( 269 | "Cache-Control", 270 | fmt.Sprintf("public,max-age=%d", EXPIRATION_TIME), 271 | ) 272 | w.Write(item.Value) 273 | return 274 | } 275 | } 276 | http.Error(w, "404 Not Found", http.StatusNotFound) 277 | } 278 | 279 | func post(w http.ResponseWriter, r *http.Request) { 280 | result := make(map[string][]*FileInfo, 1) 281 | result["files"] = handleUploads(r) 282 | b, err := json.Marshal(result) 283 | check(err) 284 | if redirect := r.FormValue("redirect"); validateRedirect(r, redirect) { 285 | if strings.Contains(redirect, "%s") { 286 | redirect = fmt.Sprintf( 287 | redirect, 288 | escape(string(b)), 289 | ) 290 | } 291 | http.Redirect(w, r, redirect, http.StatusFound) 292 | return 293 | } 294 | w.Header().Set("Cache-Control", "no-cache") 295 | jsonType := "application/json" 296 | if strings.Index(r.Header.Get("Accept"), jsonType) != -1 { 297 | w.Header().Set("Content-Type", jsonType) 298 | } 299 | fmt.Fprintln(w, string(b)) 300 | } 301 | 302 | func delete(w http.ResponseWriter, r *http.Request) { 303 | key := extractKey(r) 304 | parts := strings.Split(key, "/") 305 | if len(parts) == 3 { 306 | result := make(map[string]bool, 1) 307 | context := appengine.NewContext(r) 308 | err := memcache.Delete(context, key) 309 | if err == nil { 310 | result[key] = true 311 | contentType, _ := url.QueryUnescape(parts[0]) 312 | if imageTypes.MatchString(contentType) { 313 | thumbnailKey := key + thumbSuffix + filepath.Ext(parts[2]) 314 | err := memcache.Delete(context, thumbnailKey) 315 | if err == nil { 316 | result[thumbnailKey] = true 317 | } 318 | } 319 | } 320 | w.Header().Set("Content-Type", "application/json") 321 | b, err := json.Marshal(result) 322 | check(err) 323 | fmt.Fprintln(w, string(b)) 324 | } else { 325 | http.Error(w, "405 Method not allowed", http.StatusMethodNotAllowed) 326 | } 327 | } 328 | 329 | func handle(w http.ResponseWriter, r *http.Request) { 330 | params, err := url.ParseQuery(r.URL.RawQuery) 331 | check(err) 332 | w.Header().Add("Access-Control-Allow-Origin", "*") 333 | w.Header().Add( 334 | "Access-Control-Allow-Methods", 335 | "OPTIONS, HEAD, GET, POST, DELETE", 336 | ) 337 | w.Header().Add( 338 | "Access-Control-Allow-Headers", 339 | "Content-Type, Content-Range, Content-Disposition", 340 | ) 341 | switch r.Method { 342 | case "OPTIONS", "HEAD": 343 | return 344 | case "GET": 345 | get(w, r) 346 | case "POST": 347 | if len(params["_method"]) > 0 && params["_method"][0] == "DELETE" { 348 | delete(w, r) 349 | } else { 350 | post(w, r) 351 | } 352 | case "DELETE": 353 | delete(w, r) 354 | default: 355 | http.Error(w, "501 Not Implemented", http.StatusNotImplemented) 356 | } 357 | } 358 | 359 | func init() { 360 | http.HandleFunc("/", handle) 361 | } 362 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/server/gae-go/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/jQuery-File-Upload-9.18.0/server/gae-go/static/favicon.ico -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/server/gae-go/static/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/server/gae-python/app.yaml: -------------------------------------------------------------------------------- 1 | application: jquery-file-upload 2 | version: 1 3 | runtime: python27 4 | api_version: 1 5 | threadsafe: true 6 | 7 | libraries: 8 | - name: PIL 9 | version: latest 10 | 11 | handlers: 12 | - url: /(favicon\.ico|robots\.txt) 13 | static_files: static/\1 14 | upload: static/(.*) 15 | expiration: '1d' 16 | - url: /.* 17 | script: main.app 18 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/server/gae-python/main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # jQuery File Upload Plugin GAE Python Example 4 | # https://github.com/blueimp/jQuery-File-Upload 5 | # 6 | # Copyright 2011, Sebastian Tschan 7 | # https://blueimp.net 8 | # 9 | # Licensed under the MIT license: 10 | # https://opensource.org/licenses/MIT 11 | # 12 | 13 | from google.appengine.api import memcache, images 14 | import json 15 | import os 16 | import re 17 | import urllib 18 | import webapp2 19 | 20 | DEBUG=os.environ.get('SERVER_SOFTWARE', '').startswith('Dev') 21 | WEBSITE = 'https://blueimp.github.io/jQuery-File-Upload/' 22 | MIN_FILE_SIZE = 1 # bytes 23 | # Max file size is memcache limit (1MB) minus key size minus overhead: 24 | MAX_FILE_SIZE = 999000 # bytes 25 | IMAGE_TYPES = re.compile('image/(gif|p?jpeg|(x-)?png)') 26 | ACCEPT_FILE_TYPES = IMAGE_TYPES 27 | THUMB_MAX_WIDTH = 80 28 | THUMB_MAX_HEIGHT = 80 29 | THUMB_SUFFIX = '.'+str(THUMB_MAX_WIDTH)+'x'+str(THUMB_MAX_HEIGHT)+'.png' 30 | EXPIRATION_TIME = 300 # seconds 31 | # If set to None, only allow redirects to the referer protocol+host. 32 | # Set to a regexp for custom pattern matching against the redirect value: 33 | REDIRECT_ALLOW_TARGET = None 34 | 35 | class CORSHandler(webapp2.RequestHandler): 36 | def cors(self): 37 | headers = self.response.headers 38 | headers['Access-Control-Allow-Origin'] = '*' 39 | headers['Access-Control-Allow-Methods'] =\ 40 | 'OPTIONS, HEAD, GET, POST, DELETE' 41 | headers['Access-Control-Allow-Headers'] =\ 42 | 'Content-Type, Content-Range, Content-Disposition' 43 | 44 | def initialize(self, request, response): 45 | super(CORSHandler, self).initialize(request, response) 46 | self.cors() 47 | 48 | def json_stringify(self, obj): 49 | return json.dumps(obj, separators=(',', ':')) 50 | 51 | def options(self, *args, **kwargs): 52 | pass 53 | 54 | class UploadHandler(CORSHandler): 55 | def validate(self, file): 56 | if file['size'] < MIN_FILE_SIZE: 57 | file['error'] = 'File is too small' 58 | elif file['size'] > MAX_FILE_SIZE: 59 | file['error'] = 'File is too big' 60 | elif not ACCEPT_FILE_TYPES.match(file['type']): 61 | file['error'] = 'Filetype not allowed' 62 | else: 63 | return True 64 | return False 65 | 66 | def validate_redirect(self, redirect): 67 | if redirect: 68 | if REDIRECT_ALLOW_TARGET: 69 | return REDIRECT_ALLOW_TARGET.match(redirect) 70 | referer = self.request.headers['referer'] 71 | if referer: 72 | from urlparse import urlparse 73 | parts = urlparse(referer) 74 | redirect_allow_target = '^' + re.escape( 75 | parts.scheme + '://' + parts.netloc + '/' 76 | ) 77 | return re.match(redirect_allow_target, redirect) 78 | return False 79 | 80 | def get_file_size(self, file): 81 | file.seek(0, 2) # Seek to the end of the file 82 | size = file.tell() # Get the position of EOF 83 | file.seek(0) # Reset the file position to the beginning 84 | return size 85 | 86 | def write_blob(self, data, info): 87 | key = urllib.quote(info['type'].encode('utf-8'), '') +\ 88 | '/' + str(hash(data)) +\ 89 | '/' + urllib.quote(info['name'].encode('utf-8'), '') 90 | try: 91 | memcache.set(key, data, time=EXPIRATION_TIME) 92 | except: #Failed to add to memcache 93 | return (None, None) 94 | thumbnail_key = None 95 | if IMAGE_TYPES.match(info['type']): 96 | try: 97 | img = images.Image(image_data=data) 98 | img.resize( 99 | width=THUMB_MAX_WIDTH, 100 | height=THUMB_MAX_HEIGHT 101 | ) 102 | thumbnail_data = img.execute_transforms() 103 | thumbnail_key = key + THUMB_SUFFIX 104 | memcache.set( 105 | thumbnail_key, 106 | thumbnail_data, 107 | time=EXPIRATION_TIME 108 | ) 109 | except: #Failed to resize Image or add to memcache 110 | thumbnail_key = None 111 | return (key, thumbnail_key) 112 | 113 | def handle_upload(self): 114 | results = [] 115 | for name, fieldStorage in self.request.POST.items(): 116 | if type(fieldStorage) is unicode: 117 | continue 118 | result = {} 119 | result['name'] = urllib.unquote(fieldStorage.filename) 120 | result['type'] = fieldStorage.type 121 | result['size'] = self.get_file_size(fieldStorage.file) 122 | if self.validate(result): 123 | key, thumbnail_key = self.write_blob( 124 | fieldStorage.value, 125 | result 126 | ) 127 | if key is not None: 128 | result['url'] = self.request.host_url + '/' + key 129 | result['deleteUrl'] = result['url'] 130 | result['deleteType'] = 'DELETE' 131 | if thumbnail_key is not None: 132 | result['thumbnailUrl'] = self.request.host_url +\ 133 | '/' + thumbnail_key 134 | else: 135 | result['error'] = 'Failed to store uploaded file.' 136 | results.append(result) 137 | return results 138 | 139 | def head(self): 140 | pass 141 | 142 | def get(self): 143 | self.redirect(WEBSITE) 144 | 145 | def post(self): 146 | if (self.request.get('_method') == 'DELETE'): 147 | return self.delete() 148 | result = {'files': self.handle_upload()} 149 | s = self.json_stringify(result) 150 | redirect = self.request.get('redirect') 151 | if self.validate_redirect(redirect): 152 | return self.redirect(str( 153 | redirect.replace('%s', urllib.quote(s, ''), 1) 154 | )) 155 | if 'application/json' in self.request.headers.get('Accept'): 156 | self.response.headers['Content-Type'] = 'application/json' 157 | self.response.write(s) 158 | 159 | class FileHandler(CORSHandler): 160 | def normalize(self, str): 161 | return urllib.quote(urllib.unquote(str), '') 162 | 163 | def get(self, content_type, data_hash, file_name): 164 | content_type = self.normalize(content_type) 165 | file_name = self.normalize(file_name) 166 | key = content_type + '/' + data_hash + '/' + file_name 167 | data = memcache.get(key) 168 | if data is None: 169 | return self.error(404) 170 | # Prevent browsers from MIME-sniffing the content-type: 171 | self.response.headers['X-Content-Type-Options'] = 'nosniff' 172 | content_type = urllib.unquote(content_type) 173 | if not IMAGE_TYPES.match(content_type): 174 | # Force a download dialog for non-image types: 175 | content_type = 'application/octet-stream' 176 | elif file_name.endswith(THUMB_SUFFIX): 177 | content_type = 'image/png' 178 | self.response.headers['Content-Type'] = content_type 179 | # Cache for the expiration time: 180 | self.response.headers['Cache-Control'] = 'public,max-age=%d' \ 181 | % EXPIRATION_TIME 182 | self.response.write(data) 183 | 184 | def delete(self, content_type, data_hash, file_name): 185 | content_type = self.normalize(content_type) 186 | file_name = self.normalize(file_name) 187 | key = content_type + '/' + data_hash + '/' + file_name 188 | result = {key: memcache.delete(key)} 189 | content_type = urllib.unquote(content_type) 190 | if IMAGE_TYPES.match(content_type): 191 | thumbnail_key = key + THUMB_SUFFIX 192 | result[thumbnail_key] = memcache.delete(thumbnail_key) 193 | if 'application/json' in self.request.headers.get('Accept'): 194 | self.response.headers['Content-Type'] = 'application/json' 195 | s = self.json_stringify(result) 196 | self.response.write(s) 197 | 198 | app = webapp2.WSGIApplication( 199 | [ 200 | ('/', UploadHandler), 201 | ('/(.+)/([^/]+)/([^/]+)', FileHandler) 202 | ], 203 | debug=DEBUG 204 | ) 205 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/server/gae-python/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/jQuery-File-Upload-9.18.0/server/gae-python/static/favicon.ico -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/server/gae-python/static/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/server/php/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.0-apache 2 | 3 | # Enable the Apache Headers module: 4 | RUN ln -s /etc/apache2/mods-available/headers.load \ 5 | /etc/apache2/mods-enabled/headers.load 6 | 7 | # Enable the Apache Rewrite module: 8 | RUN ln -s /etc/apache2/mods-available/rewrite.load \ 9 | /etc/apache2/mods-enabled/rewrite.load 10 | 11 | # Install GD, Imagick and ImageMagick as image conversion options: 12 | RUN DEBIAN_FRONTEND=noninteractive \ 13 | apt-get update && apt-get install -y --no-install-recommends \ 14 | libpng-dev \ 15 | libjpeg-dev \ 16 | libmagickwand-dev \ 17 | imagemagick \ 18 | && pecl install \ 19 | imagick \ 20 | && docker-php-ext-enable \ 21 | imagick \ 22 | && docker-php-ext-configure \ 23 | gd --with-jpeg-dir=/usr/include/ \ 24 | && docker-php-ext-install \ 25 | gd \ 26 | # Uninstall obsolete packages: 27 | && apt-get autoremove -y \ 28 | libpng-dev \ 29 | libjpeg-dev \ 30 | libmagickwand-dev \ 31 | # Remove obsolete files: 32 | && apt-get clean \ 33 | && rm -rf \ 34 | /tmp/* \ 35 | /usr/share/doc/* \ 36 | /var/cache/* \ 37 | /var/lib/apt/lists/* \ 38 | /var/tmp/* 39 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/server/php/docker-compose.yml: -------------------------------------------------------------------------------- 1 | apache: 2 | build: ./ 3 | ports: 4 | - "80:80" 5 | volumes: 6 | - "../../:/var/www/html" 7 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/server/php/files/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !.htaccess 4 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/server/php/files/.htaccess: -------------------------------------------------------------------------------- 1 | # To enable the Headers module, execute the following command and reload Apache: 2 | # sudo a2enmod headers 3 | 4 | # The following directives prevent the execution of script files 5 | # in the context of the website. 6 | # They also force the content-type application/octet-stream and 7 | # force browsers to display a download dialog for non-image files. 8 | SetHandler default-handler 9 | ForceType application/octet-stream 10 | Header set Content-Disposition attachment 11 | 12 | # The following unsets the forced type and Content-Disposition headers 13 | # for known image files: 14 | 15 | ForceType none 16 | Header unset Content-Disposition 17 | 18 | 19 | # The following directive prevents browsers from MIME-sniffing the content-type. 20 | # This is an important complement to the ForceType directive above: 21 | Header set X-Content-Type-Options nosniff 22 | 23 | # Uncomment the following lines to prevent unauthorized download of files: 24 | #AuthName "Authorization required" 25 | #AuthType Basic 26 | #require valid-user 27 | -------------------------------------------------------------------------------- /fatfs_data/jQuery-File-Upload-9.18.0/server/php/index.php: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 17 | 20 | 21 | jQuery File Upload Plugin Test 22 | 23 | 24 | 25 | 26 |

jQuery File Upload Plugin Test

27 |

28 |
29 |

30 |
    31 |
    32 | 33 |
    34 | 35 |
    36 |
    37 | 38 | 39 | 40 | Add files... 41 | 42 | 43 | 47 | 51 | 55 | 56 | 57 | 58 |
    59 | 60 |
    61 | 62 |
    63 |
    64 |
    65 | 66 |
     
    67 |
    68 |
    69 | 70 | 71 |
    72 |
    73 | 74 | 105 | 106 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /fatfs_data/jqueryui/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright jQuery Foundation and other contributors, https://jquery.org/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/jquery/jquery-ui 6 | 7 | The following license applies to all parts of this software except as 8 | documented below: 9 | 10 | ==== 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ==== 32 | 33 | Copyright and related rights for sample code are waived via CC0. Sample 34 | code is defined as all source code contained within the demos directory. 35 | 36 | CC0: http://creativecommons.org/publicdomain/zero/1.0/ 37 | 38 | ==== 39 | 40 | All files located in the node_modules and external directories are 41 | externally maintained libraries used by this software which have their 42 | own licenses; we recommend you read them, as their terms may differ from 43 | the terms above. 44 | -------------------------------------------------------------------------------- /fatfs_data/jqueryui/images/ui-icons_444444_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/jqueryui/images/ui-icons_444444_256x240.png -------------------------------------------------------------------------------- /fatfs_data/jqueryui/images/ui-icons_555555_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/jqueryui/images/ui-icons_555555_256x240.png -------------------------------------------------------------------------------- /fatfs_data/jqueryui/images/ui-icons_777620_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/jqueryui/images/ui-icons_777620_256x240.png -------------------------------------------------------------------------------- /fatfs_data/jqueryui/images/ui-icons_777777_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/jqueryui/images/ui-icons_777777_256x240.png -------------------------------------------------------------------------------- /fatfs_data/jqueryui/images/ui-icons_cc0000_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/jqueryui/images/ui-icons_cc0000_256x240.png -------------------------------------------------------------------------------- /fatfs_data/jqueryui/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/jqueryui/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /fatfs_data/jqueryui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-ui", 3 | "title": "jQuery UI", 4 | "description": "A curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library.", 5 | "version": "1.12.1", 6 | "homepage": "http://jqueryui.com", 7 | "author": { 8 | "name": "jQuery Foundation and other contributors", 9 | "url": "https://github.com/jquery/jquery-ui/blob/1.12.1/AUTHORS.txt" 10 | }, 11 | "main": "ui/widget.js", 12 | "maintainers": [ 13 | { 14 | "name": "Scott González", 15 | "email": "scott.gonzalez@gmail.com", 16 | "url": "http://scottgonzalez.com" 17 | }, 18 | { 19 | "name": "Jörn Zaefferer", 20 | "email": "joern.zaefferer@gmail.com", 21 | "url": "http://bassistance.de" 22 | }, 23 | { 24 | "name": "Mike Sherov", 25 | "email": "mike.sherov@gmail.com", 26 | "url": "http://mike.sherov.com" 27 | }, 28 | { 29 | "name": "TJ VanToll", 30 | "email": "tj.vantoll@gmail.com", 31 | "url": "http://tjvantoll.com" 32 | }, 33 | { 34 | "name": "Felix Nagel", 35 | "email": "info@felixnagel.com", 36 | "url": "http://www.felixnagel.com" 37 | }, 38 | { 39 | "name": "Alex Schmitz", 40 | "email": "arschmitz@gmail.com", 41 | "url": "https://github.com/arschmitz" 42 | } 43 | ], 44 | "repository": { 45 | "type": "git", 46 | "url": "git://github.com/jquery/jquery-ui.git" 47 | }, 48 | "bugs": "https://bugs.jqueryui.com/", 49 | "license": "MIT", 50 | "scripts": { 51 | "test": "grunt" 52 | }, 53 | "dependencies": {}, 54 | "devDependencies": { 55 | "commitplease": "2.3.0", 56 | "grunt": "0.4.5", 57 | "grunt-bowercopy": "1.2.4", 58 | "grunt-cli": "0.1.13", 59 | "grunt-compare-size": "0.4.0", 60 | "grunt-contrib-concat": "0.5.1", 61 | "grunt-contrib-csslint": "0.5.0", 62 | "grunt-contrib-jshint": "0.12.0", 63 | "grunt-contrib-qunit": "1.0.1", 64 | "grunt-contrib-requirejs": "0.4.4", 65 | "grunt-contrib-uglify": "0.11.1", 66 | "grunt-git-authors": "3.1.0", 67 | "grunt-html": "6.0.0", 68 | "grunt-jscs": "2.1.0", 69 | "load-grunt-tasks": "3.4.0", 70 | "rimraf": "2.5.1", 71 | "testswarm": "1.1.0" 72 | }, 73 | "keywords": [] 74 | } 75 | -------------------------------------------------------------------------------- /fatfs_data/jstree/themes/default-dark/32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/jstree/themes/default-dark/32px.png -------------------------------------------------------------------------------- /fatfs_data/jstree/themes/default-dark/40px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/jstree/themes/default-dark/40px.png -------------------------------------------------------------------------------- /fatfs_data/jstree/themes/default-dark/throbber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/jstree/themes/default-dark/throbber.gif -------------------------------------------------------------------------------- /fatfs_data/jstree/themes/default/32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/jstree/themes/default/32px.png -------------------------------------------------------------------------------- /fatfs_data/jstree/themes/default/40px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/jstree/themes/default/40px.png -------------------------------------------------------------------------------- /fatfs_data/jstree/themes/default/throbber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkolban/ESP32_Explorer/611fcd1e418cdbb0744abaa7f3340849f84f1e60/fatfs_data/jstree/themes/default/throbber.gif -------------------------------------------------------------------------------- /main/BLEExplorer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEExplorer.cpp 3 | * 4 | * Created on: Sep 27, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #include "BLEExplorer.h" 9 | #include "sdkconfig.h" 10 | #include 11 | #include 12 | #include "Task.h" 13 | #include "Memory.h" 14 | #include 15 | #include "BLE2902.h" 16 | #include "BLEClient.h" 17 | static const char* LOG_TAG = "BLEExplorer"; 18 | static bool isRunning = false; 19 | static BLEServer *pServer; 20 | static BLEServiceMap *mServices; 21 | static BLECharacteristicMap *mCharacteristics; 22 | 23 | BLEExplorer::BLEExplorer() { 24 | // TODO Auto-generated constructor stub 25 | } 26 | 27 | BLEExplorer::~BLEExplorer() { 28 | // TODO Auto-generated destructor stub 29 | } 30 | /** 31 | * @brief Perform a BLE Scan and return the results. 32 | */ 33 | JsonArray BLEExplorer::scan() { 34 | ESP_LOGD(LOG_TAG, ">> scan"); 35 | if(!isRunning){ 36 | BLEDevice::init(""); 37 | isRunning = true; 38 | } 39 | BLEScan* pBLEScan = BLEDevice::getScan(); 40 | pBLEScan->setActiveScan(true); 41 | BLEScanResults scanResults = pBLEScan->start(1); 42 | JsonObject obj = JSON::createObject(); 43 | JsonArray arr = JSON::createArray(); 44 | arr.addString("BLE devices"); 45 | for (int c = 0; c < scanResults.getCount(); ++c) { 46 | BLEAdvertisedDevice dev = scanResults.getDevice(c); 47 | arr.addObject(enumerateDevices(dev)); 48 | } 49 | obj.setInt("deviceCount", scanResults.getCount()); 50 | ESP_LOGD(LOG_TAG, "<< scan"); 51 | return arr; 52 | } // scan 53 | /* 54 | * @brief Connect to BLE server to get and enumerate services and characteristics 55 | */ 56 | JsonArray BLEExplorer::connect(std::string _addr){ 57 | BLEAddress *pAddress = new BLEAddress(_addr); 58 | BLEClient* pClient = BLEDevice::createClient(); 59 | 60 | // Connect to the remove BLE Server. 61 | pClient->connect(*pAddress); 62 | std::map *pRemoteServices = pClient->getServices(); 63 | if (pRemoteServices == nullptr) { 64 | ESP_LOGD(LOG_TAG, "Failed to find services"); 65 | return JSON::createArray(); 66 | } 67 | // Memory::startTraceAll(); 68 | JsonArray arr = JSON::createArray(); 69 | for (auto it=pRemoteServices->begin(); it!=pRemoteServices->end(); ++it) { 70 | JsonObject obj = JSON::createObject(); 71 | char tmp[33]; 72 | itoa(it->second->getHandle(), tmp, 16); 73 | 74 | obj.setString("id", tmp); // todo service's handle 75 | obj.setString("text", BLEUtils::gattServiceToString(it->second->getUUID().getNative()->uuid.uuid32) + " Service: " + it->second->getUUID().toString()); 76 | obj.setString("icon", "service"); 77 | JsonObject state = JSON::createObject(); 78 | state.setBoolean("opened", true); 79 | obj.setObject("state", state); 80 | obj.setString("parent", _addr); 81 | std::map *pChars = it->second->getCharacteristics(); 82 | obj.setArray("children", enumerateCharacteristics(pChars)); 83 | arr.addObject(obj); 84 | } 85 | 86 | pClient->disconnect(); 87 | /* 88 | free(pClient); 89 | free(pAddress); //FIXME using it here causing multi heap crash 90 | free(pRemoteServices);*/ 91 | return arr; 92 | } 93 | /* 94 | * @brief Enumerate devices 95 | */ 96 | JsonObject BLEExplorer::enumerateDevices(BLEAdvertisedDevice device){ 97 | JsonArray arr = JSON::createArray(); 98 | JsonObject obj = JSON::createObject(); 99 | obj.setString("id", device.getAddress().toString()); 100 | obj.setString("parent", "#"); 101 | obj.setString("text", device.getName() == ""? "N/A":device.getName()); 102 | JsonObject state = JSON::createObject(); 103 | state.setBoolean("opened", true); 104 | obj.setObject("state", state); 105 | JsonObject obj2 = JSON::createObject(); 106 | //obj2.setString("id", device.getAddress().toString()); 107 | //obj2.setString("parent", device.getAddress().toString()); 108 | obj2.setString("text", "Address - " + device.getAddress().toString()); 109 | //obj2.setBoolean("children", false); 110 | arr.addObject(obj2); 111 | if(device.haveManufacturerData()){ 112 | obj2 = JSON::createObject(); 113 | obj2.setString("text", "Manufacturer - " + atoi(device.getManufacturerData().c_str())); 114 | arr.addObject(obj2); 115 | } 116 | std::stringstream ss; 117 | if(device.haveAppearance()){ 118 | ss << "Appearance - " << device.getAppearance(); 119 | obj2 = JSON::createObject(); 120 | obj2.setString("text", ss.str()); 121 | arr.addObject(obj2); 122 | } 123 | if(device.haveRSSI()){ 124 | ss.str(""); 125 | ss << "RSSI - " << (int)device.getRSSI(); 126 | obj2 = JSON::createObject(); 127 | obj2.setString("text", ss.str()); 128 | arr.addObject(obj2); 129 | } 130 | if(device.haveTXPower()){ 131 | ss.str(""); 132 | ss << "TX power - " << (int)device.getTXPower(); 133 | obj2 = JSON::createObject(); 134 | obj2.setString("text", ss.str()); 135 | arr.addObject(obj2); 136 | } 137 | if(device.haveServiceUUID()){ 138 | ss.str(""); 139 | ss << "Advertised services - " << device.getServiceUUID().toString(); 140 | obj2 = JSON::createObject(); 141 | obj2.setString("text", ss.str()); 142 | arr.addObject(obj2); 143 | } 144 | 145 | 146 | obj.setArray("children", arr); 147 | 148 | return obj; 149 | } 150 | /* 151 | * @brief Enumerate characteristics from given service 152 | */ 153 | JsonArray BLEExplorer::enumerateCharacteristics(std::map *characteristicMap){ 154 | 155 | //std::map *characteristicMap = pService; 156 | //pService->getCharacteristics(characteristicMap); 157 | JsonArray arr = JSON::createArray(); 158 | char tmp[33]; 159 | 160 | for (auto it=characteristicMap->begin(); it!=characteristicMap->end(); it++) { // TODO add descriptors enumerator, add short uuid if characteristic !UNKNOWN 161 | JsonObject ch = JSON::createObject(); 162 | JsonObject val = JSON::createObject(); 163 | JsonArray ar = JSON::createArray(); 164 | itoa(it->second->getHandle(), tmp, 16); 165 | ch.setString("id", tmp); // characteristic's handle 166 | 167 | std::string str = it->second->canRead()?"R":""; 168 | str += it->second->canWrite()?"\\W":""; 169 | str += it->second->canBroadcast()?"\\B":""; 170 | str += it->second->canIndicate()?"\\I":""; 171 | str += it->second->canNotify()?"\\N]":"]"; 172 | std::stringstream ss1; 173 | ss1 << BLEUtils::gattCharacteristicUUIDToString(it->second->getUUID().getNative()->uuid.uuid16) << \ 174 | " Characteristic: " << it->second->getUUID().toString() << "[" << \ 175 | str; 176 | 177 | ch.setString("text", ss1.str()); 178 | 179 | ch.setString("icon", "characteristic"); 180 | JsonObject state = JSON::createObject(); 181 | state.setBoolean("opened", true); 182 | ch.setObject("state", state); 183 | std::map pChars; 184 | std::map *desc = it->second->getDescriptors(); 185 | ar = enumerateDescriptors(desc); 186 | std::string f = it->second->readValue(); 187 | ESP_LOGI(LOG_TAG, "Value: %s, %d, %#4x", f.c_str(), it->second->readUInt32(), it->second->readUInt32()); 188 | std::stringstream ss; 189 | ss << "Value: " << f; 190 | val.setString("text", ss.str()); 191 | ar.addObject(val); 192 | ch.setArray("children", ar); 193 | arr.addObject(ch); 194 | } 195 | 196 | return arr; 197 | } 198 | 199 | JsonArray BLEExplorer::enumerateDescriptors(std::map* descriptors){ 200 | JsonArray arr = JSON::createArray(); 201 | for(auto it=descriptors->begin();it!=descriptors->end();it++){ 202 | JsonObject obj = JSON::createObject(); 203 | obj.setString("icon", "descriptor"); 204 | /*JsonObject val = JSON::createObject(); 205 | std::stringstream ss; 206 | ss << "Value: " << it->second->readValue(); 207 | val.setString("text", ss.str()); 208 | obj.setObject("children", val);*/ 209 | obj.setString("text", BLEUtils::gattDescriptorUUIDToString(it->second->getUUID().getNative()->uuid.uuid16) + " Descriptor: " + it->second->getUUID().toString()); 210 | arr.addObject(obj); 211 | } 212 | 213 | return arr; 214 | } 215 | 216 | void BLEExplorer::createServer(std::string name){ 217 | BLEDevice::init(name); 218 | pServer = BLEDevice::createServer(); 219 | mCharacteristics = new BLECharacteristicMap(); 220 | mServices = new BLEServiceMap(); 221 | } 222 | 223 | void BLEExplorer::startService(uint16_t handle){ 224 | BLEService *pservice = mServices->getByHandle(handle); 225 | pservice->start(); 226 | } 227 | 228 | JsonObject BLEExplorer::addService(BLEUUID _uuid){ 229 | JsonObject obj = JSON::createObject(); 230 | 231 | char ptr[33]; 232 | BLEService *pservice = pServer->createService(_uuid); 233 | if(pservice != nullptr){ 234 | mServices->setByHandle(pservice->getHandle(), pservice); 235 | // pservice->start(); 236 | obj.setString("icon", "service"); 237 | itoa(pservice->getHandle(), ptr, 16); 238 | obj.setString("handle", ptr); 239 | obj.setString("parent", "#"); 240 | obj.setString("text", BLEUtils::gattServiceToString(pservice->getUUID().getNative()->uuid.uuid16) + " Service: " + pservice->getUUID().toString()); 241 | } 242 | return obj; 243 | } 244 | 245 | JsonObject BLEExplorer::addCharacteristic(BLEUUID uuid, uint16_t service){ 246 | char ptr[33]; 247 | BLEService *pservice = mServices->getByHandle(service); 248 | ESP_LOGE(LOG_TAG, "ADD: %d", pservice->getHandle()); 249 | BLECharacteristic *charact = pservice->createCharacteristic(BLEUUID(uuid), {BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE}); 250 | charact->setValue("Private name"); 251 | //mCharacteristics->setByHandle(charact->getHandle(), charact); 252 | JsonObject obj = JSON::createObject(); 253 | obj.setString("icon", "characteristic"); 254 | itoa(charact->getHandle(), ptr, 16); 255 | obj.setString("handle", ptr); 256 | itoa(service, ptr, 16); 257 | obj.setString("parent", ptr); 258 | obj.setString("text", BLEUtils::gattCharacteristicUUIDToString(charact->getUUID().getNative()->uuid.uuid16) + " Characteristic: " + charact->getUUID().toString()); 259 | return obj; 260 | } 261 | 262 | JsonObject BLEExplorer::addDescriptor(BLEUUID uuid, uint16_t charact){ 263 | char ptr[33]; 264 | BLECharacteristic *pcharact = mCharacteristics->getByHandle(charact); 265 | assert(charact == pcharact->getHandle()); 266 | BLEDescriptor *descr = new BLE2902(); 267 | pcharact->addDescriptor(descr); 268 | JsonObject obj = JSON::createObject(); 269 | obj.setString("icon", "descriptor"); 270 | itoa(descr->getHandle(), ptr, 16); 271 | obj.setString("handle", ptr); 272 | itoa(pcharact->getHandle(), ptr, 16); 273 | obj.setString("parent", ptr); 274 | obj.setString("text", BLEUtils::gattDescriptorUUIDToString(uuid.getNative()->uuid.uuid32) + " Descriptor: " + uuid.toString()); 275 | return obj; 276 | } 277 | 278 | void BLEExplorer::startAdvertising(){ 279 | pServer->getAdvertising()->start(); 280 | } 281 | 282 | void BLEExplorer::stopAdvertising(){ 283 | pServer->getAdvertising()->stop(); 284 | } 285 | 286 | -------------------------------------------------------------------------------- /main/BLEExplorer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEExplorer.h 3 | * 4 | * Created on: Sep 27, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef MAIN_BLEEXPLORER_H_ 9 | #define MAIN_BLEEXPLORER_H_ 10 | #include 11 | #include "JSON.h" 12 | #include "BLEAdvertisedDevice.h" 13 | 14 | class BLEExplorer { 15 | public: 16 | BLEExplorer(); 17 | virtual ~BLEExplorer(); 18 | JsonArray scan(); 19 | JsonArray connect(std::string addr); 20 | JsonObject enumerateDevices(BLEAdvertisedDevice device); 21 | JsonArray enumerateCharacteristics(std::map *characteristicMap); 22 | JsonArray enumerateDescriptors(std::map *descriptorsMap); 23 | 24 | // --- SERVER --- // 25 | void createServer(std::string name); 26 | void deleteServer(); 27 | JsonObject addService(BLEUUID uuid); 28 | void startService(uint16_t handle); 29 | //void stopServer(); 30 | void startAdvertising(); 31 | void stopAdvertising(); 32 | JsonObject addCharacteristic(BLEUUID uuid, uint16_t service); 33 | JsonObject addDescriptor(BLEUUID uuid, uint16_t characteristic); 34 | void setCharacteristicValue(BLEUUID uuid, std::string value); 35 | 36 | private: 37 | }; 38 | 39 | #endif /* MAIN_BLEEXPLORER_H_ */ 40 | 41 | -------------------------------------------------------------------------------- /main/BootWiFi.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Bootwifi - Boot the WiFi environment. 3 | * 4 | * Compile with -DBOOTWIFI_OVERRIDE_GPIO= where is a GPIO pin number 5 | * to use a GPIO override. 6 | * See the README.md for full information. 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | //#include 17 | //#include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "BootWiFi.h" 24 | #include "sdkconfig.h" 25 | #include "selectAP.h" 26 | 27 | // If the structure of a record saved for a subsequent reboot changes 28 | // then consider using semver to change the version number or else 29 | // we may try and boot with the wrong data. 30 | #define KEY_VERSION "version" 31 | uint32_t g_version=0x0100; 32 | 33 | #define KEY_CONNECTION_INFO "connectionInfo" // Key used in NVS for connection info 34 | #define BOOTWIFI_NAMESPACE "bootwifi" // Namespace in NVS for bootwifi 35 | #define SSID_SIZE (32) // Maximum SSID size 36 | #define PASSWORD_SIZE (64) // Maximum password size 37 | 38 | 39 | /** 40 | * The information about a WiFi access point connection. 41 | */ 42 | typedef struct { 43 | char ssid[SSID_SIZE]; 44 | char password[PASSWORD_SIZE]; 45 | tcpip_adapter_ip_info_t ipInfo; // Optional static IP information 46 | } connection_info_t; 47 | 48 | //static bootwifi_callback_t g_callback = NULL; // Callback function to be invoked when we have finished. 49 | 50 | 51 | // Forward declarations 52 | static void saveConnectionInfo(connection_info_t *pConnectionInfo); 53 | 54 | static const char LOG_TAG[] = "bootwifi"; 55 | 56 | 57 | static void dumpConnectionInfo(connection_info_t *pConnectionInfo) { 58 | ESP_LOGD(LOG_TAG, "connection_info.ssid = %.*s", SSID_SIZE, pConnectionInfo->ssid); 59 | ESP_LOGD(LOG_TAG, "connection_info.password = %.*s", PASSWORD_SIZE, pConnectionInfo->password); 60 | ESP_LOGD(LOG_TAG, "ip: %s, gw: %s, netmask: %s", 61 | GeneralUtils::ipToString((uint8_t*)&pConnectionInfo->ipInfo.ip).c_str(), 62 | GeneralUtils::ipToString((uint8_t*)&pConnectionInfo->ipInfo.gw).c_str(), 63 | GeneralUtils::ipToString((uint8_t*)&pConnectionInfo->ipInfo.netmask).c_str()); 64 | } 65 | 66 | 67 | /** 68 | * Retrieve the connection info. A rc==0 means ok. 69 | */ 70 | static int getConnectionInfo(connection_info_t *pConnectionInfo) { 71 | ESP_LOGD(LOG_TAG, ">> getConnectionInfo"); 72 | size_t size; 73 | uint32_t version; 74 | 75 | NVS myNamespace(BOOTWIFI_NAMESPACE); 76 | myNamespace.get(KEY_VERSION, version); 77 | 78 | // Check the versions match 79 | if ((version & 0xff00) != (g_version & 0xff00)) { 80 | ESP_LOGD(LOG_TAG, "Incompatible versions ... current is %x, found is %x", version, g_version); 81 | return -1; 82 | } 83 | 84 | size = sizeof(connection_info_t); 85 | myNamespace.get(KEY_CONNECTION_INFO, (uint8_t*)pConnectionInfo, size); 86 | 87 | // Do a sanity check on the SSID 88 | if (strlen(pConnectionInfo->ssid) == 0) { 89 | ESP_LOGD(LOG_TAG, "NULL ssid detected"); 90 | return -1; 91 | } 92 | dumpConnectionInfo(pConnectionInfo); 93 | ESP_LOGD(LOG_TAG, "<< getConnectionInfo"); 94 | return 0; 95 | 96 | } // getConnectionInfo 97 | 98 | 99 | /** 100 | * Save our connection info for retrieval on a subsequent restart. 101 | */ 102 | static void saveConnectionInfo(connection_info_t *pConnectionInfo) { 103 | dumpConnectionInfo(pConnectionInfo); 104 | NVS myNamespace(BOOTWIFI_NAMESPACE); 105 | myNamespace.set(KEY_CONNECTION_INFO, (uint8_t*)pConnectionInfo, sizeof(connection_info_t)); 106 | myNamespace.set(KEY_VERSION, g_version); 107 | myNamespace.commit(); 108 | } // setConnectionInfo 109 | 110 | 111 | /** 112 | * Retrieve the signal level on the OVERRIDE_GPIO pin. This is used to 113 | * indicate that we should not attempt to connect to any previously saved 114 | * access point we may know about. 115 | */ 116 | 117 | static int checkOverrideGpio() { 118 | #ifdef BOOTWIFI_OVERRIDE_GPIO 119 | gpio_pad_select_gpio(BOOTWIFI_OVERRIDE_GPIO); 120 | gpio_set_direction(BOOTWIFI_OVERRIDE_GPIO, GPIO_MODE_INPUT); 121 | gpio_set_pull_mode(BOOTWIFI_OVERRIDE_GPIO, GPIO_PULLDOWN_ONLY); 122 | return gpio_get_level(BOOTWIFI_OVERRIDE_GPIO); 123 | #else 124 | return 0; // If no boot override, return false 125 | #endif 126 | } // checkOverrideGpio 127 | 128 | static void sendForm(HttpRequest* pRequest, HttpResponse* pResponse) { 129 | pResponse->setStatus(HttpResponse::HTTP_STATUS_OK, "OK"); 130 | pResponse->addHeader(HttpRequest::HTTP_HEADER_CONTENT_TYPE, "text/html"); 131 | pResponse->sendData(std::string((char*)selectAP_html, selectAP_html_len)); 132 | pResponse->close(); 133 | } // sendForm 134 | 135 | 136 | static void copyData(uint8_t* pTarget, size_t targetLength, std::string source) { 137 | memset(pTarget, 0, targetLength); 138 | size_t copySize = (source.length() > targetLength)? targetLength:source.length(); 139 | memcpy(pTarget, source.data(), copySize); 140 | if (copySize < targetLength) { 141 | pTarget[copySize] = '\0'; 142 | } 143 | } // copyData 144 | 145 | 146 | /** 147 | * @brief Process the form response. 148 | */ 149 | static void processForm(HttpRequest* pRequest, HttpResponse* pResponse) { 150 | ESP_LOGD(LOG_TAG, ">> processForm"); 151 | std::map formMap = pRequest->parseForm(); 152 | connection_info_t connectionInfo; 153 | copyData((uint8_t*)connectionInfo.ssid, SSID_SIZE, formMap["ssid"]); 154 | copyData((uint8_t*)connectionInfo.password, PASSWORD_SIZE, formMap["password"]); 155 | 156 | try { 157 | std::string ipStr = formMap.at("ip"); 158 | if (ipStr.empty()) { 159 | ESP_LOGD(LOG_TAG, "No IP address using default 0.0.0.0"); 160 | connectionInfo.ipInfo.ip.addr = 0; 161 | } else { 162 | inet_pton(AF_INET, ipStr.c_str(), &connectionInfo.ipInfo.ip); 163 | } 164 | } catch(std::out_of_range& e) { 165 | ESP_LOGD(LOG_TAG, "No IP address using default 0.0.0.0"); 166 | connectionInfo.ipInfo.ip.addr = 0; 167 | } 168 | 169 | try { 170 | std::string gwStr = formMap.at("gw"); 171 | if (gwStr.empty()) { 172 | ESP_LOGD(LOG_TAG, "No GW address using default 0.0.0.0"); 173 | connectionInfo.ipInfo.gw.addr = 0; 174 | } else { 175 | inet_pton(AF_INET, gwStr.c_str(), &connectionInfo.ipInfo.gw); 176 | } 177 | } catch(std::out_of_range& e) { 178 | ESP_LOGD(LOG_TAG, "No GW address using default 0.0.0.0"); 179 | connectionInfo.ipInfo.gw.addr = 0; 180 | } 181 | 182 | try { 183 | std::string netmaskStr = formMap.at("netmask"); 184 | if (netmaskStr.empty()) { 185 | ESP_LOGD(LOG_TAG, "No Netmask address using default 0.0.0.0"); 186 | connectionInfo.ipInfo.netmask.addr = 0; 187 | } else { 188 | inet_pton(AF_INET, netmaskStr.c_str(), &connectionInfo.ipInfo.netmask); 189 | } 190 | } catch(std::out_of_range& e) { 191 | ESP_LOGD(LOG_TAG, "No Netmask address using default 0.0.0.0"); 192 | connectionInfo.ipInfo.netmask.addr = 0; 193 | } 194 | 195 | ESP_LOGD(LOG_TAG, "ssid: %s, password: %s", connectionInfo.ssid, connectionInfo.password); 196 | 197 | saveConnectionInfo(&connectionInfo); 198 | 199 | pResponse->setStatus(HttpResponse::HTTP_STATUS_OK, "OK"); 200 | pResponse->addHeader(HttpRequest::HTTP_HEADER_CONTENT_TYPE, "text/html"); 201 | //pResponse->sendData(std::string((char*)selectAP_html, selectAP_html_len)); 202 | pResponse->close(); 203 | FreeRTOS::sleep(500); 204 | //GeneralUtils::restart(); 205 | esp_restart(); 206 | ESP_LOGD(LOG_TAG, "<< processForm"); 207 | } // processForm 208 | 209 | 210 | class BootWifiEventHandler: public WiFiEventHandler { 211 | public: 212 | BootWifiEventHandler(BootWiFi *pBootWiFi) { 213 | m_pBootWiFi = pBootWiFi; 214 | } 215 | 216 | /** 217 | * When the access point logic has started and we are able to receive incoming browser 218 | * requests, start the internal HTTP Server. 219 | */ 220 | esp_err_t apStart() { 221 | ESP_LOGD("BootWifiEventHandler", ">> apStart"); 222 | if (m_pBootWiFi->m_httpServerStarted == false) { 223 | m_pBootWiFi->m_httpServerStarted = true; 224 | m_pBootWiFi->m_httpServer.addPathHandler("GET", "/", sendForm); 225 | m_pBootWiFi->m_httpServer.addPathHandler("POST", "/ssidSelected", processForm); 226 | m_pBootWiFi->m_httpServer.start(80); 227 | } 228 | ESP_LOGD("BootWifiEventHandler", "<< apStart"); 229 | return ESP_OK; 230 | } // apStaConnected 231 | 232 | /** 233 | * If we fail to connect as a station, then become an access point and then 234 | * become a web server. 235 | */ 236 | esp_err_t staDisconnected() { 237 | ESP_LOGD("BootWifiEventHandler", ">> staDisconnected"); 238 | m_pBootWiFi->m_wifi.startAP("Duktape", "Duktape"); 239 | ESP_LOGD("BootWifiEventHandler", "<< staDisconnected"); 240 | return ESP_OK; 241 | } 242 | 243 | private: 244 | BootWiFi *m_pBootWiFi; 245 | }; 246 | 247 | 248 | void BootWiFi::bootWiFi2() { 249 | ESP_LOGD(LOG_TAG, ">> bootWiFi2"); 250 | // Check for a GPIO override which occurs when a physical Pin is high 251 | // during the test. This can force the ability to check for new configuration 252 | // even if the existing configured access point is available. 253 | m_wifi.setWifiEventHandler(new BootWifiEventHandler(this)); 254 | if (checkOverrideGpio()) { 255 | ESP_LOGD(LOG_TAG, "- GPIO override detected"); 256 | m_wifi.startAP(m_ssid, m_password); 257 | } else { 258 | // There was NO GPIO override, proceed as normal. This means we retrieve 259 | // our stored access point information of the access point we should connect 260 | // against. If that information doesn't exist, then again we become an 261 | // access point ourselves in order to allow a client to connect and bring 262 | // up a browser. 263 | connection_info_t connectionInfo; 264 | int rc = getConnectionInfo(&connectionInfo); 265 | if (rc == 0) { 266 | // We have received connection information, let us now become a station 267 | // and attempt to connect to the access point. 268 | ESP_LOGD(LOG_TAG, "- Connecting to access point \"%s\" ...", connectionInfo.ssid); 269 | assert(strlen(connectionInfo.ssid) > 0); 270 | 271 | m_wifi.setIPInfo( 272 | connectionInfo.ipInfo.ip.addr, 273 | connectionInfo.ipInfo.gw.addr, 274 | connectionInfo.ipInfo.netmask.addr 275 | ); 276 | m_wifi.connectAP(connectionInfo.ssid, connectionInfo.password); // Connect to the access point. 277 | 278 | } else { 279 | // We do NOT have connection information. Let us now become an access 280 | // point that serves up a web server and allow a browser user to specify 281 | // the details that will be eventually used to allow us to connect 282 | // as a station. 283 | m_wifi.startAP(m_ssid, m_password); 284 | } // We do NOT have connection info 285 | } 286 | ESP_LOGD(LOG_TAG, "<< bootWiFi2"); 287 | } // bootWiFi2 288 | 289 | 290 | /** 291 | * @brief Set the userid/password pair that will be used for the ESP32 access point. 292 | * @param [in] ssid The network id of the ESP32 when it becomes an access point. 293 | * @param [in] password The password for the ESP32 when it becomes an access point. 294 | */ 295 | void BootWiFi::setAccessPointCredentials(std::string ssid, std::string password) { 296 | m_ssid = ssid; 297 | m_password = password; 298 | } // setAccessPointCredentials 299 | 300 | 301 | void BootWiFi::boot() { 302 | ESP_LOGD(LOG_TAG, ">> boot"); 303 | ESP_LOGD(LOG_TAG, " +----------+"); 304 | ESP_LOGD(LOG_TAG, " | BootWiFi |"); 305 | ESP_LOGD(LOG_TAG, " +----------+"); 306 | ESP_LOGD(LOG_TAG, " Access point credentials: %s/%s", m_ssid.c_str(), m_password.c_str()); 307 | //m_completeSemaphore.take("boot"); // Take the semaphore which will be unlocked when we complete booting. 308 | bootWiFi2(); 309 | //m_completeSemaphore.wait("boot"); // Wait for the semaphore that indicated we have completed booting. 310 | ESP_LOGD(LOG_TAG, "<< boot"); 311 | } 312 | 313 | BootWiFi::BootWiFi() { 314 | m_httpServerStarted = false; 315 | setAccessPointCredentials("esp32", "password"); // Default access point credentials 316 | } 317 | -------------------------------------------------------------------------------- /main/BootWiFi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BootWiFi.h 3 | * 4 | * Created on: Nov 25, 2016 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef MAIN_BOOTWIFI_H_ 9 | #define MAIN_BOOTWIFI_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | typedef void (*bootwifi_callback_t)(int rc); 16 | class BootWifiEventHandler; 17 | 18 | class BootWiFi { 19 | private: 20 | friend BootWifiEventHandler; 21 | void bootWiFi2(); 22 | WiFi m_wifi; 23 | HttpServer m_httpServer; 24 | bool m_httpServerStarted; 25 | std::string m_ssid; 26 | std::string m_password; 27 | FreeRTOS::Semaphore m_completeSemaphore = FreeRTOS::Semaphore("completeSemaphore"); 28 | 29 | public: 30 | BootWiFi(); 31 | void setAccessPointCredentials(std::string ssid, std::string password); 32 | void boot(); 33 | }; 34 | 35 | #endif /* MAIN_BOOTWIFI_H_ */ 36 | -------------------------------------------------------------------------------- /main/ESP32Explorer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ESP32Explorer.h 3 | * 4 | * Created on: May 22, 2017 5 | * Author: kolban 6 | */ 7 | 8 | #ifndef MAIN_ESP32EXPLORER_H_ 9 | #define MAIN_ESP32EXPLORER_H_ 10 | 11 | class ESP32_Explorer { 12 | public: 13 | ESP32_Explorer(); 14 | virtual ~ESP32_Explorer(); 15 | void start(); 16 | }; 17 | 18 | #endif /* MAIN_ESP32EXPLORER_H_ */ 19 | -------------------------------------------------------------------------------- /main/FILESYSTEM_JSON.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static char tag[] = "FILESYSTEM_JSON"; 12 | JsonObject FILESYSTEM_GET_JSON_CONTENT(std::string path) { 13 | // Stat the file to make sure it is there and to determine what kind of a file 14 | // it is. 15 | struct stat statBuf; 16 | int rc = stat(path.c_str(), &statBuf); 17 | 18 | JsonObject obj = JSON::createObject(); 19 | if (rc == -1) { 20 | ESP_LOGE(tag, "Failed to stat file %s, errno=%s", path.c_str(), strerror(errno)); 21 | obj.setInt("errno", errno); 22 | return obj; 23 | } 24 | obj.setString("path", path); 25 | std::vector parts = FileSystem::pathSplit(path); 26 | obj.setString("name", parts[parts.size()-1]); 27 | // Do one thing if the file is a regular file. 28 | if (S_ISREG(statBuf.st_mode)) { 29 | obj.setBoolean("directory", false); 30 | File file(path.c_str()); 31 | std::string data = file.getContent(true); 32 | obj.setString("data", data); 33 | } 34 | // Do a different thing if the file is a directory. 35 | else if (S_ISDIR(statBuf.st_mode)) { 36 | obj.setBoolean("directory", true); 37 | 38 | } // End ... found a directory. 39 | return obj; 40 | } // FILESYSTEM_GET_JSON_CONTENT 41 | 42 | 43 | /** 44 | * @brief Get the content of the specified path as a JSON object. 45 | * @param [in] path The path to access. 46 | * @return A JSON object containing what was found at the path. 47 | */ 48 | JsonObject FILESYSTEM_GET_JSON_DIRECTORY(std::string path, bool isRecursive) { 49 | ESP_LOGD(tag, "FILESYSTEM_GET_JSON_DIRECTORY: path is %s", path.c_str()); 50 | 51 | // Stat the file to make sure it is there and to determine what kind of a file 52 | // it is. 53 | struct stat statBuf; 54 | int rc = stat(path.c_str(), &statBuf); 55 | 56 | JsonObject obj = JSON::createObject(); 57 | if (rc == -1) { 58 | ESP_LOGE(tag, "Failed to stat file, errno=%s", strerror(errno)); 59 | obj.setInt("errno", errno); 60 | return obj; 61 | } 62 | 63 | obj.setString("path", path); 64 | std::vector parts = FileSystem::pathSplit(path); 65 | obj.setString("name", parts[parts.size()-1]); 66 | 67 | // Do one thing if the file is a regular file. 68 | if (S_ISREG(statBuf.st_mode)) { 69 | obj.setBoolean("directory", false); 70 | } 71 | // Do a different thing if the file is a directory. 72 | else if (S_ISDIR(statBuf.st_mode)) { 73 | obj.setBoolean("directory", true); 74 | JsonArray dirArray = JSON::createArray(); 75 | obj.setArray("dir", dirArray); 76 | 77 | ESP_LOGD(tag, "Processing directory: %s", path.c_str()); 78 | std::vector files = FileSystem::getDirectoryContents(path); 79 | 80 | // Now that we have the list of files in the directory, iterator over them adding them 81 | // to our array of entries. 82 | for (std::vector::iterator it = files.begin(); it!= files.end(); it++) { 83 | if (isRecursive) { 84 | JsonObject dirEntry = FILESYSTEM_GET_JSON_DIRECTORY(path + "/" + (*it).getName(), isRecursive); 85 | dirArray.addObject(dirEntry); 86 | } else { 87 | JsonObject dirEntry = JSON::createObject(); 88 | dirEntry.setString("name", (*it).getName()); 89 | dirEntry.setInt("type", (*it).getType()); 90 | dirArray.addObject(dirEntry); 91 | } 92 | 93 | } // End ... for each entry in the directory. 94 | } // End ... found a directory. 95 | return obj; 96 | } // FILESYSTEM_GET_JSON_DIRECTORY 97 | -------------------------------------------------------------------------------- /main/GPIO_JSON.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | extern "C" { 4 | #include 5 | } 6 | 7 | JsonObject GPIO_JSON() { 8 | JsonObject obj = JSON::createObject(); 9 | JsonArray tmpArr = JSON::createArray(); 10 | int i; 11 | for (i=0;i<32; i++) { 12 | tmpArr.addBoolean((GPIO.out & (1< 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | extern "C" { 14 | #include 15 | } 16 | #include "I2C.h" 17 | 18 | JsonObject I2C_READ(std::map parts) { 19 | uint8_t SDA, SCL, ADDR, REG; 20 | uint8_t bytes = atoi(parts.at("bytesCount").c_str()); 21 | SDA = atoi(parts.at("sda").c_str()); 22 | SCL = atoi(parts.at("scl").c_str()); 23 | ADDR = atoi(parts.at("address").c_str()); 24 | REG = atoi(parts.at("register").c_str()); 25 | 26 | 27 | JsonObject obj = JSON::createObject(); 28 | JsonObject tmpObj = JSON::createObject(); 29 | I2C* i2c = new I2C(); 30 | i2c->init(ADDR, (gpio_num_t)SDA, (gpio_num_t)SCL); 31 | 32 | i2c->beginTransaction(); 33 | i2c->write(REG); 34 | i2c->endTransaction(); 35 | 36 | uint8_t data[bytes]; 37 | i2c->beginTransaction(); 38 | i2c->read(data, bytes-1, true); 39 | i2c->read(data+bytes-1, false); 40 | i2c->endTransaction(); 41 | //i2c->stop(); 42 | delete i2c; 43 | 44 | for(int i=0;i parts) { 56 | uint8_t SDA, SCL, ADDR, REG; 57 | std::string hex_byte; 58 | uint8_t bytes = atoi(parts.at("bytesCount").c_str()); 59 | uint8_t dat[1]; 60 | 61 | SDA = atoi(parts.at("sda").c_str()); 62 | SCL = atoi(parts.at("scl").c_str()); 63 | ADDR = atoi(parts.at("address").c_str()); 64 | REG = atoi(parts.at("register").c_str()); 65 | dat[0] = atoi(parts.at("data").c_str()); 66 | 67 | JsonObject obj = JSON::createObject(); 68 | JsonObject tmpObj = JSON::createObject(); 69 | 70 | printf("write to reg: %d, val: %d", REG, dat[0]); 71 | I2C* i2c = new I2C(); 72 | i2c->init(ADDR, (gpio_num_t)SDA, (gpio_num_t)SCL); 73 | 74 | i2c->beginTransaction(); 75 | i2c->write(REG); 76 | /* 77 | i2c->write(dat, bytes-1, true); 78 | i2c->write(dat[bytes-1], false);*/ 79 | i2c->write(dat[0], false); 80 | i2c->endTransaction(); 81 | delete i2c; 82 | 83 | 84 | obj.setObject("error", tmpObj); 85 | // free(dat); 86 | return obj; 87 | } 88 | -------------------------------------------------------------------------------- /main/I2C_SCAN.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * I2C_SCAN.cpp 3 | * 4 | * Created on: 18.09.2017 5 | * Author: darek 6 | */ 7 | 8 | 9 | #include "sdkconfig.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | //static const char *LOG_TAG = "I2C_SCAN"; 17 | 18 | /** 19 | * @begin Scan the I2C ports. 20 | * @return A JsonObject that describes the I2C scan. 21 | */ 22 | JsonObject I2C_SCAN_JSON() { 23 | JsonObject obj = JSON::createObject(); 24 | JsonObject tmpObj = JSON::createObject(); 25 | JsonArray tmpArr = JSON::createArray(); 26 | //tmpArr = JSON::createArray(); 27 | int i; 28 | printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); 29 | printf("00: "); 30 | 31 | I2C i2c; 32 | // i2c.init(0); 33 | 34 | for (i=3; i<0x78; i++) { // Loop over each of the possible I2C addresses. 35 | bool slavePresent = i2c.slavePresent(i); 36 | 37 | if (i%16 == 0) { 38 | std::stringstream ss; 39 | ss << "address " << std::hex << (i-16); 40 | obj.setObject(ss.str(), tmpObj); 41 | tmpObj = JSON::createObject(); 42 | printf("\n%.2x:", i); 43 | } 44 | std::stringstream ss; 45 | ss << "address " << std::hex << i; 46 | if (slavePresent) { 47 | tmpObj.setBoolean(ss.str(), true); 48 | tmpArr.addBoolean(true); 49 | printf(" %.2x", i); 50 | } else { 51 | tmpObj.setBoolean(ss.str(), false); 52 | tmpArr.addBoolean(false); 53 | printf(" --"); 54 | } 55 | } // End for each of the I2C addresses. 56 | printf("\n"); 57 | obj.setObject("70", tmpObj); 58 | obj.setArray("present", tmpArr); 59 | //obj.setObject("I2C", tmpObj); 60 | return obj; 61 | } // I2C_SCAN_JSON 62 | -------------------------------------------------------------------------------- /main/SYSTEM_JSON.cpp: -------------------------------------------------------------------------------- 1 | #include "sdkconfig.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | const static char LOG_TAG[] = "SYSTEM_JSON"; 17 | /** 18 | * @brief Obtain a JSON object describing a partition. 19 | * 20 | * { 21 | * "type": 22 | * "subType": 23 | * "size": 24 | * "address": 25 | * "encrypted": 26 | * "label": 27 | * } 28 | */ 29 | static JsonObject fromPartition(esp_partition_t *pPartition) { 30 | JsonObject obj = JSON::createObject(); 31 | obj.setInt("type", pPartition->type); // type 32 | obj.setInt("subType", pPartition->subtype); // subType 33 | obj.setInt("size", pPartition->size); // size 34 | obj.setInt("address", pPartition->address); // address 35 | obj.setBoolean("encrypted", pPartition->encrypted); // encrypted 36 | obj.setString("label", std::string(pPartition->label)); // label 37 | return obj; 38 | } // fromPartition 39 | 40 | 41 | /** 42 | * @brief Create a JSON object from a TaskStatus_t. 43 | * 44 | * { 45 | * "name": 46 | * "stackHighWater": 47 | * "priority": 48 | * "taskNumber": 49 | * "state": 50 | * } 51 | * @param [in] pTaskStatus The task status to turn into a JSON object. 52 | * @return A JSON object from a TaskStatus_t. 53 | */ 54 | static JsonObject fromTaskStatus(TaskStatus_t *pTaskStatus) { 55 | JsonObject obj = JSON::createObject(); 56 | obj.setString("name", pTaskStatus->pcTaskName); // name 57 | obj.setInt("stackHighWater", pTaskStatus->usStackHighWaterMark); // stackHighWater 58 | obj.setInt("priority", pTaskStatus->uxCurrentPriority); // priority 59 | obj.setInt("taskNumber", pTaskStatus->xTaskNumber); // taskNumber 60 | std::string state = ""; 61 | switch(pTaskStatus->eCurrentState) { 62 | case eReady: { 63 | state = "Ready"; 64 | break; 65 | } 66 | case eRunning: { 67 | state = "Running"; 68 | break; 69 | } 70 | case eBlocked: { 71 | state = "Blocked"; 72 | break; 73 | } 74 | case eSuspended: { 75 | state = "Suspended"; 76 | break; 77 | } 78 | case eDeleted: { 79 | state = "Deleted"; 80 | break; 81 | } 82 | } 83 | obj.setString("state", state); // state 84 | return obj; 85 | } // fromTaskStatus 86 | 87 | 88 | /** 89 | * @brief Create the JSON object to return to the caller that provides us information 90 | * about the system as a whole. 91 | * 92 | * The returned object contains: 93 | * { 94 | * "model": // ESP32 model number 95 | * "cores": // Number of ESP32 cores 96 | * "revision": // ESP32 revision 97 | * "hasEmbeddedFlash": 98 | * "hasWiFi": // Is WiFi present? 99 | * "hasBLE": // Is BLE present? 100 | * "hasBT": // Is BT classic present? 101 | * "espVersion": // Version of ESP-IDF 102 | * "freeHeap": // Amount of heap free 103 | * "time": // Time since boot 104 | * "taskCount": // Number of FreeRTOS tasks 105 | * "partitions": // Partitions structure 106 | * [ 107 | * { 108 | * "type": 109 | * "subType": 110 | * "size": 111 | * "address": 112 | * "encrypted": 113 | * "label": 114 | * }, 115 | * ... 116 | * ] 117 | * "taskStatus": [ 118 | * { 119 | * "name": 120 | * "stackHighWater": 121 | * "priority": 122 | * "taskNumber": 123 | * "state": 124 | * }, 125 | * ... 126 | * ] 127 | * } 128 | * 129 | * @return A JSON Object describing the data. 130 | */ 131 | JsonObject SYSTEM_JSON() { 132 | JsonObject obj = JSON::createObject(); 133 | esp_chip_info_t chipInfo; 134 | esp_chip_info(&chipInfo); 135 | obj.setInt("model", chipInfo.model); 136 | obj.setInt("cores", chipInfo.cores); 137 | obj.setInt("revision", chipInfo.revision); 138 | obj.setBoolean("hasEmbeddedFlash", chipInfo.features & CHIP_FEATURE_EMB_FLASH); 139 | obj.setBoolean("hasWifi", chipInfo.features & CHIP_FEATURE_WIFI_BGN); 140 | obj.setBoolean("hasBLE", chipInfo.features & CHIP_FEATURE_BLE); 141 | obj.setBoolean("hasBT", chipInfo.features & CHIP_FEATURE_BT); 142 | obj.setString("espVersion", System::getIDFVersion()); 143 | obj.setInt("freeHeap", System::getFreeHeapSize()); 144 | //obj.setInt("minimumFreeHeap", System::getMinimumFreeHeapSize()); 145 | struct timeval tv; 146 | gettimeofday(&tv, nullptr); 147 | obj.setDouble("time", tv.tv_sec + tv.tv_usec / 1000000.0); 148 | int taskCount = uxTaskGetNumberOfTasks(); 149 | obj.setInt("taskCount", taskCount); 150 | 151 | #if( configUSE_TRACE_FACILITY == 1 ) 152 | TaskStatus_t *pTaskStatusArray = new TaskStatus_t[taskCount]; 153 | assert(pTaskStatusArray != nullptr); 154 | taskCount = ::uxTaskGetSystemState(pTaskStatusArray, taskCount, nullptr); 155 | std::sort(pTaskStatusArray, pTaskStatusArray+taskCount, [](const TaskStatus_t& a, const TaskStatus_t& b) { 156 | return strcasecmp(a.pcTaskName, b.pcTaskName) < 0; 157 | }); 158 | 159 | JsonArray arr2 = JSON::createArray(); 160 | for (int i=0; i 2 | #include 3 | #include 4 | #include 5 | 6 | JsonObject WIFI_JSON() { 7 | JsonObject obj = JSON::createObject(); 8 | obj.setString("mode", WiFi::getMode()); 9 | obj.setString("staMac", WiFi::getStaMac()); 10 | obj.setString("apMac", WiFi::getApMac()); 11 | obj.setString("staSSID", WiFi::getStaSSID()); 12 | obj.setString("apSSID", WiFi::getApSSID()); 13 | 14 | JsonObject apIpInfo = JSON::createObject(); 15 | tcpip_adapter_ip_info_t ipInfo = WiFi::getApIpInfo(); 16 | apIpInfo.setString("ip", GeneralUtils::ipToString((uint8_t *)&(ipInfo.ip))); 17 | apIpInfo.setString("gw", GeneralUtils::ipToString((uint8_t *)&(ipInfo.gw))); 18 | apIpInfo.setString("netmask", GeneralUtils::ipToString((uint8_t *)&(ipInfo.netmask))); 19 | obj.setObject("apIpInfo", apIpInfo); 20 | 21 | JsonObject staIpInfo = JSON::createObject(); 22 | ipInfo = WiFi::getStaIpInfo(); 23 | staIpInfo.setString("ip", GeneralUtils::ipToString((uint8_t *)&(ipInfo.ip))); 24 | staIpInfo.setString("gw", GeneralUtils::ipToString((uint8_t *)&(ipInfo.gw))); 25 | staIpInfo.setString("netmask", GeneralUtils::ipToString((uint8_t *)&(ipInfo.netmask))); 26 | obj.setObject("staIpInfo", staIpInfo); 27 | return obj; 28 | } // WIFI_JSON 29 | -------------------------------------------------------------------------------- /main/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * common.h 3 | * 4 | * Created on: Nov 16, 2017 5 | * Author: esp32 6 | */ 7 | 8 | #ifndef MAIN_COMMON_H_ 9 | #define MAIN_COMMON_H_ 10 | 11 | #include "WS2812.h" 12 | 13 | extern WS2812* strip1; 14 | 15 | 16 | 17 | 18 | #endif /* MAIN_COMMON_H_ */ 19 | -------------------------------------------------------------------------------- /main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main component makefile. 3 | # 4 | # This Makefile can be left empty. By default, it will take the sources in the 5 | # src/ directory, compile them and link them into lib(subdirectory_name).a 6 | # in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | -------------------------------------------------------------------------------- /main/main.cpp: -------------------------------------------------------------------------------- 1 | #include "Memory.h" 2 | #include "sdkconfig.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "ESP32Explorer.h" 14 | #include "bt.h" 15 | #include "BootWiFi.h" 16 | 17 | //#define BOOTWIFI 18 | 19 | #ifndef BOOTWIFI 20 | //static const char WIFI_SSID[] = "sweetie"; 21 | //static const char WIFI_PASSWORD[] = "l16wint!"; 22 | static const char *WIFI_SSID = "Orange-8F54"; 23 | static const char *WIFI_PASSWORD = "33413006"; 24 | #endif 25 | 26 | extern "C" { 27 | int app_main(void); 28 | } 29 | 30 | //static const char* LOG_TAG = "ESP32_Explorer_MAIN"; // Logging tag 31 | 32 | 33 | class ESP32_ExplorerTask: public Task { 34 | void run(void* data) override { 35 | ESP32_Explorer* pESP32_Explorer = new ESP32_Explorer(); 36 | pESP32_Explorer->start(); 37 | } 38 | }; // ESP32_ExplorerTask 39 | 40 | 41 | /** 42 | * @brief Wifi management task. 43 | */ 44 | class WiFiTask: public Task { 45 | void run(void *data) override { 46 | #ifdef BOOTWIFI 47 | BootWiFi boot = BootWiFi(); 48 | boot.boot(); 49 | #else 50 | WiFi *pWifi = new WiFi(); // Can't delete at the end of the task. 51 | pWifi->setIPInfo("192.168.1.99", "192.168.1.1", "255.255.255.0"); 52 | pWifi->connectAP(WIFI_SSID, WIFI_PASSWORD); 53 | #endif 54 | ESP32_ExplorerTask *pESP32_ExplorerTask = new ESP32_ExplorerTask(); 55 | pESP32_ExplorerTask->setStackSize(6000); 56 | pESP32_ExplorerTask->start(); 57 | } // End run 58 | }; // WiFiTask 59 | 60 | 61 | void task_webserver(void* ignore) { 62 | WiFiTask* pMyTask = new WiFiTask(); 63 | pMyTask->setStackSize(6000); 64 | pMyTask->start(); 65 | FreeRTOS::deleteTask(); 66 | } // task_webserver 67 | 68 | 69 | 70 | /** 71 | * @brief Main entry point. 72 | */ 73 | int app_main(void) { 74 | //Memory::init(300); 75 | esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); //FIXME waiting for response from esp-idf issue 76 | task_webserver(nullptr); 77 | return 0; 78 | } // app_main 79 | -------------------------------------------------------------------------------- /main/selectAP.h: -------------------------------------------------------------------------------- 1 | unsigned char selectAP_html[] = { 2 | 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20, 0x68, 0x74, 3 | 0x6d, 0x6c, 0x3e, 0x0a, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0x0a, 0x3c, 4 | 0x68, 0x65, 0x61, 0x64, 0x3e, 0x0a, 0x3c, 0x6d, 0x65, 0x74, 0x61, 0x20, 5 | 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x55, 0x54, 0x46, 6 | 0x2d, 0x38, 0x22, 0x3e, 0x0a, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 7 | 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x20, 0x57, 0x69, 0x46, 0x69, 0x3c, 8 | 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x0a, 0x3c, 0x2f, 0x68, 0x65, 9 | 0x61, 0x64, 0x3e, 0x0a, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x0a, 0x3c, 10 | 0x21, 0x2d, 0x2d, 0x20, 0x53, 0x74, 0x61, 0x72, 0x74, 0x20, 0x2d, 0x2d, 11 | 0x3e, 0x0a, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 12 | 0x3d, 0x22, 0x7a, 0x6f, 0x6f, 0x6d, 0x3a, 0x20, 0x33, 0x35, 0x30, 0x25, 13 | 0x3b, 0x22, 0x3e, 0x0a, 0x3c, 0x68, 0x31, 0x3e, 0x53, 0x65, 0x6c, 0x65, 14 | 0x63, 0x74, 0x20, 0x57, 0x69, 0x46, 0x69, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 15 | 0x0a, 0x3c, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x61, 0x63, 0x74, 0x69, 0x6f, 16 | 0x6e, 0x3d, 0x22, 0x73, 0x73, 0x69, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 17 | 0x74, 0x65, 0x64, 0x22, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x3d, 18 | 0x22, 0x70, 0x6f, 0x73, 0x74, 0x22, 0x3e, 0x0a, 0x3c, 0x74, 0x61, 0x62, 19 | 0x6c, 0x65, 0x3e, 0x0a, 0x3c, 0x74, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x0a, 20 | 0x3c, 0x74, 0x72, 0x3e, 0x0a, 0x3c, 0x74, 0x64, 0x3e, 0x53, 0x53, 0x49, 21 | 0x44, 0x3a, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 0x3c, 0x74, 0x64, 0x3e, 22 | 0x3c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, 23 | 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x63, 24 | 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x6f, 0x66, 0x66, 0x22, 25 | 0x20, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x61, 0x70, 0x69, 0x74, 0x61, 0x6c, 26 | 0x69, 0x7a, 0x65, 0x3d, 0x22, 0x6e, 0x6f, 0x6e, 0x65, 0x22, 0x20, 0x6e, 27 | 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x73, 0x73, 0x69, 0x64, 0x22, 0x20, 0x2f, 28 | 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 29 | 0x0a, 0x3c, 0x74, 0x72, 0x3e, 0x0a, 0x3c, 0x74, 0x64, 0x3e, 0x50, 0x61, 30 | 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x3a, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 31 | 0x0a, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 32 | 0x74, 0x79, 0x70, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, 0x20, 33 | 0x61, 0x75, 0x74, 0x6f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x3d, 34 | 0x22, 0x6f, 0x66, 0x66, 0x22, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x61, 35 | 0x70, 0x69, 0x74, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x3d, 0x22, 0x6e, 0x6f, 36 | 0x6e, 0x65, 0x22, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x70, 0x61, 37 | 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x20, 0x2f, 0x3e, 0x3c, 0x2f, 38 | 0x74, 0x64, 0x3e, 0x0a, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x3c, 0x74, 39 | 0x72, 0x3e, 0x0a, 0x3c, 0x74, 0x64, 0x3e, 0x49, 0x50, 0x20, 0x61, 0x64, 40 | 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 41 | 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, 42 | 0x79, 0x70, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, 0x20, 0x61, 43 | 0x75, 0x74, 0x6f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 44 | 0x6f, 0x66, 0x66, 0x22, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x61, 0x70, 45 | 0x69, 0x74, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x3d, 0x22, 0x6e, 0x6f, 0x6e, 46 | 0x65, 0x22, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x69, 0x70, 0x22, 47 | 0x20, 0x2f, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 0x3c, 0x2f, 0x74, 48 | 0x72, 0x3e, 0x0a, 0x3c, 0x74, 0x72, 0x3e, 0x0a, 0x3c, 0x74, 0x64, 0x3e, 49 | 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x20, 0x61, 0x64, 0x64, 0x72, 50 | 0x65, 0x73, 0x73, 0x3a, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 0x3c, 0x74, 51 | 0x64, 0x3e, 0x3c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, 0x79, 0x70, 52 | 0x65, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, 0x20, 0x61, 0x75, 0x74, 53 | 0x6f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 0x6f, 0x66, 54 | 0x66, 0x22, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x61, 0x70, 0x69, 0x74, 55 | 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x3d, 0x22, 0x6e, 0x6f, 0x6e, 0x65, 0x22, 56 | 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x67, 0x77, 0x22, 0x20, 0x2f, 57 | 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 58 | 0x0a, 0x3c, 0x74, 0x72, 0x3e, 0x0a, 0x3c, 0x74, 0x64, 0x3e, 0x4e, 0x65, 59 | 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x3a, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 60 | 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, 61 | 0x79, 0x70, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, 0x20, 0x61, 62 | 0x75, 0x74, 0x6f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x3d, 0x22, 63 | 0x6f, 0x66, 0x66, 0x22, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x61, 0x70, 64 | 0x69, 0x74, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x3d, 0x22, 0x6e, 0x6f, 0x6e, 65 | 0x65, 0x22, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x6e, 0x65, 0x74, 66 | 0x6d, 0x61, 0x73, 0x6b, 0x22, 0x20, 0x2f, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 67 | 0x3e, 0x0a, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x3c, 0x2f, 0x74, 0x62, 68 | 0x6f, 0x64, 0x79, 0x3e, 0x0a, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 69 | 0x3e, 0x0a, 0x20, 0x3c, 0x70, 0x3e, 0x0a, 0x3c, 0x69, 0x6e, 0x70, 0x75, 70 | 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, 0x22, 0x73, 0x75, 0x62, 0x6d, 71 | 0x69, 0x74, 0x22, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3d, 0x22, 0x53, 72 | 0x75, 0x62, 0x6d, 0x69, 0x74, 0x22, 0x3e, 0x0a, 0x3c, 0x2f, 0x70, 0x3e, 73 | 0x0a, 0x3c, 0x2f, 0x66, 0x6f, 0x72, 0x6d, 0x3e, 0x0a, 0x3c, 0x64, 0x69, 74 | 0x76, 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d, 0x22, 0x6d, 0x61, 0x72, 75 | 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x36, 0x70, 0x78, 0x3b, 0x22, 0x3e, 0x0a, 76 | 0x54, 0x68, 0x65, 0x20, 0x49, 0x50, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 77 | 0x73, 0x73, 0x2c, 0x20, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x20, 78 | 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 79 | 0x6e, 0x65, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x20, 0x61, 0x72, 0x65, 0x20, 80 | 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2e, 0x20, 0x20, 0x49, 81 | 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 82 | 0x65, 0x64, 0x0a, 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, 0x76, 0x61, 0x6c, 83 | 0x75, 0x65, 0x73, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 84 | 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 85 | 0x65, 0x20, 0x57, 0x69, 0x46, 0x69, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 86 | 0x73, 0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2e, 0x0a, 0x3c, 0x2f, 0x64, 87 | 0x69, 0x76, 0x3e, 0x0a, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0a, 0x3c, 88 | 0x21, 0x2d, 0x2d, 0x20, 0x45, 0x6e, 0x64, 0x20, 0x2d, 0x2d, 0x3e, 0x0a, 89 | 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x0a, 0x3c, 0x2f, 0x68, 0x74, 90 | 0x6d, 0x6c, 0x3e 91 | }; 92 | unsigned int selectAP_html_len = 1059; 93 | -------------------------------------------------------------------------------- /partitions.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild 3 | nvs, data, nvs, 0x9000, 0x6000, 4 | phy_init, data, phy, 0xf000, 0x1000, 5 | factory, app, factory, 0x10000, 2M, 6 | storage, data, fat, 0x300000, 1M, 7 | --------------------------------------------------------------------------------