├── .cproject ├── .gitignore ├── .project ├── .settings └── language.settings.xml ├── Compiling.md ├── LICENSE ├── Makefile ├── distri └── README.txt ├── include ├── i2s_register.h ├── pin_mux_register.h ├── sdkfixup.h ├── slc_register.h ├── slc_slv.h ├── spi_register.h └── user_config.h ├── static-rename-sections.txt └── user ├── CTimer.cpp ├── CTimer.h ├── config ├── CConfigHtmlGenerator.cpp ├── CConfigHtmlGenerator.h ├── CConfigLoader.cpp ├── CConfigLoader.h ├── CConfigPostHandler.cpp ├── CConfigPostHandler.h ├── CConfigReader.cpp ├── CConfigReader.h ├── CConfigSection.cpp ├── CConfigSection.h ├── CConfigWriter.cpp ├── CConfigWriter.h ├── IConfigObject.h ├── IConfigRunner.cpp ├── IConfigRunner.h ├── config.cpp ├── config.h └── format.h ├── cppcompat.cpp ├── debug ├── CDebugServer.cpp └── CDebugServer.h ├── helpers.cpp ├── helpers.h ├── httpd ├── CHttpRequest.cpp ├── CHttpRequest.h ├── CHttpServer.cpp ├── CHttpServer.h ├── CTcpServer.cpp ├── CTcpServer.h ├── CTcpSocket.cpp └── CTcpSocket.h ├── input_protocols ├── artnet.cpp ├── artnet.h ├── tpm2net.cpp └── tpm2net.h ├── main.cpp ├── output_protocols ├── C3WireEncoder.cpp ├── C3WireEncoder.h ├── C3WireOutput.cpp ├── C3WireOutput.h ├── CColorCorrector.cpp ├── CColorCorrector.h ├── CLimiter.cpp ├── CLimiter.h ├── COutput.cpp ├── COutput.h ├── CSPIBitbang.cpp ├── CSPIBitbang.h ├── CSPIHardware.cpp ├── CSPIHardware.h ├── CWS2801Output.cpp ├── CWS2801Output.h ├── ISPIInterface.cpp ├── ISPIInterface.h ├── output.cpp └── output.h ├── wifisetup.cpp └── wifisetup.h /.cproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | user/user_config.h 2 | /Debug/ 3 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | EspLightNode 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.managedbuilder.core.managedBuildNature 24 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 25 | 26 | 27 | -------------------------------------------------------------------------------- /.settings/language.settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Compiling.md: -------------------------------------------------------------------------------- 1 | EspLightNode compilation guide 2 | ============================== 3 | Prerequisites 4 | ------------- 5 | To compile EspLightNode, you need: 6 | - G++ and friends for XTensa106-elf architecture 7 | - newlib compiled with -mlongcalls 8 | - Libstdc++ compiled with -mlongcalls 9 | - GNU tools (grep, awk, make, print) 10 | - esptool.py (https://github.com/themadinventor/esptool) 11 | 12 | Recommended setup 13 | ----------------- 14 | Most testing and compilation was done on ArchLinux, using the XTensa packages from: 15 | https://github.com/Frans-Willem/arch-esp8266-packages/ 16 | And the esptool.py package from: 17 | https://aur.archlinux.org/packages/esptool-git/ 18 | 19 | Compiling 20 | --------- 21 | Just typing 'make' is usually enough. 22 | 'make flash' will compile and immediately try to flash to the device 23 | 'make clearconfig' will compile, flash, and erase any previous configuration on the device. 24 | 'make release' will make a release .zip file in the release directory. 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | 676 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SDK:=/home/frans-willem/esp8266/SDK/esp_iot_sdk_v1.3.0 2 | PORT:=/dev/ttyUSB0 3 | 4 | OBJ_DIR:=objs 5 | SRC_DIR:=user 6 | OUTPUT_DIR:=firmware 7 | RELEASE_DIR:=release 8 | 9 | 10 | # Object files 11 | OBJS:= cppcompat main wifisetup \ 12 | CTimer \ 13 | output_protocols/output output_protocols/COutput \ 14 | output_protocols/ISPIInterface \ 15 | output_protocols/CSPIBitbang \ 16 | output_protocols/CSPIHardware \ 17 | output_protocols/CWS2801Output \ 18 | output_protocols/C3WireOutput \ 19 | output_protocols/C3WireEncoder \ 20 | output_protocols/CColorCorrector \ 21 | output_protocols/CLimiter \ 22 | input_protocols/tpm2net \ 23 | input_protocols/artnet \ 24 | config/config config/IConfigRunner config/CConfigHtmlGenerator config/CConfigPostHandler \ 25 | config/CConfigWriter config/CConfigReader config/CConfigSection config/CConfigLoader \ 26 | httpd/CTcpServer httpd/CTcpSocket \ 27 | httpd/CHttpServer httpd/CHttpRequest \ 28 | debug/CDebugServer \ 29 | helpers 30 | 31 | 32 | # Tool paths 33 | TOOLCHAIN_PREFIX:=xtensa-lx106-elf- 34 | CC:=$(TOOLCHAIN_PREFIX)gcc 35 | CXX:=$(TOOLCHAIN_PREFIX)g++ 36 | LD:=$(TOOLCHAIN_PREFIX)ld 37 | OBJDUMP:=$(TOOLCHAIN_PREFIX)objdump 38 | OBJCOPY:=$(TOOLCHAIN_PREFIX)objcopy 39 | STRIP:=$(TOOLCHAIN_PREFIX)strip 40 | ESPTOOL:=esptool.py 41 | 42 | # EspTool information, symbols needed, and firmware offsets generated 43 | KEEPSYMS:=_text_start _data_start _rodata_start _irom0_text_start 44 | FW_OFFSETS:=0x00000 0x40000 45 | 46 | DEFINES:=-DENABLE_TPM2NET -DENABLE_ARTNET -DENABLE_WS2812 47 | CXXFLAGS:=-Os -ggdb -std=c++0x -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \ 48 | -nostdlib -mlongcalls -mtext-section-literals -Wno-address \ 49 | -I./include/ -I./$(SRC_DIR) -I$(SDK)/include \ 50 | -fno-exceptions -fno-rtti -fno-inline-functions \ 51 | -fdata-sections -ffunction-sections 52 | CXXLDFLAGS:= -nostdlib -Wl,--no-check-sections \ 53 | -Wl,-EL -Wl,-relocatable -Wl,--gc-sections \ 54 | --entry user_init 55 | 56 | # Library directories 57 | LIBDIRS:=$(SDK)/lib 58 | # Libraries that should be moved to the bigger flash section 59 | LIBS_FIXUP:= stdc++ m 60 | # Libraries that should stay at the smaller flash section 61 | # Double libraries could keep some parts in big flash, and some parts on smaller flash. 62 | LIBS_NOFIXUP:= c gcc main phy pp net80211 wpa lwip 63 | # Linker script, adjust if you want to target a bigger flash chip 64 | LDSCRIPT:=$(SDK)/ld/eagle.app.v6.ld 65 | 66 | all: $(FW_OFFSETS:%=$(OUTPUT_DIR)/%.bin) 67 | 68 | # Compilation of cpp files to .o files (object, compiled) and .d (dependency, used by Makefile) 69 | -include $(OBJS:%=$(OBJ_DIR)/%.d) 70 | $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp 71 | mkdir -p $(dir $@) 72 | $(CXX) $(CXXFLAGS) -MM $< -MT $@ > $(@:%.o=%.d) 73 | $(CXX) $(CXXFLAGS) -c $< -o $@ 74 | 75 | # Stage 1 linking 76 | # Everything that should be moved to the big flash area should be linked in at this point. 77 | # Furthermore --gc-sections throws away all unreferenced sections 78 | # And -fdata-sections and -ffunction-sections will make sure each function is in a seperate section. 79 | # Ideally libc, libgcc, and libstdc++ should be compiled with those flags too for the biggest space savings. 80 | $(OBJ_DIR)/firmware_stage1.elf: $(OBJS:%=$(OBJ_DIR)/%.o) $(OBJSXX:%=$(OBJ_DIR)/%.o) 81 | $(CXX) -o $@ $(CXXLDFLAGS) $(addprefix -L,$LIBDIRS) -Wl,--start-group $^ $(addprefix -l,$(LIBS_FIXUP)) -Wl,--end-group 82 | 83 | # Find all sections starting with .text (either .text, or a function-specific section starting with .text) 84 | $(OBJ_DIR)/function-sections.txt: $(OBJ_DIR)/firmware_stage1.elf 85 | $(OBJDUMP) -h $^ | grep "^\W*[[:digit:]]\+\W\+\.text" | awk '{print $$2}' > $@ 86 | 87 | # Same as above, for literals 88 | $(OBJ_DIR)/literal-sections.txt: $(OBJ_DIR)/firmware_stage1.elf 89 | $(OBJDUMP) -h $^ | grep "^\W*[[:digit:]]\+\W\+\.literal" | awk '{print $$2}' > $@ 90 | 91 | # Create a list of all sections that should be renamed to .irom0.text (the big flash section) 92 | $(OBJ_DIR)/rename-sections.txt: $(OBJ_DIR)/function-sections.txt $(OBJ_DIR)/literal-sections.txt 93 | cat $^ | awk '{print "--rename-section " $$0 "=.irom0.text"}' > $@ 94 | 95 | # Apply the mass section renaming. 96 | $(OBJ_DIR)/firmware_stage2.elf: $(OBJ_DIR)/firmware_stage1.elf $(OBJ_DIR)/rename-sections.txt static-rename-sections.txt 97 | $(OBJCOPY) @$(word 2, $^) @$(word 3, $^) $< $@ 98 | 99 | # Link in the other libraries 100 | $(OBJ_DIR)/firmware_stage3.elf: $(OBJ_DIR)/firmware_stage2.elf 101 | $(CXX) -o $@ -nostdlib $(addprefix -L,$(LIBDIRS)) -Wl,--start-group $(addprefix -l,$(LIBS_NOFIXUP)) $^ -Wl,--end-group -Wl,-T$(LDSCRIPT) -Wl,--gc-sections 102 | 103 | # Strip out all symbols not used by ESPTOOL, as some undefined symbols left may confuse it. 104 | $(OBJ_DIR)/firmware_stage4.elf: $(OBJ_DIR)/firmware_stage3.elf 105 | cp $^ $@ 106 | $(STRIP) -s $(addprefix -K,$(KEEPSYMS)) $@ 107 | 108 | # Turn .elf file into .bin files ready for flashing 109 | $(FW_OFFSETS:%=$(OUTPUT_DIR)/%.bin): $(OBJ_DIR)/firmware_stage4.elf 110 | @mkdir -p $(OUTPUT_DIR) 111 | $(ESPTOOL) elf2image --output $(OUTPUT_DIR)/ $^ 112 | 113 | # Flash! 114 | flash: $(FW_OFFSETS:%=$(OUTPUT_DIR)/%.bin) 115 | $(ESPTOOL) --port $(PORT) --baud 460800 write_flash $(foreach x,$(FW_OFFSETS),$(x) $(OUTPUT_DIR)/$(x).bin) 116 | 117 | $(OUTPUT_DIR)/blank.bin: 118 | @mkdir -p $(OUTPUT_DIR) 119 | tr '\0' '\377' < /dev/zero | dd of=$@ bs=4096 count=1 120 | 121 | clearconfig: $(OUTPUT_DIR)/blank.bin $(FW_OFFSETS:%=$(OUTPUT_DIR)/%.bin) 122 | # Write all firmware, as writing just a blank sector also erases the one after it somehow. 123 | $(ESPTOOL) --port $(PORT) --baud 460800 write_flash `echo $$((63 * 4096))` $< $(foreach x,$(FW_OFFSETS),$(x) $(OUTPUT_DIR)/$(x).bin) 124 | 125 | clean: 126 | rm -rf $(OBJ_DIR) 127 | rm -rf $(OUTPUT_DIR) 128 | rm -rf $(RELEASE_DIR) 129 | 130 | .PHONY: release 131 | release: $(FW_OFFSETS:%=$(OUTPUT_DIR)/%.bin) $(OUTPUT_DIR)/blank.bin LICENSE distri/README.txt 132 | $(eval $@_TMP := $(shell mktemp -d)) 133 | $(eval $@_TARGET := EspLightNode-$(shell git describe --dirty)-$(shell date +%F).zip) 134 | mkdir $($@_TMP)/firmware 135 | mkdir $($@_TMP)/documentation 136 | cp LICENSE $($@_TMP) 137 | cp distri/README.txt $($@_TMP) 138 | cp $(FW_OFFSETS:%=$(OUTPUT_DIR)/%.bin) $($@_TMP)/firmware 139 | cp $(OUTPUT_DIR)/blank.bin $($@_TMP)/firmware 140 | git describe --dirty > $($@_TMP)/VERSION.txt 141 | @mkdir -p $(RELEASE_DIR) 142 | rm -f $(RELEASE_DIR)/$($@_TARGET) 143 | cd $($@_TMP); zip -r "$(abspath $(RELEASE_DIR))/$($@_TARGET)" . 144 | rm -r $($@_TMP) 145 | -------------------------------------------------------------------------------- /distri/README.txt: -------------------------------------------------------------------------------- 1 | EspLightNode precompiled package 2 | ================================ 3 | This is a pre-compiled version of the EspLightNode package. 4 | Source code and documentation can be found at: 5 | https://github.com/Frans-Willem/EspLightNode 6 | 7 | To flash this to your ESP8266, use esptool to flash all numbered .bin files to their appropriate location. 8 | If needed, write blank.bin to 0x3F000 to reset EspLightNode's configuration. It might be needed to also re-flash the other firmware parts after this. 9 | 10 | An example on linux would look like this. 11 | Without configuration reset: 12 | esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash 0x00000 firmware/0x00000.bin 0x40000 firmware/0x40000.bin 13 | With configuration reset: 14 | esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash 0x00000 firmware/0x00000.bin 0x3F000 firmware/blank.bin 0x40000 firmware/0x40000.bin 15 | 16 | -------------------------------------------------------------------------------- /include/i2s_register.h: -------------------------------------------------------------------------------- 1 | #ifndef I2S_REGISTER_H 2 | #define I2S_REGISTER_H 3 | #define DR_REG_I2S_BASE (0x60000e00) 4 | 5 | #define I2STXFIFO (DR_REG_I2S_BASE + 0x0000) 6 | #define I2SRXFIFO (DR_REG_I2S_BASE + 0x0004) 7 | #define I2SCONF (DR_REG_I2S_BASE + 0x0008) 8 | #define I2S_BCK_DIV_NUM 0x0000003F 9 | #define I2S_BCK_DIV_NUM_S 22 10 | #define I2S_CLKM_DIV_NUM 0x0000003F 11 | #define I2S_CLKM_DIV_NUM_S 16 12 | #define I2S_BITS_MOD 0x0000000F 13 | #define I2S_BITS_MOD_S 12 14 | #define I2S_RECE_MSB_SHIFT (BIT(11)) 15 | #define I2S_TRANS_MSB_SHIFT (BIT(10)) 16 | #define I2S_I2S_RX_START (BIT(9)) 17 | #define I2S_I2S_TX_START (BIT(8)) 18 | #define I2S_MSB_RIGHT (BIT(7)) 19 | #define I2S_RIGHT_FIRST (BIT(6)) 20 | #define I2S_RECE_SLAVE_MOD (BIT(5)) 21 | #define I2S_TRANS_SLAVE_MOD (BIT(4)) 22 | #define I2S_I2S_RX_FIFO_RESET (BIT(3)) 23 | #define I2S_I2S_TX_FIFO_RESET (BIT(2)) 24 | #define I2S_I2S_RX_RESET (BIT(1)) 25 | #define I2S_I2S_TX_RESET (BIT(0)) 26 | #define I2S_I2S_RESET_MASK 0xf 27 | 28 | #define I2SINT_RAW (DR_REG_I2S_BASE + 0x000c) 29 | #define I2S_I2S_TX_REMPTY_INT_RAW (BIT(5)) 30 | #define I2S_I2S_TX_WFULL_INT_RAW (BIT(4)) 31 | #define I2S_I2S_RX_REMPTY_INT_RAW (BIT(3)) 32 | #define I2S_I2S_RX_WFULL_INT_RAW (BIT(2)) 33 | #define I2S_I2S_TX_PUT_DATA_INT_RAW (BIT(1)) 34 | #define I2S_I2S_RX_TAKE_DATA_INT_RAW (BIT(0)) 35 | 36 | 37 | #define I2SINT_ST (DR_REG_I2S_BASE + 0x0010) 38 | #define I2S_I2S_TX_REMPTY_INT_ST (BIT(5)) 39 | #define I2S_I2S_TX_WFULL_INT_ST (BIT(4)) 40 | #define I2S_I2S_RX_REMPTY_INT_ST (BIT(3)) 41 | #define I2S_I2S_RX_WFULL_INT_ST (BIT(2)) 42 | #define I2S_I2S_TX_PUT_DATA_INT_ST (BIT(1)) 43 | #define I2S_I2S_RX_TAKE_DATA_INT_ST (BIT(0)) 44 | 45 | #define I2SINT_ENA (DR_REG_I2S_BASE + 0x0014) 46 | #define I2S_I2S_TX_REMPTY_INT_ENA (BIT(5)) 47 | #define I2S_I2S_TX_WFULL_INT_ENA (BIT(4)) 48 | #define I2S_I2S_RX_REMPTY_INT_ENA (BIT(3)) 49 | #define I2S_I2S_RX_WFULL_INT_ENA (BIT(2)) 50 | #define I2S_I2S_TX_PUT_DATA_INT_ENA (BIT(1)) 51 | #define I2S_I2S_RX_TAKE_DATA_INT_ENA (BIT(0)) 52 | 53 | #define I2SINT_CLR (DR_REG_I2S_BASE + 0x0018) 54 | #define I2S_I2S_TX_REMPTY_INT_CLR (BIT(5)) 55 | #define I2S_I2S_TX_WFULL_INT_CLR (BIT(4)) 56 | #define I2S_I2S_RX_REMPTY_INT_CLR (BIT(3)) 57 | #define I2S_I2S_RX_WFULL_INT_CLR (BIT(2)) 58 | #define I2S_I2S_PUT_DATA_INT_CLR (BIT(1)) 59 | #define I2S_I2S_TAKE_DATA_INT_CLR (BIT(0)) 60 | 61 | #define I2STIMING (DR_REG_I2S_BASE + 0x001c) 62 | #define I2S_TRANS_BCK_IN_INV (BIT(22)) 63 | #define I2S_RECE_DSYNC_SW (BIT(21)) 64 | #define I2S_TRANS_DSYNC_SW (BIT(20)) 65 | #define I2S_RECE_BCK_OUT_DELAY 0x00000003 66 | #define I2S_RECE_BCK_OUT_DELAY_S 18 67 | #define I2S_RECE_WS_OUT_DELAY 0x00000003 68 | #define I2S_RECE_WS_OUT_DELAY_S 16 69 | #define I2S_TRANS_SD_OUT_DELAY 0x00000003 70 | #define I2S_TRANS_SD_OUT_DELAY_S 14 71 | #define I2S_TRANS_WS_OUT_DELAY 0x00000003 72 | #define I2S_TRANS_WS_OUT_DELAY_S 12 73 | #define I2S_TRANS_BCK_OUT_DELAY 0x00000003 74 | #define I2S_TRANS_BCK_OUT_DELAY_S 10 75 | #define I2S_RECE_SD_IN_DELAY 0x00000003 76 | #define I2S_RECE_SD_IN_DELAY_S 8 77 | #define I2S_RECE_WS_IN_DELAY 0x00000003 78 | #define I2S_RECE_WS_IN_DELAY_S 6 79 | #define I2S_RECE_BCK_IN_DELAY 0x00000003 80 | #define I2S_RECE_BCK_IN_DELAY_S 4 81 | #define I2S_TRANS_WS_IN_DELAY 0x00000003 82 | #define I2S_TRANS_WS_IN_DELAY_S 2 83 | #define I2S_TRANS_BCK_IN_DELAY 0x00000003 84 | #define I2S_TRANS_BCK_IN_DELAY_S 0 85 | 86 | #define I2S_FIFO_CONF (DR_REG_I2S_BASE + 0x0020) 87 | #define I2S_I2S_RX_FIFO_MOD 0x00000007 88 | #define I2S_I2S_RX_FIFO_MOD_S 16 89 | #define I2S_I2S_TX_FIFO_MOD 0x00000007 90 | #define I2S_I2S_TX_FIFO_MOD_S 13 91 | #define I2S_I2S_DSCR_EN (BIT(12)) 92 | #define I2S_I2S_TX_DATA_NUM 0x0000003F 93 | #define I2S_I2S_TX_DATA_NUM_S 6 94 | #define I2S_I2S_RX_DATA_NUM 0x0000003F 95 | #define I2S_I2S_RX_DATA_NUM_S 0 96 | 97 | 98 | #define I2SRXEOF_NUM (DR_REG_I2S_BASE + 0x0024) 99 | #define I2S_I2S_RX_EOF_NUM 0xFFFFFFFF 100 | #define I2S_I2S_RX_EOF_NUM_S 0 101 | 102 | #define I2SCONF_SIGLE_DATA (DR_REG_I2S_BASE + 0x0028) 103 | #define I2S_I2S_SIGLE_DATA 0xFFFFFFFF 104 | #define I2S_I2S_SIGLE_DATA_S 0 105 | 106 | #define I2SCONF_CHAN (DR_REG_I2S_BASE + 0x002c) 107 | #define I2S_RX_CHAN_MOD 0x00000003 108 | #define I2S_RX_CHAN_MOD_S 3 109 | #define I2S_TX_CHAN_MOD 0x00000007 110 | #define I2S_TX_CHAN_MOD_S 0 111 | #endif//I2S_REGISTER_H 112 | 113 | -------------------------------------------------------------------------------- /include/pin_mux_register.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Espressif System 2010 - 2012 3 | * 4 | */ 5 | 6 | #ifndef _PIN_MUX_H_ 7 | #define _PIN_MUX_H_ 8 | 9 | #define PERIPHS_IO_MUX 0x60000800 10 | 11 | #define PERIPHS_IO_MUX_FUNC 0x13 12 | #define PERIPHS_IO_MUX_FUNC_S 4 13 | #define PERIPHS_IO_MUX_PULLUP BIT7 14 | #define PERIPHS_IO_MUX_PULLDWN BIT6 15 | #define PERIPHS_IO_MUX_SLEEP_PULLUP BIT3 16 | #define PERIPHS_IO_MUX_SLEEP_PULLDWN BIT2 17 | #define PERIPHS_IO_MUX_SLEEP_OE BIT1 18 | #define PERIPHS_IO_MUX_OE BIT0 19 | 20 | #define PERIPHS_IO_MUX_CONF_U (PERIPHS_IO_MUX + 0x00) 21 | #define SPI0_CLK_EQU_SYS_CLK BIT8 22 | #define SPI1_CLK_EQU_SYS_CLK BIT9 23 | 24 | #define PERIPHS_IO_MUX_MTDI_U (PERIPHS_IO_MUX + 0x04) 25 | #define FUNC_MTDI 0 26 | #define FUNC_I2SI_DATA 1 27 | #define FUNC_HSPIQ_MISO 2 28 | #define FUNC_GPIO12 3 29 | #define FUNC_UART0_DTR 4 30 | 31 | #define PERIPHS_IO_MUX_MTCK_U (PERIPHS_IO_MUX + 0x08) 32 | #define FUNC_MTCK 0 33 | #define FUNC_I2SI_BCK 1 34 | #define FUNC_HSPID_MOSI 2 35 | #define FUNC_GPIO13 3 36 | #define FUNC_UART0_CTS 4 37 | 38 | #define PERIPHS_IO_MUX_MTMS_U (PERIPHS_IO_MUX + 0x0C) 39 | #define FUNC_MTMS 0 40 | #define FUNC_I2SI_WS 1 41 | #define FUNC_HSPI_CLK 2 42 | #define FUNC_GPIO14 3 43 | #define FUNC_UART0_DSR 4 44 | 45 | #define PERIPHS_IO_MUX_MTDO_U (PERIPHS_IO_MUX + 0x10) 46 | #define FUNC_MTDO 0 47 | #define FUNC_I2SO_BCK 1 48 | #define FUNC_HSPI_CS0 2 49 | #define FUNC_GPIO15 3 50 | #define FUNC_U0RTS 4 51 | #define FUNC_UART0_RTS 4 52 | 53 | #define PERIPHS_IO_MUX_U0RXD_U (PERIPHS_IO_MUX + 0x14) 54 | #define FUNC_U0RXD 0 55 | #define FUNC_I2SO_DATA 1 56 | #define FUNC_GPIO3 3 57 | #define FUNC_CLK_XTAL_BK 4 58 | 59 | #define PERIPHS_IO_MUX_U0TXD_U (PERIPHS_IO_MUX + 0x18) 60 | #define FUNC_U0TXD 0 61 | #define FUNC_SPICS1 1 62 | #define FUNC_GPIO1 3 63 | #define FUNC_CLK_RTC_BK 4 64 | 65 | #define PERIPHS_IO_MUX_SD_CLK_U (PERIPHS_IO_MUX + 0x1c) 66 | #define FUNC_SDCLK 0 67 | #define FUNC_SPICLK 1 68 | #define FUNC_GPIO6 3 69 | #define UART1_CTS 4 70 | 71 | #define PERIPHS_IO_MUX_SD_DATA0_U (PERIPHS_IO_MUX + 0x20) 72 | #define FUNC_SDDATA0 0 73 | #define FUNC_SPIQ_MISO 1 74 | #define FUNC_GPIO7 3 75 | #define FUNC_U1TXD 4 76 | #define FUNC_UART1_TXD 4 77 | 78 | #define PERIPHS_IO_MUX_SD_DATA1_U (PERIPHS_IO_MUX + 0x24) 79 | #define FUNC_SDDATA1 0 80 | #define FUNC_SPID_MOSI 1 81 | #define FUNC_GPIO8 3 82 | #define FUNC_U1RXD 4 83 | #define FUNC_UART1_RXD 4 84 | 85 | #define PERIPHS_IO_MUX_SD_DATA2_U (PERIPHS_IO_MUX + 0x28) 86 | #define FUNC_SDDATA2 0 87 | #define FUNC_SPIHD 1 88 | #define FUNC_GPIO9 3 89 | #define UFNC_HSPIHD 4 90 | 91 | #define PERIPHS_IO_MUX_SD_DATA3_U (PERIPHS_IO_MUX + 0x2c) 92 | #define FUNC_SDDATA3 0 93 | #define FUNC_SPIWP 1 94 | #define FUNC_GPIO10 3 95 | #define FUNC_HSPIWP 4 96 | 97 | #define PERIPHS_IO_MUX_SD_CMD_U (PERIPHS_IO_MUX + 0x30) 98 | #define FUNC_SDCMD 0 99 | #define FUNC_SPICS0 1 100 | #define FUNC_GPIO11 3 101 | #define U1RTS 4 102 | #define UART1_RTS 4 103 | 104 | #define PERIPHS_IO_MUX_GPIO0_U (PERIPHS_IO_MUX + 0x34) 105 | #define FUNC_GPIO0 0 106 | #define FUNC_SPICS2 1 107 | #define FUNC_CLK_OUT 4 108 | 109 | #define PERIPHS_IO_MUX_GPIO2_U (PERIPHS_IO_MUX + 0x38) 110 | #define FUNC_GPIO2 0 111 | #define FUNC_I2SO_WS 1 112 | #define FUNC_U1TXD_BK 2 113 | #define FUNC_UART1_TXD_BK 2 114 | #define FUNC_U0TXD_BK 4 115 | #define FUNC_UART0_TXD_BK 4 116 | 117 | #define PERIPHS_IO_MUX_GPIO4_U (PERIPHS_IO_MUX + 0x3C) 118 | #define FUNC_GPIO4 0 119 | #define FUNC_CLK_XTAL 1 120 | 121 | #define PERIPHS_IO_MUX_GPIO5_U (PERIPHS_IO_MUX + 0x40) 122 | #define FUNC_GPIO5 0 123 | #define FUNC_CLK_RTC 1 124 | 125 | #define PIN_PULLUP_DIS(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME, PERIPHS_IO_MUX_PULLUP) 126 | #define PIN_PULLUP_EN(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME, PERIPHS_IO_MUX_PULLUP) 127 | 128 | #define PIN_FUNC_SELECT(PIN_NAME, FUNC) do { \ 129 | CLEAR_PERI_REG_MASK(PIN_NAME, (PERIPHS_IO_MUX_FUNC< 4 | 5 | // Include Espressif version first, then undefine, then include LibC version 6 | #define int8_t int8_t_espressif 7 | #define int16_t int16_t_espressif 8 | #define int32_t int32_t_espressif 9 | #define uint8_t uint8_t_espressif 10 | #define uint16_t uint16_t_espressif 11 | #define uint32_t uint32_t_espressif 12 | extern "C" { 13 | #include 14 | } 15 | #undef int8_t 16 | #undef int16_t 17 | #undef int32_t 18 | #undef uint8_t 19 | #undef uint16_t 20 | #undef uint32_t 21 | #undef __packed__ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | extern "C" { 28 | #include 29 | 30 | void *pvPortMalloc( size_t xWantedSize ); 31 | void vPortFree( void *pv ); 32 | void *pvPortZalloc(size_t size); 33 | 34 | typedef __builtin_va_list va_list; 35 | int ets_sprintf(char *, const char *, ...); 36 | int ets_vsprintf(char *str, const char *format, va_list ap); 37 | int ets_vsnprintf(char *str, size_t size, const char *format, va_list ap); 38 | void* ets_memcpy(void *, const void*,size_t); 39 | void ets_intr_lock(); 40 | void ets_intr_unlock(); 41 | void ets_wdt_disable(); 42 | void ets_delay_us(uint32_t); 43 | void ets_timer_disarm(os_timer_t *); 44 | void ets_timer_arm_new(os_timer_t *, uint32_t, bool, int); 45 | void ets_timer_setfn(os_timer_t *, os_timer_func_t *, void *); 46 | void ets_isr_attach(int intr, void *handler, void *arg); 47 | void ets_isr_mask(unsigned intr); 48 | void ets_isr_unmask(unsigned intr); 49 | } 50 | 51 | extern "C" { 52 | #include 53 | #include 54 | } 55 | #ifndef ESPCONN_MAXNUM 56 | #define ESPCONN_MAXNUM -7 57 | #endif 58 | #endif//__SDKFIXUP_H_ 59 | -------------------------------------------------------------------------------- /include/slc_register.h: -------------------------------------------------------------------------------- 1 | //Generated at 2012-10-23 19:55:03 2 | /* 3 | * Copyright (c) 2010 - 2011 Espressif System 4 | * 5 | */ 6 | 7 | #ifndef SLC_REGISTER_H_ 8 | #define SLC_REGISTER_H_ 9 | 10 | #define REG_SLC_BASE 0x60000B00 11 | //version value:32'h091700 12 | 13 | #define SLC_CONF0 (REG_SLC_BASE + 0x0) 14 | #ifndef ESP_MAC_5 15 | #define SLC_MODE 0x00000003 16 | #define SLC_MODE_S 12 17 | #endif 18 | #define SLC_DATA_BURST_EN (BIT(9)) 19 | #define SLC_DSCR_BURST_EN (BIT(8)) 20 | #define SLC_RX_NO_RESTART_CLR (BIT(7)) 21 | #define SLC_RX_AUTO_WRBACK (BIT(6)) 22 | #define SLC_RX_LOOP_TEST (BIT(5)) 23 | #define SLC_TX_LOOP_TEST (BIT(4)) 24 | #define SLC_AHBM_RST (BIT(3)) 25 | #define SLC_AHBM_FIFO_RST (BIT(2)) 26 | #define SLC_RXLINK_RST (BIT(1)) 27 | #define SLC_TXLINK_RST (BIT(0)) 28 | 29 | #define SLC_INT_RAW (REG_SLC_BASE + 0x4) 30 | #define SLC_TX_DSCR_EMPTY_INT_RAW (BIT(21)) 31 | #define SLC_RX_DSCR_ERR_INT_RAW (BIT(20)) 32 | #define SLC_TX_DSCR_ERR_INT_RAW (BIT(19)) 33 | #define SLC_TOHOST_INT_RAW (BIT(18)) 34 | #define SLC_RX_EOF_INT_RAW (BIT(17)) 35 | #define SLC_RX_DONE_INT_RAW (BIT(16)) 36 | #define SLC_TX_EOF_INT_RAW (BIT(15)) 37 | #define SLC_TX_DONE_INT_RAW (BIT(14)) 38 | #define SLC_TOKEN1_1TO0_INT_RAW (BIT(13)) 39 | #define SLC_TOKEN0_1TO0_INT_RAW (BIT(12)) 40 | #define SLC_TX_OVF_INT_RAW (BIT(11)) 41 | #define SLC_RX_UDF_INT_RAW (BIT(10)) 42 | #define SLC_TX_START_INT_RAW (BIT(9)) 43 | #define SLC_RX_START_INT_RAW (BIT(8)) 44 | #define SLC_FRHOST_BIT7_INT_RAW (BIT(7)) 45 | #define SLC_FRHOST_BIT6_INT_RAW (BIT(6)) 46 | #define SLC_FRHOST_BIT5_INT_RAW (BIT(5)) 47 | #define SLC_FRHOST_BIT4_INT_RAW (BIT(4)) 48 | #define SLC_FRHOST_BIT3_INT_RAW (BIT(3)) 49 | #define SLC_FRHOST_BIT2_INT_RAW (BIT(2)) 50 | #define SLC_FRHOST_BIT1_INT_RAW (BIT(1)) 51 | #define SLC_FRHOST_BIT0_INT_RAW (BIT(0)) 52 | 53 | #define SLC_INT_STATUS (REG_SLC_BASE + 0x8) 54 | #define SLC_TX_DSCR_EMPTY_INT_ST (BIT(21)) 55 | #define SLC_RX_DSCR_ERR_INT_ST (BIT(20)) 56 | #define SLC_TX_DSCR_ERR_INT_ST (BIT(19)) 57 | #define SLC_TOHOST_INT_ST (BIT(18)) 58 | #define SLC_RX_EOF_INT_ST (BIT(17)) 59 | #define SLC_RX_DONE_INT_ST (BIT(16)) 60 | #define SLC_TX_EOF_INT_ST (BIT(15)) 61 | #define SLC_TX_DONE_INT_ST (BIT(14)) 62 | #define SLC_TOKEN1_1TO0_INT_ST (BIT(13)) 63 | #define SLC_TOKEN0_1TO0_INT_ST (BIT(12)) 64 | #define SLC_TX_OVF_INT_ST (BIT(11)) 65 | #define SLC_RX_UDF_INT_ST (BIT(10)) 66 | #define SLC_TX_START_INT_ST (BIT(9)) 67 | #define SLC_RX_START_INT_ST (BIT(8)) 68 | #define SLC_FRHOST_BIT7_INT_ST (BIT(7)) 69 | #define SLC_FRHOST_BIT6_INT_ST (BIT(6)) 70 | #define SLC_FRHOST_BIT5_INT_ST (BIT(5)) 71 | #define SLC_FRHOST_BIT4_INT_ST (BIT(4)) 72 | #define SLC_FRHOST_BIT3_INT_ST (BIT(3)) 73 | #define SLC_FRHOST_BIT2_INT_ST (BIT(2)) 74 | #define SLC_FRHOST_BIT1_INT_ST (BIT(1)) 75 | #define SLC_FRHOST_BIT0_INT_ST (BIT(0)) 76 | 77 | #define SLC_INT_ENA (REG_SLC_BASE + 0xC) 78 | #define SLC_TX_DSCR_EMPTY_INT_ENA (BIT(21)) 79 | #define SLC_RX_DSCR_ERR_INT_ENA (BIT(20)) 80 | #define SLC_TX_DSCR_ERR_INT_ENA (BIT(19)) 81 | #define SLC_TOHOST_INT_ENA (BIT(18)) 82 | #define SLC_RX_EOF_INT_ENA (BIT(17)) 83 | #define SLC_RX_DONE_INT_ENA (BIT(16)) 84 | #define SLC_TX_EOF_INT_ENA (BIT(15)) 85 | #define SLC_TX_DONE_INT_ENA (BIT(14)) 86 | #define SLC_TOKEN1_1TO0_INT_ENA (BIT(13)) 87 | #define SLC_TOKEN0_1TO0_INT_ENA (BIT(12)) 88 | #define SLC_TX_OVF_INT_ENA (BIT(11)) 89 | #define SLC_RX_UDF_INT_ENA (BIT(10)) 90 | #define SLC_TX_START_INT_ENA (BIT(9)) 91 | #define SLC_RX_START_INT_ENA (BIT(8)) 92 | #define SLC_FRHOST_BIT7_INT_ENA (BIT(7)) 93 | #define SLC_FRHOST_BIT6_INT_ENA (BIT(6)) 94 | #define SLC_FRHOST_BIT5_INT_ENA (BIT(5)) 95 | #define SLC_FRHOST_BIT4_INT_ENA (BIT(4)) 96 | #define SLC_FRHOST_BIT3_INT_ENA (BIT(3)) 97 | #define SLC_FRHOST_BIT2_INT_ENA (BIT(2)) 98 | #define SLC_FRHOST_BIT1_INT_ENA (BIT(1)) 99 | #define SLC_FRHOST_BIT0_INT_ENA (BIT(0)) 100 | 101 | #define SLC_FRHOST_BIT_INT_ENA_ALL 0xff 102 | 103 | #define SLC_INT_CLR (REG_SLC_BASE + 0x10) 104 | #define SLC_TX_DSCR_EMPTY_INT_CLR (BIT(21)) 105 | #define SLC_RX_DSCR_ERR_INT_CLR (BIT(20)) 106 | #define SLC_TX_DSCR_ERR_INT_CLR (BIT(19)) 107 | #define SLC_TOHOST_INT_CLR (BIT(18)) 108 | #define SLC_RX_EOF_INT_CLR (BIT(17)) 109 | #define SLC_RX_DONE_INT_CLR (BIT(16)) 110 | #define SLC_TX_EOF_INT_CLR (BIT(15)) 111 | #define SLC_TX_DONE_INT_CLR (BIT(14)) 112 | #define SLC_TOKEN1_1TO0_INT_CLR (BIT(13)) 113 | #define SLC_TOKEN0_1TO0_INT_CLR (BIT(12)) 114 | #define SLC_TX_OVF_INT_CLR (BIT(11)) 115 | #define SLC_RX_UDF_INT_CLR (BIT(10)) 116 | #define SLC_TX_START_INT_CLR (BIT(9)) 117 | #define SLC_RX_START_INT_CLR (BIT(8)) 118 | #define SLC_FRHOST_BIT7_INT_CLR (BIT(7)) 119 | #define SLC_FRHOST_BIT6_INT_CLR (BIT(6)) 120 | #define SLC_FRHOST_BIT5_INT_CLR (BIT(5)) 121 | #define SLC_FRHOST_BIT4_INT_CLR (BIT(4)) 122 | #define SLC_FRHOST_BIT3_INT_CLR (BIT(3)) 123 | #define SLC_FRHOST_BIT2_INT_CLR (BIT(2)) 124 | #define SLC_FRHOST_BIT1_INT_CLR (BIT(1)) 125 | #define SLC_FRHOST_BIT0_INT_CLR (BIT(0)) 126 | 127 | #define SLC_RX_STATUS (REG_SLC_BASE + 0x14) 128 | #define SLC_RX_EMPTY (BIT(1)) 129 | #define SLC_RX_FULL (BIT(0)) 130 | 131 | #define SLC_RX_FIFO_PUSH (REG_SLC_BASE + 0x18) 132 | #define SLC_RXFIFO_PUSH (BIT(16)) 133 | #define SLC_RXFIFO_WDATA 0x000001FF 134 | #define SLC_RXFIFO_WDATA_S 0 135 | 136 | #define SLC_TX_STATUS (REG_SLC_BASE + 0x1C) 137 | #define SLC_TX_EMPTY (BIT(1)) 138 | #define SLC_TX_FULL (BIT(0)) 139 | 140 | #define SLC_TX_FIFO_POP (REG_SLC_BASE + 0x20) 141 | #define SLC_TXFIFO_POP (BIT(16)) 142 | #define SLC_TXFIFO_RDATA 0x000007FF 143 | #define SLC_TXFIFO_RDATA_S 0 144 | 145 | #define SLC_RX_LINK (REG_SLC_BASE + 0x24) 146 | #define SLC_RXLINK_PARK (BIT(31)) 147 | #define SLC_RXLINK_RESTART (BIT(30)) 148 | #define SLC_RXLINK_START (BIT(29)) 149 | #define SLC_RXLINK_STOP (BIT(28)) 150 | #define SLC_RXLINK_DESCADDR_MASK 0x000FFFFF 151 | #define SLC_RXLINK_ADDR_S 0 152 | 153 | #define SLC_TX_LINK (REG_SLC_BASE + 0x28) 154 | #define SLC_TXLINK_PARK (BIT(31)) 155 | #define SLC_TXLINK_RESTART (BIT(30)) 156 | #define SLC_TXLINK_START (BIT(29)) 157 | #define SLC_TXLINK_STOP (BIT(28)) 158 | #define SLC_TXLINK_DESCADDR_MASK 0x000FFFFF 159 | #define SLC_TXLINK_ADDR_S 0 160 | 161 | #define SLC_INTVEC_TOHOST (REG_SLC_BASE + 0x2C) 162 | #define SLC_TOHOST_INTVEC 0x000000FF 163 | #define SLC_TOHOST_INTVEC_S 0 164 | 165 | #define SLC_TOKEN0 (REG_SLC_BASE + 0x30) 166 | #define SLC_TOKEN0_MASK 0x00000FFF 167 | #define SLC_TOKEN0_S 16 168 | #define SLC_TOKEN0_LOCAL_INC_MORE (BIT(14)) 169 | #define SLC_TOKEN0_LOCAL_INC (BIT(13)) 170 | #define SLC_TOKEN0_LOCAL_WR (BIT(12)) 171 | #define SLC_TOKEN0_LOCAL_WDATA_MASK 0x00000FFF 172 | #define SLC_TOKEN0_LOCAL_WDATA_S 0 173 | 174 | #define SLC_TOKEN1 (REG_SLC_BASE + 0x34) 175 | #define SLC_TOKEN1_MASK 0x00000FFF 176 | #define SLC_TOKEN1_S 16 177 | #define SLC_TOKEN1_LOCAL_INC_MORE (BIT(14)) 178 | #define SLC_TOKEN1_LOCAL_INC (BIT(13)) 179 | #define SLC_TOKEN1_LOCAL_WR (BIT(12)) 180 | #define SLC_TOKEN1_LOCAL_WDATA 0x00000FFF 181 | #define SLC_TOKEN1_LOCAL_WDATA_S 0 182 | 183 | #define SLC_CONF1 (REG_SLC_BASE + 0x38) 184 | #define SLC_STATE0 (REG_SLC_BASE + 0x3C) 185 | #define SLC_STATE1 (REG_SLC_BASE + 0x40) 186 | 187 | #define SLC_BRIDGE_CONF (REG_SLC_BASE + 0x44) 188 | #ifndef ESP_MAC_5 189 | #define SLC_TX_PUSH_IDLE_NUM 0x0000FFFF 190 | #define SLC_TX_PUSH_IDLE_NUM_S 16 191 | #define SLC_TX_DUMMY_MODE (BIT(12)) 192 | #endif 193 | #define SLC_FIFO_MAP_ENA 0x0000000F 194 | #define SLC_FIFO_MAP_ENA_S 8 195 | #define SLC_TXEOF_ENA 0x0000003F 196 | #define SLC_TXEOF_ENA_S 0 197 | 198 | #define SLC_RX_EOF_DES_ADDR (REG_SLC_BASE + 0x48) 199 | #define SLC_TX_EOF_DES_ADDR (REG_SLC_BASE + 0x4C) 200 | #define SLC_FROM_HOST_LAST_DESC SLC_TX_EOF_DES_ADDR 201 | #define SLC_TO_HOST_LAST_DESC SLC_RX_EOF_DES_ADDR 202 | 203 | #define SLC_RX_EOF_BFR_DES_ADDR (REG_SLC_BASE + 0x50) 204 | #define SLC_AHB_TEST (REG_SLC_BASE + 0x54) 205 | #define SLC_AHB_TESTADDR 0x00000003 206 | #define SLC_AHB_TESTADDR_S 4 207 | #define SLC_AHB_TESTMODE 0x00000007 208 | #define SLC_AHB_TESTMODE_S 0 209 | 210 | #define SLC_SDIO_ST (REG_SLC_BASE + 0x58) 211 | #define SLC_BUS_ST 0x00000007 212 | #define SLC_BUS_ST_S 12 213 | #define SLC_SDIO_WAKEUP (BIT(8)) 214 | #define SLC_FUNC_ST 0x0000000F 215 | #define SLC_FUNC_ST_S 4 216 | #define SLC_CMD_ST 0x00000007 217 | #define SLC_CMD_ST_S 0 218 | 219 | #define SLC_RX_DSCR_CONF (REG_SLC_BASE + 0x5C) 220 | #ifdef ESP_MAC_5 221 | #define SLC_INFOR_NO_REPLACE (BIT(9)) 222 | #define SLC_TOKEN_NO_REPLACE (BIT(8)) 223 | #define SLC_POP_IDLE_CNT 0x000000FF 224 | #else 225 | #define SLC_RX_FILL_EN (BIT(20)) 226 | #define SLC_RX_EOF_MODE (BIT(19)) 227 | #define SLC_RX_FILL_MODE (BIT(18)) 228 | #define SLC_INFOR_NO_REPLACE (BIT(17)) 229 | #define SLC_TOKEN_NO_REPLACE (BIT(16)) 230 | #define SLC_POP_IDLE_CNT 0x0000FFFF 231 | #endif 232 | #define SLC_POP_IDLE_CNT_S 0 233 | 234 | #define SLC_TXLINK_DSCR (REG_SLC_BASE + 0x60) 235 | #define SLC_TXLINK_DSCR_BF0 (REG_SLC_BASE + 0x64) 236 | #define SLC_TXLINK_DSCR_BF1 (REG_SLC_BASE + 0x68) 237 | #define SLC_RXLINK_DSCR (REG_SLC_BASE + 0x6C) 238 | #define SLC_RXLINK_DSCR_BF0 (REG_SLC_BASE + 0x70) 239 | #define SLC_RXLINK_DSCR_BF1 (REG_SLC_BASE + 0x74) 240 | #define SLC_DATE (REG_SLC_BASE + 0x78) 241 | #define SLC_ID (REG_SLC_BASE + 0x7C) 242 | 243 | #define SLC_HOST_CONF_W0 (REG_SLC_BASE + 0x80 + 0x14) 244 | #define SLC_HOST_CONF_W1 (REG_SLC_BASE + 0x80 + 0x18) 245 | #define SLC_HOST_CONF_W2 (REG_SLC_BASE + 0x80 + 0x20) 246 | #define SLC_HOST_CONF_W3 (REG_SLC_BASE + 0x80 + 0x24) 247 | #define SLC_HOST_CONF_W4 (REG_SLC_BASE + 0x80 + 0x28) 248 | 249 | #define SLC_HOST_INTR_ST (REG_SLC_BASE + 0x80 + 0x1c) 250 | #define SLC_HOST_INTR_CLR (REG_SLC_BASE + 0x80 + 0x30) 251 | #define SLC_HOST_INTR_SOF_BIT (BIT(12)) 252 | 253 | #define SLC_HOST_INTR_ENA (REG_SLC_BASE + 0x80 + 0x34) 254 | #define SLC_RX_NEW_PACKET_INT_ENA (BIT23) 255 | #define SLC_HOST_TOHOST_BIT0_INT_ENA (BIT0) 256 | #define SLC_HOST_CONF_W5 (REG_SLC_BASE + 0x80 + 0x3C) 257 | #define SLC_HOST_INTR_RAW (REG_SLC_BASE + 0x80 + 0x8) 258 | #define SLC_HOST_INTR_ENA_BIT (BIT(23)) 259 | //[15:12]: 0x3ff9xxxx -- 0b01 from_host 260 | // 0x3ffaxxxx -- 0b10 general 261 | // 0x3ffbxxxx -- 0b11 to_host 262 | #define SLC_DATA_ADDR_CLEAR_MASK (~(0xf<<12)) 263 | #define SLC_FROM_HOST_ADDR_MASK (0x1<<12) 264 | #define SLC_TO_HOST_ADDR_MASK (0x3<<12) 265 | 266 | #define SLC_SET_FROM_HOST_ADDR_MASK(v) do { \ 267 | (v) &= SLC_DATA_ADDR_CLEAR_MASK; \ 268 | (v) |= SLC_FROM_HOST_ADDR_MASK; \ 269 | } while(0); 270 | 271 | #define SLC_SET_TO_HOST_ADDR_MASK(v) do { \ 272 | (v) &= SLC_DATA_ADDR_CLEAR_MASK; \ 273 | (v) |= SLC_TO_HOST_ADDR_MASK; \ 274 | } while(0); 275 | 276 | 277 | #define SLC_TX_DESC_DEBUG_REG 0x3ff0002c //[15:0] set to 0xcccc 278 | 279 | 280 | #endif // SLC_REGISTER_H_INCLUDED 281 | 282 | -------------------------------------------------------------------------------- /include/slc_slv.h: -------------------------------------------------------------------------------- 1 | #ifndef SLC_SLV_H 2 | #define SLC_SLV_H 3 | struct sdio_queue 4 | { 5 | uint32 blocksize:12; 6 | uint32 datalen:12; 7 | uint32 unused:5; 8 | uint32 sub_sof:1; 9 | uint32 eof:1; 10 | uint32 owner:1; 11 | 12 | uint32 buf_ptr; 13 | uint32 next_link_ptr; 14 | }; 15 | 16 | struct sdio_slave_status_element 17 | { 18 | uint32 wr_busy:1; 19 | uint32 rd_empty :1; 20 | uint32 comm_cnt :3; 21 | uint32 intr_no :3; 22 | uint32 rx_length:16; 23 | uint32 res:8; 24 | }; 25 | 26 | union sdio_slave_status 27 | { 28 | struct sdio_slave_status_element elm_value; 29 | uint32 word_value; 30 | }; 31 | #endif//SLC_SLV_H 32 | 33 | -------------------------------------------------------------------------------- /include/spi_register.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 - 2011 Espressif System 3 | * 4 | */ 5 | 6 | #ifndef SPI_REGISTER_H_INCLUDED 7 | #define SPI_REGISTER_H_INCLUDED 8 | 9 | #define REG_SPI_BASE(i) (0x60000200-i*0x100) 10 | #define SPI_CMD(i) (REG_SPI_BASE(i) + 0x0) 11 | #define SPI_USR (BIT(18)) 12 | 13 | #define SPI_ADDR(i) (REG_SPI_BASE(i) + 0x4) 14 | 15 | #define SPI_CTRL(i) (REG_SPI_BASE(i) + 0x8) 16 | #define SPI_WR_BIT_ORDER (BIT(26)) 17 | #define SPI_RD_BIT_ORDER (BIT(25)) 18 | #define SPI_QIO_MODE (BIT(24)) 19 | #define SPI_DIO_MODE (BIT(23)) 20 | #define SPI_QOUT_MODE (BIT(20)) 21 | #define SPI_DOUT_MODE (BIT(14)) 22 | #define SPI_FASTRD_MODE (BIT(13)) 23 | 24 | 25 | 26 | #define SPI_RD_STATUS(i) (REG_SPI_BASE(i) + 0x10) 27 | 28 | #define SPI_CTRL2(i) (REG_SPI_BASE(i) + 0x14) 29 | 30 | #define SPI_CS_DELAY_NUM 0x0000000F 31 | #define SPI_CS_DELAY_NUM_S 28 32 | #define SPI_CS_DELAY_MODE 0x00000003 33 | #define SPI_CS_DELAY_MODE_S 26 34 | #define SPI_MOSI_DELAY_NUM 0x00000007 35 | #define SPI_MOSI_DELAY_NUM_S 23 36 | #define SPI_MOSI_DELAY_MODE 0x00000003 37 | #define SPI_MOSI_DELAY_MODE_S 21 38 | #define SPI_MISO_DELAY_NUM 0x00000007 39 | #define SPI_MISO_DELAY_NUM_S 18 40 | #define SPI_MISO_DELAY_MODE 0x00000003 41 | #define SPI_MISO_DELAY_MODE_S 16 42 | #define SPI_CLOCK(i) (REG_SPI_BASE(i) + 0x18) 43 | #define SPI_CLK_EQU_SYSCLK (BIT(31)) 44 | #define SPI_CLKDIV_PRE 0x00001FFF 45 | #define SPI_CLKDIV_PRE_S 18 46 | #define SPI_CLKCNT_N 0x0000003F 47 | #define SPI_CLKCNT_N_S 12 48 | #define SPI_CLKCNT_H 0x0000003F 49 | #define SPI_CLKCNT_H_S 6 50 | #define SPI_CLKCNT_L 0x0000003F 51 | #define SPI_CLKCNT_L_S 0 52 | 53 | #define SPI_USER(i) (REG_SPI_BASE(i) + 0x1C) 54 | #define SPI_USR_COMMAND (BIT(31)) 55 | #define SPI_USR_ADDR (BIT(30)) 56 | #define SPI_USR_DUMMY (BIT(29)) 57 | #define SPI_USR_MISO (BIT(28)) 58 | #define SPI_USR_MOSI (BIT(27)) 59 | 60 | #define SPI_USR_MOSI_HIGHPART (BIT(25)) 61 | #define SPI_USR_MISO_HIGHPART (BIT(24)) 62 | 63 | 64 | #define SPI_SIO (BIT(16)) 65 | #define SPI_FWRITE_QIO (BIT(15)) 66 | #define SPI_FWRITE_DIO (BIT(14)) 67 | #define SPI_FWRITE_QUAD (BIT(13)) 68 | #define SPI_FWRITE_DUAL (BIT(12)) 69 | #define SPI_WR_BYTE_ORDER (BIT(11)) 70 | #define SPI_RD_BYTE_ORDER (BIT(10)) 71 | #define SPI_CK_OUT_EDGE (BIT(7)) 72 | #define SPI_CK_I_EDGE (BIT(6)) 73 | #define SPI_CS_SETUP (BIT(5)) 74 | #define SPI_CS_HOLD (BIT(4)) 75 | #define SPI_FLASH_MODE (BIT(2)) 76 | 77 | #define SPI_USER1(i) (REG_SPI_BASE(i) + 0x20) 78 | #define SPI_USR_ADDR_BITLEN 0x0000003F 79 | #define SPI_USR_ADDR_BITLEN_S 26 80 | #define SPI_USR_MOSI_BITLEN 0x000001FF 81 | #define SPI_USR_MOSI_BITLEN_S 17 82 | #define SPI_USR_MISO_BITLEN 0x000001FF 83 | #define SPI_USR_MISO_BITLEN_S 8 84 | 85 | #define SPI_USR_DUMMY_CYCLELEN 0x000000FF 86 | #define SPI_USR_DUMMY_CYCLELEN_S 0 87 | 88 | #define SPI_USER2(i) (REG_SPI_BASE(i) + 0x24) 89 | #define SPI_USR_COMMAND_BITLEN 0x0000000F 90 | #define SPI_USR_COMMAND_BITLEN_S 28 91 | #define SPI_USR_COMMAND_VALUE 0x0000FFFF 92 | #define SPI_USR_COMMAND_VALUE_S 0 93 | 94 | #define SPI_WR_STATUS(i) (REG_SPI_BASE(i) + 0x28) 95 | #define SPI_PIN(i) (REG_SPI_BASE(i) + 0x2C) 96 | #define SPI_CS2_DIS (BIT(2)) 97 | #define SPI_CS1_DIS (BIT(1)) 98 | #define SPI_CS0_DIS (BIT(0)) 99 | 100 | #define SPI_SLAVE(i) (REG_SPI_BASE(i) + 0x30) 101 | #define SPI_SYNC_RESET (BIT(31)) 102 | #define SPI_SLAVE_MODE (BIT(30)) 103 | #define SPI_SLV_WR_RD_BUF_EN (BIT(29)) 104 | #define SPI_SLV_WR_RD_STA_EN (BIT(28)) 105 | #define SPI_SLV_CMD_DEFINE (BIT(27)) 106 | #define SPI_TRANS_CNT 0x0000000F 107 | #define SPI_TRANS_CNT_S 23 108 | #define SPI_TRANS_DONE_EN (BIT(9)) 109 | #define SPI_SLV_WR_STA_DONE_EN (BIT(8)) 110 | #define SPI_SLV_RD_STA_DONE_EN (BIT(7)) 111 | #define SPI_SLV_WR_BUF_DONE_EN (BIT(6)) 112 | #define SPI_SLV_RD_BUF_DONE_EN (BIT(5)) 113 | 114 | 115 | 116 | #define SLV_SPI_INT_EN 0x0000001f 117 | #define SLV_SPI_INT_EN_S 5 118 | 119 | #define SPI_TRANS_DONE (BIT(4)) 120 | #define SPI_SLV_WR_STA_DONE (BIT(3)) 121 | #define SPI_SLV_RD_STA_DONE (BIT(2)) 122 | #define SPI_SLV_WR_BUF_DONE (BIT(1)) 123 | #define SPI_SLV_RD_BUF_DONE (BIT(0)) 124 | 125 | #define SPI_SLAVE1(i) (REG_SPI_BASE(i) + 0x34) 126 | #define SPI_SLV_STATUS_BITLEN 0x0000001F 127 | #define SPI_SLV_STATUS_BITLEN_S 27 128 | #define SPI_SLV_BUF_BITLEN 0x000001FF 129 | #define SPI_SLV_BUF_BITLEN_S 16 130 | #define SPI_SLV_RD_ADDR_BITLEN 0x0000003F 131 | #define SPI_SLV_RD_ADDR_BITLEN_S 10 132 | #define SPI_SLV_WR_ADDR_BITLEN 0x0000003F 133 | #define SPI_SLV_WR_ADDR_BITLEN_S 4 134 | 135 | #define SPI_SLV_WRSTA_DUMMY_EN (BIT(3)) 136 | #define SPI_SLV_RDSTA_DUMMY_EN (BIT(2)) 137 | #define SPI_SLV_WRBUF_DUMMY_EN (BIT(1)) 138 | #define SPI_SLV_RDBUF_DUMMY_EN (BIT(0)) 139 | 140 | 141 | 142 | #define SPI_SLAVE2(i) (REG_SPI_BASE(i) + 0x38) 143 | #define SPI_SLV_WRBUF_DUMMY_CYCLELEN 0X000000FF 144 | #define SPI_SLV_WRBUF_DUMMY_CYCLELEN_S 24 145 | #define SPI_SLV_RDBUF_DUMMY_CYCLELEN 0X000000FF 146 | #define SPI_SLV_RDBUF_DUMMY_CYCLELEN_S 16 147 | #define SPI_SLV_WRSTR_DUMMY_CYCLELEN 0X000000FF 148 | #define SPI_SLV_WRSTR_DUMMY_CYCLELEN_S 8 149 | #define SPI_SLV_RDSTR_DUMMY_CYCLELEN 0x000000FF 150 | #define SPI_SLV_RDSTR_DUMMY_CYCLELEN_S 0 151 | 152 | #define SPI_SLAVE3(i) (REG_SPI_BASE(i) + 0x3C) 153 | #define SPI_SLV_WRSTA_CMD_VALUE 0x000000FF 154 | #define SPI_SLV_WRSTA_CMD_VALUE_S 24 155 | #define SPI_SLV_RDSTA_CMD_VALUE 0x000000FF 156 | #define SPI_SLV_RDSTA_CMD_VALUE_S 16 157 | #define SPI_SLV_WRBUF_CMD_VALUE 0x000000FF 158 | #define SPI_SLV_WRBUF_CMD_VALUE_S 8 159 | #define SPI_SLV_RDBUF_CMD_VALUE 0x000000FF 160 | #define SPI_SLV_RDBUF_CMD_VALUE_S 0 161 | 162 | #define SPI_W0(i) (REG_SPI_BASE(i) +0x40) 163 | #define SPI_W1(i) (REG_SPI_BASE(i) +0x44) 164 | #define SPI_W2(i) (REG_SPI_BASE(i) +0x48) 165 | #define SPI_W3(i) (REG_SPI_BASE(i) +0x4C) 166 | #define SPI_W4(i) (REG_SPI_BASE(i) +0x50) 167 | #define SPI_W5(i) (REG_SPI_BASE(i) +0x54) 168 | #define SPI_W6(i) (REG_SPI_BASE(i) +0x58) 169 | #define SPI_W7(i) (REG_SPI_BASE(i) +0x5C) 170 | #define SPI_W8(i) (REG_SPI_BASE(i) +0x60) 171 | #define SPI_W9(i) (REG_SPI_BASE(i) +0x64) 172 | #define SPI_W10(i) (REG_SPI_BASE(i) +0x68) 173 | #define SPI_W11(i) (REG_SPI_BASE(i) +0x6C) 174 | #define SPI_W12(i) (REG_SPI_BASE(i) +0x70) 175 | #define SPI_W13(i) (REG_SPI_BASE(i) +0x74) 176 | #define SPI_W14(i) (REG_SPI_BASE(i) +0x78) 177 | #define SPI_W15(i) (REG_SPI_BASE(i) +0x7C) 178 | 179 | #define SPI_EXT3(i) (REG_SPI_BASE(i) + 0xFC) 180 | #define SPI_INT_HOLD_ENA 0x00000003 181 | #define SPI_INT_HOLD_ENA_S 0 182 | #endif // SPI_REGISTER_H_INCLUDED 183 | -------------------------------------------------------------------------------- /include/user_config.h: -------------------------------------------------------------------------------- 1 | #ifndef USER_CONFIG_H 2 | #define USER_CONFIG_H 3 | #endif//USER_CONFIG_H 4 | -------------------------------------------------------------------------------- /static-rename-sections.txt: -------------------------------------------------------------------------------- 1 | --rename-section .nospi=.text 2 | 3 | -------------------------------------------------------------------------------- /user/CTimer.cpp: -------------------------------------------------------------------------------- 1 | #include "CTimer.h" 2 | extern "C" { 3 | #include 4 | } 5 | 6 | CTimer::CTimer() { 7 | os_timer_disarm(&m_timer); 8 | m_bRunning = false; 9 | m_bRepeat = false; 10 | } 11 | 12 | CTimer::~CTimer() { 13 | os_timer_disarm(&m_timer); 14 | } 15 | 16 | void CTimer::onTrigger() {} 17 | 18 | void CTimer::Stop() { 19 | os_timer_disarm(&m_timer); 20 | m_bRunning = false; 21 | m_bRepeat = false; 22 | } 23 | 24 | void CTimer::Start(uint32_t nMilliseconds, bool bRepeat) { 25 | if (m_bRunning) 26 | os_timer_disarm(&m_timer); 27 | os_timer_setfn(&m_timer, &CTimer::timer_cb, (void *)this); 28 | os_timer_arm(&m_timer, nMilliseconds, bRepeat); 29 | m_bRepeat = bRepeat; 30 | m_bRunning = true; 31 | } 32 | 33 | void CTimer::timer_cb(void *pTimer) { 34 | CTimer *pThis = (CTimer *)pTimer; 35 | if (pThis->m_bRunning) { 36 | if (!pThis->m_bRepeat) 37 | pThis->m_bRunning = false; 38 | pThis->onTrigger(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /user/CTimer.h: -------------------------------------------------------------------------------- 1 | #ifndef CTIMER_H 2 | #define CTIMER_H 3 | #include 4 | 5 | class CTimer { 6 | public: 7 | CTimer(); 8 | virtual ~CTimer(); 9 | virtual void onTrigger(); 10 | void Stop(); 11 | void Start(uint32_t nMilliseconds, bool bRepeat); 12 | private: 13 | os_timer_t m_timer; 14 | bool m_bRunning; 15 | bool m_bRepeat; 16 | 17 | static void timer_cb(void *pTimer); 18 | }; 19 | #endif//CTIMER_H 20 | -------------------------------------------------------------------------------- /user/config/CConfigHtmlGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | extern "C" { 3 | #include 4 | #include 5 | } 6 | #include "CConfigHtmlGenerator.h" 7 | #include "httpd/CHttpRequest.h" 8 | #include "config/config.h" 9 | #include "helpers.h" 10 | 11 | void CConfigHtmlGenerator::handle(CHttpRequest *pRequest) { 12 | pRequest->addListener(new CConfigHtmlGenerator(pRequest)); 13 | } 14 | 15 | CConfigHtmlGenerator::CConfigHtmlGenerator(CHttpRequest *pRequest) { 16 | m_pRequest = pRequest; 17 | } 18 | 19 | void CConfigHtmlGenerator::beginModule(const char *szName, const char *szDescription) { 20 | write("
"); 21 | write(szDescription); 22 | write(""); 23 | m_lCategories.push_back(szName); 24 | } 25 | void CConfigHtmlGenerator::endModule() { 26 | write("
"); 27 | if (!m_lCategories.empty()) 28 | m_lCategories.pop_back(); 29 | } 30 | void CConfigHtmlGenerator::optionBool(const char *szName, const char *szDescription, bool *pbValue, bool bDefault) { 31 | write(szDescription); 32 | write(":
"); 39 | } 40 | void CConfigHtmlGenerator::optionString(const char *szName, const char *szDescription, char *szValue, size_t nSize, const char *szDefault) { 41 | write(szDescription); 42 | write(":
"); 48 | } 49 | void CConfigHtmlGenerator::optionInt(const char *szName, const char *szDescription, void *pValue, size_t nSize, uint32_t nMin, uint32_t nMax, uint32_t nDefault) { 50 | char szTemp[12]; 51 | write(szDescription); 52 | write(":
"); 64 | } 65 | void CConfigHtmlGenerator::optionSelectBegin(const char *szName, const char *szDescription, unsigned int* pnValue, unsigned int nDefault) { 66 | write(szDescription); 67 | write(":
"); 87 | } 88 | void CConfigHtmlGenerator::optionIpAddress(const char *szName, const char *szDescription, uint32_t *pAddress, uint32_t nDefault) { 89 | char szTemp[32]; 90 | write(szDescription); 91 | write(": "); 92 | for (unsigned int i=0; i<4; i++) { 93 | if (i != 0) 94 | write("."); 95 | write("> (i*8)) & 0xFF); 103 | write(szTemp); 104 | write("\">"); 105 | } 106 | write("
"); 107 | } 108 | void CConfigHtmlGenerator::optionFloat(const char *szName, const char *szDescription, float* pfValue, float fDefault) { 109 | char szTemp[64]; 110 | write(szDescription); 111 | write(": "); 112 | write(""); 119 | write("
"); 120 | } 121 | void CConfigHtmlGenerator::onHeader(CHttpRequest *pRequest, const char *szName, const char *szValue) { 122 | } 123 | void CConfigHtmlGenerator::onHeadersDone(CHttpRequest *pRequest, size_t nDataLength) { 124 | } 125 | void CConfigHtmlGenerator::onData(CHttpRequest *pRequest, const uint8_t *pData, size_t nLength) { 126 | } 127 | void CConfigHtmlGenerator::onDataDone(CHttpRequest *pRequest) { 128 | write_header(); 129 | config_run(this); 130 | write_footer(); 131 | pRequest->startHeaders(200, "OK"); 132 | pRequest->sendHeader("Content-Type", "text/html"); 133 | pRequest->sendHeader("Content-Length", m_nTotalLen); 134 | pRequest->endHeaders(); 135 | //Actual data will be sent in onSent 136 | } 137 | void CConfigHtmlGenerator::onSent(CHttpRequest *pRequest) { 138 | if (m_lChunks.empty()) { 139 | pRequest->end(false); 140 | } else { 141 | pRequest->sendData(m_lChunks.front().pData, m_lChunks.front().nLen); 142 | m_lChunks.pop_front(); 143 | } 144 | } 145 | void CConfigHtmlGenerator::onDisconnected(CHttpRequest *pRequest) { 146 | delete this; 147 | } 148 | //Only 149 | void CConfigHtmlGenerator::write_header() { 150 | write("EspLightNode Configuration

EspLightNode Configuration

"); 151 | write("
"); 152 | } 153 | void CConfigHtmlGenerator::write_footer() { 154 | write("
"); 155 | write(""); 156 | } 157 | void CConfigHtmlGenerator::start_transfer(CHttpRequest *pRequest) { 158 | pRequest->startHeaders(200, "OK"); 159 | pRequest->sendHeader("Content-Type", "text/html"); 160 | pRequest->sendHeader("Content-Length", m_nTotalLen); 161 | for (auto chunk : m_lChunks) 162 | pRequest->sendData(chunk.pData, chunk.nLen); 163 | pRequest->end(false); 164 | } 165 | void CConfigHtmlGenerator::write_fieldprefix() { 166 | for (auto name : m_lCategories) { 167 | write(name); 168 | write("."); 169 | } 170 | } 171 | void CConfigHtmlGenerator::write(const uint8_t* pData, size_t nLen) { 172 | while (nLen) { 173 | if (m_lChunks.empty() || m_lChunks.back().nLen >= sizeof(Chunk::pData)) { 174 | m_lChunks.push_back(Chunk()); 175 | } 176 | Chunk& curChunk = m_lChunks.back(); 177 | size_t nCurLen = std::min(nLen, sizeof(Chunk::pData) - curChunk.nLen); 178 | memcpy(&curChunk.pData[curChunk.nLen], pData, nCurLen); 179 | curChunk.nLen += nCurLen; 180 | m_nTotalLen += nCurLen; 181 | nLen -= nCurLen; 182 | pData = &pData[nCurLen]; 183 | } 184 | } 185 | void CConfigHtmlGenerator::write(const char* szData) { 186 | write((const uint8_t *)szData, strlen(szData)); 187 | } 188 | -------------------------------------------------------------------------------- /user/config/CConfigHtmlGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef CCONFIGHTMLGENERATOR_H 2 | #define CCONFIGHTMLGENERATOR_H 3 | #include "IConfigRunner.h" 4 | #include "httpd/CHttpRequest.h" 5 | #include 6 | 7 | class CHttpRequest; 8 | class CConfigHtmlGenerator : public IConfigRunner, IHttpRequestListener { 9 | public: 10 | static void handle(CHttpRequest *pRequest); 11 | //IConfigRunner 12 | void beginModule(const char *szName, const char *szDescription); 13 | void endModule(); 14 | void optionBool(const char *szName, const char *szDescription, bool *pbValue, bool bDefault); 15 | void optionString(const char *szName, const char *szDescription, char *szValue, size_t nSize, const char *szDefault); 16 | void optionInt(const char *szName, const char *szDescription, void *pValue, size_t nSize, uint32_t nMin, uint32_t nMax, uint32_t nDefault); 17 | void optionSelectBegin(const char *szName, const char *szDescription, unsigned int* pnValue, unsigned int nDefault); 18 | void optionSelectItem(const char *szName, unsigned int nValue); 19 | void optionSelectEnd(); 20 | void optionIpAddress(const char *szName, const char *szDescription, uint32_t *pAddress, uint32_t nDefault); 21 | void optionFloat(const char *szName, const char *szDescription, float* pfValue, float fDefault); 22 | //IHttpRequestListener 23 | void onHeader(CHttpRequest *pRequest, const char *szName, const char *szValue); 24 | void onHeadersDone(CHttpRequest *pRequest, size_t nDataLength); 25 | void onData(CHttpRequest *pRequest, const uint8_t *pData, size_t nData); 26 | void onDataDone(CHttpRequest *pRequest); 27 | void onSent(CHttpRequest *pRequest); 28 | void onDisconnected(CHttpRequest *pRequest); 29 | 30 | //Only 31 | private: 32 | CHttpRequest *m_pRequest; 33 | struct Chunk { 34 | uint8_t pData[512]; 35 | size_t nLen; 36 | }; 37 | std::list m_lCategories; 38 | size_t m_nTotalLen; 39 | std::list m_lChunks; 40 | unsigned int m_nCurrentSelectItem; 41 | 42 | CConfigHtmlGenerator(CHttpRequest *pRequest); 43 | void write_header(); 44 | void write_footer(); 45 | void start_transfer(CHttpRequest *pRequest); 46 | void write_fieldprefix(); 47 | void write(const uint8_t* pData, size_t nLen); 48 | void write(const char* szData); 49 | }; 50 | #endif//CCONFIGHTMLGENERATOR_H 51 | 52 | -------------------------------------------------------------------------------- /user/config/CConfigLoader.cpp: -------------------------------------------------------------------------------- 1 | #include "CConfigLoader.h" 2 | #include "config/CConfigSection.h" 3 | #include "config/format.h" 4 | #include "config/CConfigReader.h" 5 | #include "config/config.h" 6 | #include "string.h" 7 | 8 | void CConfigLoader::load() { 9 | //Allocate big classes on the heap instead of the stack. 10 | CConfigReader *pReader = new CConfigReader(CONFIG_START_SECTOR, CONFIG_SECTOR_DIRECTION); 11 | CConfigLoader loader; 12 | CConfigSection *pRootSection=new CConfigSection(); 13 | const uint8_t pExpectedHeader[] = CONFIG_HEADER; 14 | uint8_t pHeader[sizeof(pExpectedHeader)]; 15 | pReader->readBytes(pHeader, sizeof(pExpectedHeader)); 16 | if (memcmp(pHeader, pExpectedHeader, sizeof(pExpectedHeader)) != 0 || !pRootSection->read(pReader)) { 17 | delete pRootSection; 18 | pRootSection = NULL; 19 | } 20 | delete pReader; 21 | 22 | loader.m_lSectionStack.push_back(pRootSection); 23 | config_run(&loader); 24 | 25 | if (pRootSection) 26 | delete pRootSection; 27 | } 28 | 29 | void CConfigLoader::beginModule(const char *szName, const char *szDescription) { 30 | CConfigSection *pSubSection; 31 | if (m_lSectionStack.empty() || m_lSectionStack.back() == NULL || !m_lSectionStack.back()->getSection(szName, &pSubSection)) 32 | pSubSection = NULL; 33 | m_lSectionStack.push_back(pSubSection); 34 | } 35 | 36 | void CConfigLoader::endModule() { 37 | // Only pop if there will be at least one left, 38 | // We don't want to constantly have to check for emptiness. 39 | if (m_lSectionStack.size() > 1) 40 | m_lSectionStack.pop_back(); 41 | } 42 | 43 | void CConfigLoader::optionBool(const char *szName, const char *szDescription, bool *pbValue, bool bDefault) { 44 | unsigned int nValue; 45 | if (!m_lSectionStack.empty() && m_lSectionStack.back() && m_lSectionStack.back()->getUInt(szName, nValue)) 46 | *pbValue = (nValue != 0); 47 | else 48 | *pbValue = bDefault; 49 | } 50 | 51 | void CConfigLoader::optionString(const char *szName, const char *szDescription, char *szValue, size_t nSize, const char *szDefault) { 52 | if (m_lSectionStack.empty() || !m_lSectionStack.back() || !m_lSectionStack.back()->getString(szName, szValue, nSize)) { 53 | strncpy(szValue, szDefault, nSize); 54 | szValue[nSize-1]='\0'; 55 | } 56 | } 57 | 58 | void CConfigLoader::optionInt(const char *szName, const char *szDescription, void *pValue, size_t nSize, uint32_t nMin, uint32_t nMax, uint32_t nDefault) { 59 | unsigned int nValue; 60 | if (m_lSectionStack.empty() || !m_lSectionStack.back() || !m_lSectionStack.back()->getUInt(szName, nValue)) 61 | nValue = nDefault; 62 | if (nValue < nMin) 63 | nValue = nMin; 64 | if (nValue > nMax) 65 | nValue = nMax; 66 | switch (nSize) { 67 | case 1: (*(uint8_t*)pValue) = nValue; break; 68 | case 2: (*(uint16_t*)pValue) = nValue; break; 69 | case 4: (*(uint32_t*)pValue) = nValue; break; 70 | } 71 | } 72 | void CConfigLoader::optionSelectBegin(const char *szName, const char *szDescription, unsigned int* pnValue, unsigned int nDefault) { 73 | unsigned int nValue; 74 | if (m_lSectionStack.empty() || !m_lSectionStack.back() || !m_lSectionStack.back()->getUInt(szName, nValue)) 75 | nValue = nDefault; 76 | *pnValue = nValue; 77 | 78 | m_pnSelectValue = pnValue; 79 | m_nDefaultSelectValue = nDefault; 80 | m_bValidSelectValue = false; 81 | } 82 | void CConfigLoader::optionSelectItem(const char *szName, unsigned int nValue) { 83 | if (nValue == *m_pnSelectValue) 84 | m_bValidSelectValue = true; 85 | } 86 | void CConfigLoader::optionSelectEnd() { 87 | if (!m_bValidSelectValue) 88 | *m_pnSelectValue = m_nDefaultSelectValue; 89 | } 90 | void CConfigLoader::optionIpAddress(const char *szName, const char *szDescription, uint32_t *pAddress, uint32_t nDefault) { 91 | if (m_lSectionStack.empty() || !m_lSectionStack.back() || !m_lSectionStack.back()->getUInt(szName, *pAddress)) 92 | *pAddress = nDefault; 93 | } 94 | void CConfigLoader::optionFloat(const char *szName, const char *szDescription, float* pfValue, float fDefault) { 95 | if (m_lSectionStack.empty() || !m_lSectionStack.back() || !m_lSectionStack.back()->getFloat(szName, *pfValue)) 96 | *pfValue = fDefault; 97 | } 98 | 99 | -------------------------------------------------------------------------------- /user/config/CConfigLoader.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_CCONFIGLOADER_H 2 | #define CONFIG_CCONFIGLOADER_H 3 | #include "config/IConfigRunner.h" 4 | #include 5 | 6 | class CConfigSection; 7 | class CConfigLoader : IConfigRunner { 8 | public: 9 | static void load(); 10 | private: 11 | void beginModule(const char *szName, const char *szDescription); 12 | void endModule(); 13 | void optionBool(const char *szName, const char *szDescription, bool *pbValue, bool pbDefault); 14 | void optionString(const char *szName, const char *szDescription, char *szValue, size_t nSize, const char *szDefault); 15 | void optionInt(const char *szName, const char *szDescription, void *pValue, size_t nSize, uint32_t nMin, uint32_t nMax, uint32_t nDefault); 16 | void optionSelectBegin(const char *szName, const char *szDescription, unsigned int* pnValue, unsigned int nDefault); 17 | void optionSelectItem(const char *szName, unsigned int nValue); 18 | void optionSelectEnd(); 19 | void optionIpAddress(const char *szName, const char *szDescription, uint32_t *pAddress, uint32_t nDefault); 20 | void optionFloat(const char *szName, const char *szDescription, float* pfValue, float fDefault); 21 | 22 | std::list m_lSectionStack; 23 | unsigned int* m_pnSelectValue; 24 | unsigned int m_nDefaultSelectValue; 25 | bool m_bValidSelectValue; 26 | }; 27 | #endif//CONFIG_CCONFIGLOADER_H 28 | -------------------------------------------------------------------------------- /user/config/CConfigPostHandler.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "CConfigPostHandler.h" 3 | #include 4 | #include "debug/CDebugServer.h" 5 | #include "config/config.h" 6 | #include "CConfigWriter.h" 7 | #include "config/format.h" 8 | #include "helpers.h" 9 | extern "C" { 10 | #include 11 | } 12 | 13 | bool CConfigPostHandler::handle(CHttpRequest* pRequest) { 14 | CConfigPostHandler *pHandler = new CConfigPostHandler(pRequest); 15 | pRequest->addListener(static_cast(pHandler)); 16 | return true; 17 | } 18 | 19 | CConfigPostHandler::CConfigPostHandler(CHttpRequest* pRequest) { 20 | m_pRequest=pRequest; 21 | } 22 | 23 | CConfigPostHandler::~CConfigPostHandler() { 24 | 25 | } 26 | 27 | void CConfigPostHandler::onHeader(CHttpRequest *pRequest, const char *szName, const char *szValue) { 28 | } 29 | 30 | void CConfigPostHandler::onHeadersDone(CHttpRequest *pRequest, size_t nDataLength) { 31 | 32 | } 33 | 34 | void CConfigPostHandler::onData(CHttpRequest *pRequest, const uint8_t *pData, size_t nLength) { 35 | for (size_t i = 0; i < nLength; i++) { 36 | if (m_nEscapeLeft) { 37 | m_nEscapeLeft--; 38 | m_cEscape <<= 4; 39 | if (pData[i] >= '0' && pData[i] <= '9') 40 | m_cEscape |= (pData[i] - '0'); 41 | else if (pData[i] >= 'a' && pData[i] <= 'z') 42 | m_cEscape |= (pData[i] - 'a') + 10; 43 | else if (pData[i] >= 'A' && pData[i] <= 'Z') 44 | m_cEscape |= (pData[i] - 'A') + 10; 45 | if (m_nEscapeLeft == 0) 46 | m_vBuffer.push_back(m_cEscape); 47 | } else if (pData[i] == '=') { 48 | DEBUG("Equal sign"); 49 | if (m_bHasKey) { 50 | m_vBuffer.push_back(pData[i]); 51 | } else { 52 | m_szKey = std::string(m_vBuffer.begin(), m_vBuffer.end()); 53 | m_vBuffer.clear(); 54 | m_bHasKey = true; 55 | } 56 | } else if (pData[i] == '&') { 57 | DEBUG("Ampersand"); 58 | if (!m_bHasKey) { 59 | m_szKey=std::string(m_vBuffer.begin(), m_vBuffer.end()); 60 | m_vBuffer.clear(); 61 | m_bHasKey=true; 62 | } 63 | std::string szValue(m_vBuffer.begin(), m_vBuffer.end()); 64 | DEBUG("Insert %s = %s", m_szKey.c_str(), szValue.c_str()); 65 | m_mValues[m_szKey]=szValue; 66 | 67 | m_vBuffer.clear(); 68 | m_bHasKey = false; 69 | } else if (pData[i] == '%') { 70 | m_cEscape = 0; 71 | m_nEscapeLeft = 2; 72 | } else if (pData[i] == '+') { 73 | m_vBuffer.push_back(' '); 74 | } else { 75 | m_vBuffer.push_back(pData[i]); 76 | } 77 | } 78 | } 79 | 80 | void CConfigPostHandler::onDataDone(CHttpRequest *pRequest) { 81 | //Handle last bit of data 82 | if (!m_bHasKey) { 83 | m_szKey=std::string(m_vBuffer.begin(), m_vBuffer.end()); 84 | m_vBuffer.clear(); 85 | m_bHasKey=true; 86 | } 87 | std::string szValue(m_vBuffer.begin(), m_vBuffer.end()); 88 | m_mValues[m_szKey]=szValue; 89 | 90 | m_vBuffer.clear(); 91 | m_bHasKey = false; 92 | 93 | // Start output 94 | m_szOutput = ""; 95 | m_szOutput += "Saving..."; 96 | m_szOutput += ""; 97 | m_szOutput += ""; 98 | 99 | // Write out config 100 | const uint8_t pHeader[] = CONFIG_HEADER; 101 | m_pWriter = new CConfigWriter(CONFIG_START_SECTOR, CONFIG_SECTOR_DIRECTION); 102 | m_pWriter->writeBytes(pHeader,sizeof(pHeader)); // Header 103 | config_run(this); 104 | m_pWriter->writeUInt(ConfigSectionEnd); 105 | m_pWriter->flush(true); 106 | delete m_pWriter; 107 | 108 | m_szOutput += "

Please wait for the unit to reboot...

"; 109 | 110 | m_szOutput += ""; 111 | 112 | pRequest->startHeaders(200,"OK"); 113 | pRequest->sendHeader("Content-Type", "text/html"); 114 | pRequest->sendHeader("Content-Length", m_szOutput.length()); 115 | pRequest->sendHeader("Refresh","3;url=/"); 116 | pRequest->endHeaders(); 117 | pRequest->sendData((const uint8_t *)m_szOutput.c_str(), m_szOutput.length()); 118 | } 119 | 120 | void CConfigPostHandler::onSent(CHttpRequest *pRequest) { 121 | pRequest->end(false); 122 | } 123 | 124 | void CConfigPostHandler::onDisconnected(CHttpRequest *pRequest) { 125 | delete this; 126 | system_restart(); 127 | } 128 | 129 | std::string CConfigPostHandler::createOptionKey(const char *szName) { 130 | std::string strRetval; 131 | for (auto section : m_lSections) { 132 | strRetval += section; 133 | strRetval += "."; 134 | } 135 | strRetval+=szName; 136 | return strRetval; 137 | } 138 | 139 | void CConfigPostHandler::beginModule(const char *szName, const char *szDescription) { 140 | m_pWriter->writeUInt(ConfigSectionStart); 141 | m_pWriter->writeString(szName); 142 | m_lSections.push_back(szName); 143 | } 144 | 145 | void CConfigPostHandler::endModule() { 146 | m_pWriter->writeUInt(ConfigSectionEnd); 147 | if (!m_lSections.empty()) 148 | m_lSections.pop_back(); 149 | } 150 | 151 | void CConfigPostHandler::optionBool(const char *szName, const char *szDescription, bool *pbValue, bool bDefault) { 152 | const auto found = m_mValues.find(createOptionKey(szName)); 153 | bool bValue = (found != m_mValues.end() && found->second.compare("1") == 0); 154 | if (bValue != bDefault) { 155 | m_pWriter->writeUInt(ConfigInteger); 156 | m_pWriter->writeString(szName); 157 | m_pWriter->writeUInt(bValue?1:0); 158 | } 159 | } 160 | 161 | void CConfigPostHandler::optionString(const char *szName, const char *szDescription, char *szValue, size_t nSize, const char *szDefault) { 162 | const auto found = m_mValues.find(createOptionKey(szName)); 163 | if (found != m_mValues.end() && found->second.compare(szDefault)!=0) { 164 | std::string capped(found->second); 165 | if (capped.length() + 1 > nSize) 166 | capped=capped.substr(0,nSize-1); 167 | m_pWriter->writeUInt(ConfigString); 168 | m_pWriter->writeString(szName); 169 | m_pWriter->writeString(capped.c_str()); 170 | } 171 | } 172 | 173 | void CConfigPostHandler::optionInt(const char *szName, const char *szDescription, void *pValue, size_t nSize, uint32_t nMin, uint32_t nMax, uint32_t nDefault) { 174 | auto found = m_mValues.find(createOptionKey(szName)); 175 | if (found != m_mValues.end()) { 176 | uint32_t nValue = atoi(found->second.c_str()); 177 | if (nValue < nMin) 178 | nValue = nMin; 179 | if (nValue > nMax) 180 | nValue = nMax; 181 | if (nValue != nDefault) { 182 | m_pWriter->writeUInt(ConfigInteger); 183 | m_pWriter->writeString(szName); 184 | m_pWriter->writeUInt(nValue); 185 | } 186 | } 187 | } 188 | void CConfigPostHandler::optionSelectBegin(const char *szName, const char *szDescription, unsigned int* pnValue, unsigned int nDefault) { 189 | auto found = m_mValues.find(createOptionKey(szName)); 190 | if (found != m_mValues.end()) { 191 | unsigned int nValue = atoi(found->second.c_str()); 192 | if (nValue != nDefault) { 193 | m_pWriter->writeUInt(ConfigInteger); 194 | m_pWriter->writeString(szName); 195 | m_pWriter->writeUInt(nValue); 196 | } 197 | } 198 | } 199 | void CConfigPostHandler::optionSelectItem(const char *szName, unsigned int nValue) { 200 | 201 | } 202 | void CConfigPostHandler::optionSelectEnd() { 203 | } 204 | void CConfigPostHandler::optionIpAddress(const char *szName, const char *szDescription, uint32_t *pAddress, uint32_t nDefault) { 205 | std::string szBaseKey(createOptionKey(szName)); 206 | char szSuffix[]="[0]"; 207 | uint32_t nValue = 0; 208 | for (unsigned int i=0; i<4; i++) { 209 | szSuffix[1] = '0' + i; 210 | auto found = m_mValues.find(szBaseKey + szSuffix); 211 | if (found != m_mValues.end()) 212 | nValue |= ((unsigned int)atoi(found->second.c_str()) & 0xFF) << (i*8); 213 | } 214 | if (nValue != nDefault) { 215 | m_pWriter->writeUInt(ConfigInteger); 216 | m_pWriter->writeString(szName); 217 | m_pWriter->writeUInt(nValue); 218 | } 219 | } 220 | void CConfigPostHandler::optionFloat(const char *szName, const char *szDescription, float* pfValue, float fDefault) { 221 | auto found = m_mValues.find(createOptionKey(szName)); 222 | if (found != m_mValues.end()) { 223 | float fValue = eln_atof(found->second.c_str()); 224 | if (fValue != fDefault) { 225 | m_pWriter->writeUInt(ConfigFloat); 226 | m_pWriter->writeString(szName); 227 | m_pWriter->writeFloat(fValue); 228 | } 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /user/config/CConfigPostHandler.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_CCONFIGPOSTHANDLER_H 2 | #define CONFIG_CCONFIGPOSTHANDLER_H 3 | #include "httpd/CHttpRequest.h" 4 | #include "config/IConfigRunner.h" 5 | #include 6 | #include 7 | 8 | class CConfigWriter; 9 | class CConfigPostHandler : IHttpRequestListener, IConfigRunner { 10 | public: 11 | static bool handle(CHttpRequest* pRequest); 12 | private: 13 | CConfigPostHandler(CHttpRequest* pRequest); 14 | ~CConfigPostHandler(); 15 | //IHttpRequestListener 16 | void onHeader(CHttpRequest *pRequest, const char *szName, const char *szValue); 17 | void onHeadersDone(CHttpRequest *pRequest, size_t nDataLen); 18 | void onData(CHttpRequest *pRequest, const uint8_t *pData, size_t nLength); 19 | void onDataDone(CHttpRequest *pRequest); 20 | void onSent(CHttpRequest *pRequest); 21 | void onDisconnected(CHttpRequest *pRequest); 22 | //IConfigRunner 23 | void beginModule(const char *szName, const char *szDescription); 24 | void endModule(); 25 | void optionBool(const char *szName, const char *szDescription, bool *pbValue, bool bDefault); 26 | void optionString(const char *szName, const char *szDescription, char *szValue, size_t nSize, const char *szDefault); 27 | void optionInt(const char *szName, const char *szDescription, void *pValue, size_t nSize, uint32_t nMin, uint32_t nMax, uint32_t nDefault); 28 | void optionSelectBegin(const char *szName, const char *szDescription, unsigned int* pnValue, unsigned int nDefault); 29 | void optionSelectItem(const char *szName, unsigned int nValue); 30 | void optionSelectEnd(); 31 | void optionIpAddress(const char *szName, const char *szDescription, uint32_t *pAddress, uint32_t nDefault); 32 | void optionFloat(const char *szName, const char *szDescription, float *pfValue, float fDefault); 33 | 34 | std::string createOptionKey(const char *szName); 35 | 36 | 37 | CHttpRequest *m_pRequest; 38 | std::map m_mValues; 39 | CConfigWriter* m_pWriter; 40 | std::string m_szOutput; 41 | std::list m_lSections; 42 | 43 | size_t m_nEscapeLeft; 44 | char m_cEscape; 45 | std::vector m_vBuffer; 46 | std::string m_szKey; 47 | bool m_bHasKey; 48 | }; 49 | #endif//CONFIG_CCONFIGPOSTHANDLER_H 50 | -------------------------------------------------------------------------------- /user/config/CConfigReader.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "CConfigReader.h" 3 | #include 4 | extern "C" { 5 | #include 6 | } 7 | 8 | CConfigReader::CConfigReader(unsigned int nFirstSector, int nDirection) { 9 | m_nCurrentSector = nFirstSector; 10 | m_nDirection = nDirection; 11 | m_nBufferSize = m_nBufferOffset = 0; 12 | m_nOffset = 0; 13 | } 14 | 15 | uint8_t CConfigReader::readByte() { 16 | if (m_nBufferOffset >= m_nBufferSize) 17 | fillBuffer(); 18 | return m_bBuffer[m_nBufferOffset++]; 19 | } 20 | 21 | void CConfigReader::readBytes(uint8_t* pBytes, size_t nLength) { 22 | while (nLength) { 23 | if (m_nBufferOffset >= m_nBufferSize) 24 | fillBuffer(); 25 | size_t nAvailable = std::min(nLength, m_nBufferSize-m_nBufferOffset); 26 | memcpy(pBytes, &m_bBuffer[m_nBufferOffset], nAvailable); 27 | m_nBufferOffset += nAvailable; 28 | nLength -= nAvailable; 29 | pBytes = &pBytes[nAvailable]; 30 | } 31 | } 32 | 33 | void CConfigReader::fillBuffer() { 34 | // Discard all already-read bytes, but ensure that the number of kept bytes is divisible by uint32_t 35 | ptrdiff_t nDiscard = m_nBufferOffset; 36 | if ((m_nBufferSize - nDiscard) % sizeof(uint32_t) != 0) 37 | nDiscard -= sizeof(uint32_t) - ((m_nBufferSize - nDiscard) % sizeof(uint32_t)); 38 | if (nDiscard >= 0) 39 | memmove(m_bBuffer, &m_bBuffer[nDiscard], m_nBufferSize - nDiscard); 40 | else 41 | memmove(&m_bBuffer[-nDiscard], &m_bBuffer, m_nBufferSize); 42 | m_nBufferSize -= nDiscard; 43 | m_nBufferOffset -= nDiscard; 44 | 45 | // Possibly skip to next sector 46 | if (m_nOffset >= SPI_FLASH_SEC_SIZE) { 47 | m_nOffset = 0; 48 | m_nCurrentSector += m_nDirection; 49 | } 50 | // How much can we read? 51 | size_t nSpace = std::min(sizeof(m_bBuffer)-m_nBufferSize, SPI_FLASH_SEC_SIZE - m_nOffset); 52 | nSpace -= nSpace % sizeof(uint32_t); 53 | if (!nSpace) 54 | return; 55 | 56 | spi_flash_read((m_nCurrentSector * SPI_FLASH_SEC_SIZE) + m_nOffset, (uint32_t *)&m_bBuffer[m_nBufferSize], nSpace); 57 | m_nOffset += nSpace; 58 | m_nBufferSize += nSpace; 59 | } 60 | 61 | unsigned int CConfigReader::readUInt() { 62 | unsigned int nRetval = 0; 63 | unsigned int nShift = 0; 64 | uint8_t nBit; 65 | do { 66 | nBit = readByte(); 67 | nRetval |= (unsigned int)(nBit & 0x7F) << nShift; 68 | nShift += 7; 69 | } while (nBit & 0x80); 70 | return nRetval; 71 | } 72 | 73 | std::string CConfigReader::readString() { 74 | unsigned int nLength = readUInt(); 75 | std::string szRetval(nLength,' '); 76 | readBytes((uint8_t *)szRetval.data(), nLength); 77 | return szRetval; 78 | } 79 | 80 | float CConfigReader::readFloat() { 81 | float fValue; 82 | readBytes((uint8_t*)&fValue, sizeof(float)); 83 | return fValue; 84 | } 85 | -------------------------------------------------------------------------------- /user/config/CConfigReader.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_CCONFIGREADER_H 2 | #define CONFIG_CCONFIGREADER_H 3 | #include 4 | #include 5 | #include 6 | 7 | class CConfigReader { 8 | public: 9 | CConfigReader(unsigned int nFirstSector, int nDirection); 10 | uint8_t readByte(); 11 | void readBytes(uint8_t* pBytes, size_t nLength); 12 | void skip(size_t nLength); 13 | unsigned int readUInt(); 14 | std::string readString(); 15 | float readFloat(); 16 | private: 17 | unsigned int m_nCurrentSector; 18 | int m_nDirection; 19 | unsigned int m_nOffset; 20 | uint8_t m_bBuffer[64]; 21 | size_t m_nBufferSize; 22 | size_t m_nBufferOffset; 23 | 24 | void fillBuffer(); 25 | }; 26 | #endif//CONFIG_CCONFIGREADER_H 27 | 28 | -------------------------------------------------------------------------------- /user/config/CConfigSection.cpp: -------------------------------------------------------------------------------- 1 | #include "CConfigSection.h" 2 | #include "config/CConfigReader.h" 3 | #include "config/format.h" 4 | #include "string.h" 5 | 6 | CConfigSection::CConfigSection() { 7 | } 8 | 9 | CConfigSection::~CConfigSection() { 10 | for (auto i : m_mSubSections) 11 | delete i.second; 12 | } 13 | 14 | bool CConfigSection::read(CConfigReader *pReader) { 15 | while (true) { 16 | switch (pReader->readUInt()) { 17 | case ConfigSectionEnd:{ 18 | return true; 19 | } 20 | case ConfigSectionStart:{ 21 | std::string szName(pReader->readString()); 22 | CConfigSection *pSubSection = new CConfigSection(); 23 | if (!pSubSection->read(pReader)) { 24 | delete pSubSection; 25 | return false; 26 | } 27 | auto found = m_mSubSections.find(szName); 28 | if (found != m_mSubSections.end()) { 29 | delete found->second; 30 | found->second = pSubSection; 31 | } else { 32 | m_mSubSections[szName] = pSubSection; 33 | } 34 | break; 35 | } 36 | case ConfigString:{ 37 | std::string szName(pReader->readString()); 38 | std::string szValue(pReader->readString()); 39 | m_mStrings[szName]=szValue; 40 | break; 41 | } 42 | case ConfigInteger:{ 43 | std::string szName(pReader->readString()); 44 | m_mIntegers[szName] = pReader->readUInt(); 45 | break; 46 | } 47 | case ConfigFloat:{ 48 | std::string szName(pReader->readString()); 49 | m_mFloats[szName] = pReader->readFloat(); 50 | break; 51 | } 52 | } 53 | } 54 | } 55 | 56 | bool CConfigSection::getUInt(const std::string szKey, unsigned int &nValue) { 57 | const auto found = m_mIntegers.find(szKey); 58 | if (found == m_mIntegers.end()) 59 | return false; 60 | nValue = found->second; 61 | return true; 62 | } 63 | 64 | bool CConfigSection::getString(const std::string szKey, char *szString, size_t nSize) { 65 | const auto found = m_mStrings.find(szKey); 66 | if (found == m_mStrings.end()) 67 | return false; 68 | strncpy(szString, found->second.c_str(), nSize-1); 69 | szString[nSize-1]='\0'; 70 | return true; 71 | } 72 | 73 | bool CConfigSection::getString(const std::string szKey, std::string& szValue) { 74 | const auto found = m_mStrings.find(szKey); 75 | if (found == m_mStrings.end()) 76 | return false; 77 | szValue = found->second; 78 | return true; 79 | } 80 | 81 | bool CConfigSection::getSection(const std::string szKey, CConfigSection** ppSection) { 82 | const auto found = m_mSubSections.find(szKey); 83 | if (found == m_mSubSections.end()) 84 | return false; 85 | *ppSection = found->second; 86 | return true; 87 | } 88 | 89 | bool CConfigSection::getFloat(const std::string szKey, float& fValue) { 90 | const auto found = m_mFloats.find(szKey); 91 | if (found == m_mFloats.end()) 92 | return false; 93 | fValue = found->second; 94 | return true; 95 | } 96 | -------------------------------------------------------------------------------- /user/config/CConfigSection.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_CCONFIGSECTION_H 2 | #define CONFIG_CCONFIGSECTION_H 3 | #include 4 | #include 5 | 6 | class CConfigReader; 7 | class CConfigSection { 8 | public: 9 | CConfigSection(); 10 | ~CConfigSection(); 11 | bool read(CConfigReader *pRead); 12 | bool getUInt(const std::string szKey, unsigned int &nValue); 13 | bool getString(const std::string szKey, char *szString, size_t nSize); 14 | bool getString(const std::string szKey, std::string &szValue); 15 | bool getSection(const std::string szKey, CConfigSection** ppSection); 16 | bool getFloat(const std::string szKey, float& fValue); 17 | private: 18 | 19 | std::map m_mIntegers; 20 | std::map m_mStrings; 21 | std::map m_mSubSections; 22 | std::map m_mFloats; 23 | }; 24 | #endif//CONFIG_CCONFIGSECTION_H 25 | -------------------------------------------------------------------------------- /user/config/CConfigWriter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "config/CConfigWriter.h" 3 | extern "C" { 4 | #include 5 | } 6 | #include 7 | #include 8 | 9 | CConfigWriter::CConfigWriter(unsigned int nFirstSector, int nDirection) { 10 | m_nCurrentSector = nFirstSector; 11 | m_nDirection = nDirection; 12 | m_nOffset = 0; 13 | m_nBufferFilled = 0; 14 | } 15 | 16 | bool CConfigWriter::flush(bool bPad) { 17 | size_t nFlushed = 0; 18 | // Possibly pad to 4 bytes, as SPI write always wants at least that. 19 | if (bPad && m_nBufferFilled % sizeof(uint32_t) != 0) { 20 | size_t nPad = sizeof(uint32_t) - (m_nBufferFilled % sizeof(uint32_t)); 21 | memset(&m_bBuffer[m_nBufferFilled], 0, nPad); 22 | m_nBufferFilled += nPad; 23 | } 24 | // Write out as much as possible 25 | while (m_nBufferFilled - nFlushed >= sizeof(uint32_t)) { 26 | size_t nWrite = std::min(SPI_FLASH_SEC_SIZE - m_nOffset, m_nBufferFilled - nFlushed); 27 | nWrite -= nWrite % sizeof(uint32_t); 28 | if (m_nOffset == 0) 29 | spi_flash_erase_sector(m_nCurrentSector); 30 | spi_flash_write((m_nCurrentSector * SPI_FLASH_SEC_SIZE) + m_nOffset, (uint32_t *)&m_bBuffer[nFlushed], nWrite); 31 | m_nOffset += nWrite; 32 | nFlushed += nWrite; 33 | if (m_nOffset >= SPI_FLASH_SEC_SIZE) { 34 | m_nOffset = 0; 35 | m_nCurrentSector += m_nDirection; 36 | } 37 | } 38 | // Move any remaining bits and pieces 39 | m_nBufferFilled -= nFlushed; 40 | memmove(m_bBuffer, &m_bBuffer[nFlushed], m_nBufferFilled); 41 | return (m_nBufferFilled == 0); 42 | } 43 | 44 | void CConfigWriter::writeByte(const uint8_t nByte) { 45 | if (m_nBufferFilled >= sizeof(m_bBuffer)) 46 | flush(false); 47 | m_bBuffer[m_nBufferFilled] = nByte; 48 | m_nBufferFilled++; 49 | } 50 | 51 | void CConfigWriter::writeBytes(const uint8_t* pBytes, size_t nLength) { 52 | while (nLength) { 53 | if (m_nBufferFilled >= sizeof(m_bBuffer)) 54 | flush(false); 55 | size_t nWrite = std::min(nLength, sizeof(m_bBuffer) - m_nBufferFilled); 56 | memcpy(&m_bBuffer[m_nBufferFilled], pBytes, nWrite); 57 | m_nBufferFilled += nWrite; 58 | nLength -= nWrite; 59 | pBytes = &pBytes[nWrite]; 60 | } 61 | } 62 | 63 | void CConfigWriter::writeUInt(unsigned int nValue) { 64 | uint8_t nBit; 65 | do { 66 | nBit = nValue & 0x7F; 67 | nValue >>= 7; 68 | if (nValue) 69 | nBit |= 0x80; 70 | writeByte(nBit); 71 | } while(nBit & 0x80); 72 | } 73 | 74 | void CConfigWriter::writeString(const char* szString) { 75 | size_t nLen = strlen(szString); 76 | writeUInt(nLen); 77 | writeBytes((const uint8_t *)szString, nLen); 78 | } 79 | void CConfigWriter::writeFloat(float fValue) { 80 | writeBytes((const uint8_t *)&fValue, sizeof(float)); 81 | } 82 | -------------------------------------------------------------------------------- /user/config/CConfigWriter.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_CCONFIGWRITER_H 2 | #define CONFIG_CCONFIGWRITER_H 3 | #include 4 | #include 5 | 6 | class CConfigWriter { 7 | public: 8 | // nFirstSector is the sector where writing starts 9 | // nDirection is 1 or -1, depending on which direction should be written. 10 | // e.g. nFirstSector 200 and nDirection 1 would mean that sector 200, 201, 202, ... will be written 11 | // whereas nFirstSector 100 and nDirection -1 would mean 100, 99, 98, 97 12 | CConfigWriter(unsigned int nFirstSector, int nDirection); 13 | bool flush(bool bPad); 14 | void writeByte(const uint8_t nByte); 15 | void writeBytes(const uint8_t* pBytes, size_t nLength); 16 | void writeUInt(unsigned int nValue); 17 | void writeString(const char* szString); 18 | void writeFloat(float fValue); 19 | private: 20 | unsigned int m_nCurrentSector; //Current sector 21 | int m_nDirection; //Which direction to continue after this sector is done 22 | unsigned int m_nOffset; //Offset in current sector 23 | uint8_t m_bBuffer[64]; 24 | size_t m_nBufferFilled; 25 | }; 26 | #endif//CONFIG_CCONFIGWRITER_H 27 | -------------------------------------------------------------------------------- /user/config/IConfigObject.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_ICONFIGOBJECT_H 2 | #define CONFIG_ICONFIGOBJECT_H 3 | #include 4 | 5 | class IConfigObject { 6 | public: 7 | virtual ~IConfigObject() {}; 8 | virtual IConfigObject* findChild(const char* szName) = 0; 9 | virtual bool getUint(unsigned int* pnValue) = 0; 10 | virtual bool getString(const char* szValue, size_t nLen) = 0; 11 | }; 12 | #endif//CONFIG_ICONFIGOBJECT_H 13 | -------------------------------------------------------------------------------- /user/config/IConfigRunner.cpp: -------------------------------------------------------------------------------- 1 | #include "IConfigRunner.h" 2 | 3 | //Stub implementations 4 | IConfigRunner::~IConfigRunner() { 5 | } 6 | void IConfigRunner::beginModule(const char *szName, const char *szDescription) { 7 | } 8 | void IConfigRunner::endModule() { 9 | } 10 | void IConfigRunner::optionBool(const char *szName, const char *szDescription, bool *pValue, bool bDefault) { 11 | } 12 | void IConfigRunner::optionString(const char *szName, const char *szDescription, char *szValue, size_t nSize, const char *szDefault) { 13 | } 14 | void IConfigRunner::optionInt(const char *szName, const char *szDescription, void *pValue, size_t nSize, uint32_t nMin, uint32_t nMax, uint32_t nDefault) { 15 | } 16 | void IConfigRunner::optionSelectBegin(const char *szName, const char *szDescription, unsigned int* pnValue, unsigned int nDefault) { 17 | } 18 | void IConfigRunner::optionSelectItem(const char *szName, unsigned int nValue) { 19 | } 20 | void IConfigRunner::optionSelectEnd() { 21 | } 22 | void IConfigRunner::optionIpAddress(const char *szName, const char *szDescription, uint32_t* pAddress, uint32_t nDefault) { 23 | } 24 | void IConfigRunner::optionFloat(const char *szName, const char *szDescription, float* pfValue, float fDefault) { 25 | } 26 | -------------------------------------------------------------------------------- /user/config/IConfigRunner.h: -------------------------------------------------------------------------------- 1 | #ifndef ICONFIGRUNNER_H 2 | #define ICONFIGRUNNER_H 3 | #include 4 | #include 5 | class IConfigRunner { 6 | public: 7 | virtual ~IConfigRunner(); 8 | virtual void beginModule(const char *szName, const char *szDescription); 9 | virtual void endModule(); 10 | virtual void optionBool(const char *szName, const char *szDescription, bool *pbValue, bool bDefault); 11 | virtual void optionString(const char *szName, const char *szDescription, char *szValue, size_t nSize, const char *szDefault); 12 | virtual void optionInt(const char *szName, const char *szDescription, void *pValue, size_t nSize, uint32_t nMin, uint32_t nMax, uint32_t nDefault); 13 | virtual void optionSelectBegin(const char *szName, const char *szDescription, unsigned int* pnValue, unsigned int nDefault); 14 | virtual void optionSelectItem(const char *szName, unsigned int nValue); 15 | virtual void optionSelectEnd(); 16 | virtual void optionIpAddress(const char *szName, const char *szDescription, uint32_t* pAddress, uint32_t nDefault); 17 | virtual void optionFloat(const char *szName, const char *szDescription, float* pfValue, float fDefault); 18 | }; 19 | #endif//ICONFIGRUNNER_H 20 | -------------------------------------------------------------------------------- /user/config/config.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * config.c 3 | * 4 | * Created on: Nov 19, 2014 5 | * Author: frans-willem 6 | */ 7 | #include 8 | extern "C" { 9 | #include 10 | #include 11 | } 12 | #include "config.h" 13 | #include 14 | #include 15 | #include "CConfigHtmlGenerator.h" 16 | #include 17 | #include "httpd/CHttpServer.h" 18 | #include "config/CConfigPostHandler.h" 19 | #include "config/CConfigLoader.h" 20 | #include "output_protocols/output.h" 21 | #include "input_protocols/tpm2net.h" 22 | 23 | DEFINE_CONFIG(artnet); 24 | DEFINE_CONFIG(wifi); 25 | DEFINE_CONFIG(network); 26 | 27 | void config_run(IConfigRunner *_configrunner) { 28 | CONFIG_SUB(wifi); 29 | CONFIG_SUB(network); 30 | CONFIG_SUB(Output::config); 31 | CONFIG_SUB(artnet); 32 | CONFIG_SUB(tpm2net::config); 33 | } 34 | 35 | void config_load() { 36 | CConfigLoader::load(); 37 | } 38 | 39 | class CConfigHttpServerListener : IHttpServerListener { 40 | public: 41 | static void attach(CHttpServer *pServer) { 42 | if (m_gInstance == NULL) 43 | m_gInstance = new CConfigHttpServerListener(); 44 | pServer->addListener(m_gInstance); 45 | } 46 | static void detach(CHttpServer *pServer) { 47 | pServer->removeListener(m_gInstance); 48 | } 49 | private: 50 | static CConfigHttpServerListener* m_gInstance; 51 | 52 | bool onRequest(CHttpServer *pServer, CHttpRequest *pRequest) { 53 | std::string szUri = pRequest->getUri(); 54 | if (szUri.compare("/") == 0 || szUri.compare("/index.html")==0) { 55 | CConfigHtmlGenerator::handle(pRequest); 56 | return true; 57 | } 58 | if (szUri.compare("/submit.cgi") == 0) { 59 | CConfigPostHandler::handle(pRequest); 60 | return true; 61 | } 62 | return false; 63 | } 64 | 65 | }; 66 | CConfigHttpServerListener* CConfigHttpServerListener::m_gInstance = NULL; 67 | 68 | void config_init(CHttpServer *pServer) { 69 | CConfigHttpServerListener::attach(pServer); 70 | } 71 | 72 | -------------------------------------------------------------------------------- /user/config/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * config.h 3 | * 4 | * Created on: Nov 19, 2014 5 | * Author: frans-willem 6 | */ 7 | 8 | #ifndef CONFIG_CONFIG_H_ 9 | #define CONFIG_CONFIG_H_ 10 | #include "IConfigRunner.h" 11 | 12 | class CHttpServer; 13 | class CHttpRequest; 14 | void config_load(); 15 | void config_run(IConfigRunner *pRunner); 16 | void config_init(CHttpServer *pServer); 17 | 18 | #define DEFINE_CONFIG(module) void module ## _runconfig(IConfigRunner *_configrunner); 19 | 20 | #define BEGIN_CONFIG(module, name, description) void module ## _runconfig(IConfigRunner *_configrunner) { _configrunner->beginModule(name , description); 21 | #define END_CONFIG() _configrunner->endModule(); } 22 | 23 | #define CONFIG_SUB(name) name ## _runconfig(_configrunner) 24 | #define CONFIG_BOOLEAN(name, description, address, defvalue) _configrunner->optionBool(name, description, address, defvalue) 25 | #define CONFIG_STRING(name, description, address, len, defvalue) _configrunner->optionString(name, description, address, len, defvalue) 26 | #define CONFIG_INT(name, description, address, min, max, defvalue) _configrunner->optionInt(name, description, address, sizeof(*(address)), min, max, defvalue) 27 | #define CONFIG_SELECTSTART(name, description, address, defvalue) _configrunner->optionSelectBegin(name, description, address, defvalue) 28 | #define CONFIG_SELECTOPTION(name, value) _configrunner->optionSelectItem(name, value) 29 | #define CONFIG_SELECTEND() _configrunner->optionSelectEnd() 30 | #define CONFIG_IP(name, description, address, a, b, c, d) _configrunner->optionIpAddress(name,description,address,a | (b << 8) | (c << 16) | (d << 24)) 31 | #define CONFIG_FLOAT(name, description, address, def) _configrunner->optionFloat(name, description, address, def) 32 | 33 | #endif /* CONFIG_CONFIG_H_ */ 34 | -------------------------------------------------------------------------------- /user/config/format.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_FORMAT_H 2 | #define CONFIG_FORMAT_H 3 | 4 | #define CONFIG_START_SECTOR 63 5 | #define CONFIG_SECTOR_DIRECTION -1 6 | 7 | #define CONFIG_HEADER "ELN0" 8 | 9 | enum ConfigCommand { 10 | ConfigSectionStart, 11 | ConfigSectionEnd, 12 | ConfigString, 13 | ConfigInteger, 14 | ConfigFloat 15 | }; 16 | 17 | #endif//CONFIG_FORMAT_H 18 | -------------------------------------------------------------------------------- /user/cppcompat.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | extern "C" { 3 | #include 4 | } 5 | #include 6 | 7 | void* operator new(std::size_t size) { 8 | return os_zalloc(size); 9 | }; 10 | 11 | void operator delete(void *ptr) { 12 | os_free(ptr); 13 | return; 14 | } 15 | 16 | extern "C" void __cxa_pure_virtual() { 17 | while (1); 18 | } 19 | 20 | // These make no sense at all on ESP8266, but just in case something links to it here are stubs 21 | extern "C" void _write_r() { while(1); } 22 | extern "C" void _read_r() { while(1); } 23 | extern "C" void _fstat_r() { while(1); } 24 | extern "C" void _open_r() { while(1); } 25 | extern "C" void _close_r() { while(1); } 26 | extern "C" void _lseek_r() { while(1); } 27 | 28 | // Stub 29 | extern "C" void abort() { 30 | while (1); 31 | } 32 | 33 | // All different versions of malloc, free, realloc, etc 34 | extern "C" void* _malloc_r(struct _reent *ignored __attribute__((unused)), 35 | size_t size) { 36 | return os_zalloc(size); 37 | } 38 | 39 | extern "C" void _free_r(struct _reent *ignore __attribute__((unused)), void *ptr) { 40 | return os_free(ptr); 41 | } 42 | 43 | extern "C" void* _calloc_r(struct _reent *ignored __attribute((unused)), size_t x, size_t y) { 44 | return os_zalloc(x*y); 45 | } 46 | 47 | extern "C" void* _realloc_r(struct _rrent *ignore __attribute__((unused)), void *ptr, size_t size) { 48 | os_free(ptr); 49 | return os_zalloc(size); 50 | } 51 | 52 | extern "C" void* malloc(size_t size) { 53 | return os_zalloc(size); 54 | } 55 | 56 | extern "C" void free(void *ptr) { 57 | return os_free(ptr); 58 | } 59 | 60 | extern "C" void* realloc(void *ptr, size_t size) { 61 | os_free(ptr); 62 | return os_zalloc(size); 63 | } 64 | 65 | // Relatively 'big' functions that are implemented in ROM, 66 | // We save space by redirecting to the ROM versions. 67 | extern "C" void *memcpy(void *dest, const void *src, size_t n) { 68 | return ets_memcpy(dest, src, n); 69 | } 70 | 71 | // strcpy, strncpy, strlen, memset are already provided by ESP8266 linker script 72 | -------------------------------------------------------------------------------- /user/debug/CDebugServer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "CDebugServer.h" 4 | #include 5 | 6 | CDebugServer* CDebugServer::g_pInstance = 0; 7 | 8 | CDebugServer* CDebugServer::get() { 9 | if (!g_pInstance) 10 | g_pInstance = new CDebugServer(8888); 11 | return g_pInstance; 12 | } 13 | 14 | CDebugServer::CDebugServer(int nPort) : m_cServer(nPort) { 15 | m_cServer.addListener(this); 16 | m_cServer.setTimeout(0); 17 | } 18 | 19 | void CDebugServer::send(const char *szFormat, ...) { 20 | static char szTemp[512]; 21 | va_list args; 22 | __builtin_va_start(args, szFormat); 23 | ets_vsnprintf(szTemp, (sizeof(szTemp)/sizeof(szTemp[0])) -1, szFormat, args); 24 | __builtin_va_end(args); 25 | for (auto s : m_sSockets) 26 | s->send((const uint8_t *)szTemp, strlen(szTemp)); 27 | } 28 | 29 | void CDebugServer::onConnection(CTcpSocket *pSocket) { 30 | m_sSockets.insert(pSocket); 31 | pSocket->addListener(this); 32 | pSocket->setTimeout(0); 33 | DEBUG("New connection (%08X)", pSocket); 34 | DEBUG("Lost connections: %d", m_nLostConnections); 35 | } 36 | 37 | void CDebugServer::onSocketRecv(CTcpSocket *pSocket, const uint8_t *pData, size_t nLen) { 38 | //Do nothing 39 | } 40 | 41 | void CDebugServer::onSocketDisconnected(CTcpSocket *pSocket) { 42 | m_sSockets.erase(pSocket); 43 | pSocket->removeListener(this); 44 | DEBUG("Lost connection (%08X)", pSocket); 45 | m_nLostConnections++; 46 | } 47 | 48 | void CDebugServer::onSocketSent(CTcpSocket *pSocket) { 49 | 50 | } 51 | -------------------------------------------------------------------------------- /user/debug/CDebugServer.h: -------------------------------------------------------------------------------- 1 | #ifndef DEBUG_CDEBUGSERVER_H 2 | #define DEBUG_CDEBUGSERVER_H 3 | #include "httpd/CTcpServer.h" 4 | #include "httpd/CTcpSocket.h" 5 | #include 6 | 7 | #define DEBUG(f,args...) CDebugServer::get()->send("%s:%d: " f "\r\n", __FILE__, __LINE__, ##args) 8 | 9 | class CDebugServer : ITcpServerListener, ITcpSocketListener { 10 | public: 11 | static CDebugServer* get(); 12 | void send(const char *szFormat, ...); 13 | private: 14 | CDebugServer(int nPort); 15 | 16 | static CDebugServer *g_pInstance; 17 | CTcpServer m_cServer; 18 | std::set m_sSockets; 19 | unsigned int m_nLostConnections; 20 | 21 | // ITcpServerListener 22 | void onConnection(CTcpSocket *pSocket); 23 | 24 | // ITcpSocketListener 25 | void onSocketRecv(CTcpSocket *pSocket, const uint8_t *pData, size_t nLen); 26 | void onSocketDisconnected(CTcpSocket *pSocket); 27 | void onSocketSent(CTcpSocket *pSocket); 28 | }; 29 | #endif//DEBUG_CDEBUGSERVER_H 30 | -------------------------------------------------------------------------------- /user/helpers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "helpers.h" 3 | extern "C" { 4 | #include 5 | } 6 | 7 | float eln_atof(const char *nptr) { 8 | float fRetval = 0.0f; 9 | float fMulti = 1.0f; 10 | float fSign = 1.0f; 11 | if (*nptr == '-') 12 | fSign = -1.0f; 13 | bool bAfterComma = false; 14 | for (; *nptr != '\0'; nptr++) { 15 | if (*nptr >= '0' && *nptr <= '9') { 16 | if (bAfterComma) { 17 | fMulti /= 10.0f; 18 | fRetval += fMulti * (float)(*nptr - '0'); 19 | } else { 20 | fRetval *= 10.0f; 21 | fRetval += (float)(*nptr - '0'); 22 | } 23 | } else if (*nptr == '.' || *nptr == ',') { 24 | bAfterComma = true; 25 | } 26 | } 27 | fRetval *= fSign; 28 | return fRetval; 29 | } 30 | 31 | void eln_ftoa(float fValue, char *ptr, size_t max) { 32 | if (max == 0) return; 33 | if (max < 3) { 34 | *ptr = '\0'; 35 | return; 36 | } 37 | if (fValue < 0.0f) { 38 | *ptr = '-'; 39 | eln_ftoa(0.0f-fValue,&ptr[1],max - 1); 40 | return; 41 | } 42 | int nInt = (int)fValue; 43 | int nWritten = ets_snprintf(ptr,max-2,"%d",nInt); 44 | ptr[nWritten]='.'; 45 | nWritten++; 46 | do { 47 | fValue = (fValue - nInt) * 10.0f; 48 | nInt = (int)fValue; 49 | ptr[nWritten] = '0' + nInt; 50 | nWritten++; 51 | } while (fValue > (float)nInt && nWritten + 1 < max); 52 | ptr[nWritten] = '\0'; 53 | } 54 | 55 | int ets_snprintf(char *str, size_t size, const char *format, ...) { 56 | va_list args; 57 | __builtin_va_start(args, format); 58 | int retval = ets_vsnprintf(str, size, format, args); 59 | __builtin_va_end(args); 60 | return retval; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /user/helpers.h: -------------------------------------------------------------------------------- 1 | #ifndef HELPERS_H 2 | #define HELPERS_H 3 | //Custom atof implementation, as atof on newlib pulls in a shitload of dependencies. 4 | float eln_atof(const char *nptr); 5 | void eln_ftoa(float fValue, char *ptr, size_t max); 6 | int ets_snprintf(char *str, size_t size, const char *format, ...); 7 | #endif//HELPERS_H 8 | -------------------------------------------------------------------------------- /user/httpd/CHttpRequest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "CHttpRequest.h" 3 | #include "CHttpServer.h" 4 | #include 5 | extern "C" { 6 | #include 7 | } 8 | #include 9 | #include "debug/CDebugServer.h" 10 | #include 11 | 12 | CHttpRequest::CHttpRequest(CHttpServer *pOwner, CTcpSocket *pSocket) { 13 | m_pOwner = pOwner; 14 | m_pSocket = pSocket; 15 | m_pSocket->addListener(this); 16 | m_nRef = 1; 17 | DEBUG("CHttpRequest::CHttpRequest(); = %08X", this); 18 | } 19 | CHttpRequest::~CHttpRequest() { 20 | if (m_pSocket) 21 | m_pSocket->removeListener(this); 22 | DEBUG("CHttpRequest::~CHttpRequest(%08X);", this); 23 | } 24 | 25 | void CHttpRequest::addRef() { 26 | m_nRef++; 27 | } 28 | 29 | void CHttpRequest::release() { 30 | if (--m_nRef == 0) 31 | delete this; 32 | } 33 | 34 | void CHttpRequest::addListener(IHttpRequestListener *pListener) { 35 | if (m_sListeners.insert(pListener).second) 36 | addRef(); 37 | } 38 | 39 | void CHttpRequest::removeListener(IHttpRequestListener *pListener) { 40 | if (m_sListeners.erase(pListener) > 0) 41 | release(); 42 | } 43 | 44 | std::string CHttpRequest::getUri() { 45 | return m_szUri; 46 | } 47 | 48 | void CHttpRequest::onSocketRecv(CTcpSocket *pSocket, const uint8_t *pData, size_t nLen) { 49 | if (m_bHadError) 50 | return; 51 | while (nLen) { 52 | if (m_bHeadersDone) { 53 | DEBUG("Data after headers, %d bytes, %d left", nLen, m_nDataLeft); 54 | nLen = std::min(nLen, m_nDataLeft); 55 | m_nDataLeft -= nLen; 56 | if (nLen > 0) { 57 | for (auto listener : m_sListeners) 58 | listener->onData(this, pData, nLen); 59 | if (m_nDataLeft == 0) 60 | dispatchDataDone(); 61 | } 62 | return; 63 | } 64 | size_t nProcess = std::min(HTTP_BUFFER_SIZE - m_nBufferFilled, nLen); 65 | if (nProcess == 0) { 66 | onError(431,"Request Header Fields Too Large","Request Header Fields Too Large"); 67 | return; 68 | } 69 | memcpy(&m_pBuffer[m_nBufferFilled], pData, nProcess); 70 | m_nBufferFilled += nProcess; 71 | nLen -= nProcess; 72 | pData = &pData[nProcess]; 73 | if (!process()) { 74 | onError(400,"Bad Request","Unknown error occured by bad request"); 75 | } 76 | } 77 | } 78 | 79 | void CHttpRequest::onSocketDisconnected(CTcpSocket *pSocket) { 80 | DEBUG("CHttpRequest::onSocketDisconnected(%08X)",this); 81 | std::set sCopy(m_sListeners); 82 | //Remove all listeners at this point. 83 | m_sListeners.clear(); 84 | addRef(); 85 | for (auto listener : sCopy) { 86 | listener->onDisconnected(this); 87 | release(); 88 | } 89 | 90 | if (m_pSocket) { 91 | m_pSocket=(CTcpSocket*)NULL; 92 | release(); 93 | } 94 | release(); 95 | } 96 | 97 | void CHttpRequest::onSocketSent(CTcpSocket *pSocket) { 98 | if (m_bHadError) { 99 | pSocket->disconnect(true); 100 | } 101 | for (auto listener : m_sListeners) 102 | listener->onSent(this); 103 | } 104 | 105 | bool CHttpRequest::process() { 106 | if (m_bHadError) 107 | return false; 108 | size_t nProcessed, nOldProcessed; 109 | nProcessed = 0; 110 | do { 111 | nOldProcessed = nProcessed; 112 | 113 | if (m_bHeadersDone) { 114 | if (m_nDataLeft > 0) { 115 | size_t nProcess = std::min(m_nBufferFilled - nProcessed, m_nDataLeft); 116 | m_nDataLeft -= nProcess; 117 | for (auto listener : m_sListeners) 118 | listener->onData(this, &m_pBuffer[nProcessed], nProcess); 119 | if (m_nDataLeft == 0) 120 | dispatchDataDone(); 121 | } 122 | return true; 123 | } 124 | size_t nEndLine=nProcessed; 125 | while (m_pBuffer[nEndLine] != '\n' && nEndLine < m_nBufferFilled) 126 | nEndLine++; 127 | if (nEndLine < m_nBufferFilled) { 128 | size_t nNextLine = nEndLine+1; 129 | if (nEndLine > 0 && m_pBuffer[nEndLine-1] == '\r') 130 | nEndLine--; 131 | m_pBuffer[nEndLine]='\0'; 132 | if (!processHeader((char *)&m_pBuffer[nProcessed], nEndLine-nProcessed)) { 133 | onError(400, "Bad Request", "Bad Request"); 134 | return false; 135 | } 136 | nProcessed = nNextLine; 137 | } 138 | } while (nOldProcessed != nProcessed); 139 | //Save rest 140 | m_nBufferFilled -= nProcessed; 141 | memmove(m_pBuffer, &m_pBuffer[nProcessed], m_nBufferFilled); 142 | return true; 143 | } 144 | 145 | bool CHttpRequest::processHeader(char *szHeader, size_t nLength) { 146 | if (m_bHadError) 147 | return false; 148 | if (m_szUri.empty()) { 149 | size_t nSpaces[4]; 150 | size_t nNumSpaces=0; 151 | for (size_t i=0; i < nLength && nNumSpaces < 3; i++) { 152 | if (szHeader[i] == ' ') 153 | nSpaces[nNumSpaces++] = i; 154 | } 155 | // Set end as last "space" to easy calculation 156 | nSpaces[nNumSpaces] = nLength; 157 | if (nNumSpaces < 2) { 158 | onError(400, "Bad Request", "Invalid number of parts to VERB"); 159 | return false; 160 | } 161 | if (nSpaces[0] == 3 && memcmp(szHeader,"GET",3)==0) { 162 | m_vVerb = VERB_GET; 163 | } else if (nSpaces[0] == 4 && memcmp(szHeader,"POST",4)==0) { 164 | m_vVerb = VERB_POST; 165 | } else { 166 | onError(400, "Bad Request", "Invalid verb"); 167 | return false; 168 | } 169 | 170 | size_t nUriLength = (nSpaces[1] - nSpaces[0])-1; 171 | if (nUriLength == 0) { 172 | onError(400, "Bad Request", "Empty URI"); 173 | return false; 174 | } 175 | m_szUri = std::string(&szHeader[nSpaces[0]+1], nUriLength); 176 | //Trigger onRequest on the server 177 | m_pOwner->onRequest(this); 178 | return true; 179 | } else if (nLength == 0) { 180 | m_bHeadersDone = true; 181 | for (auto listener : m_sListeners) 182 | listener->onHeadersDone(this, m_nDataLeft); 183 | if (m_nDataLeft == 0) 184 | dispatchDataDone(); 185 | return true; 186 | } else { 187 | size_t nSplit; 188 | for (nSplit=0; szHeader[nSplit] != ':' && nSplit < nLength; nSplit++); 189 | const char *szName; 190 | const char *szValue; 191 | if (nSplit == nLength) { 192 | szName = szHeader; 193 | szValue = ""; 194 | } else { 195 | szHeader[nSplit]='\0'; 196 | szHeader[nLength]='\0'; 197 | size_t nValueStart = nSplit+1; 198 | while (nValueStart < nLength && szHeader[nValueStart] != ' ') 199 | nValueStart++; 200 | szName = szHeader; 201 | szValue = &szHeader[nValueStart]; 202 | } 203 | if (strcasecmp(szName,"Content-Length") == 0) { 204 | m_nDataLeft = 0; 205 | for (const char *i = szValue; i < &szHeader[nLength]; i++) { 206 | m_nDataLeft *= 10; 207 | if (*i >= '0' && *i <= '9') 208 | m_nDataLeft += (*i)-'0'; 209 | } 210 | DEBUG("Content-Length: %d %s", m_nDataLeft,szValue); 211 | } 212 | for (auto listener : m_sListeners) 213 | listener->onHeader(this, szName, szValue); 214 | return true; 215 | } 216 | onError(400,"bad request","unknown error"); 217 | return false; 218 | } 219 | 220 | void CHttpRequest::onError(unsigned int nCode, const char *szType, const char *szDescription) { 221 | if (m_bHadError) 222 | return; 223 | m_bHadError = true; 224 | startHeaders(nCode, szType); 225 | sendHeader("Content-Length", strlen(szDescription)); 226 | sendHeader("Content-Type", "text/plain"); 227 | sendData(szDescription); 228 | end(false); 229 | } 230 | 231 | bool CHttpRequest::startHeaders(unsigned int nCode, const char *szMessage) { 232 | if (m_bResponseStarted || !m_pSocket) 233 | return false; 234 | m_bResponseStarted = true; 235 | static char szTemp[512]; 236 | ets_sprintf(szTemp,"HTTP/1.0 %d %s\r\n",nCode,szMessage); 237 | return m_pSocket->send((uint8_t *)szTemp, strlen(szTemp)); 238 | } 239 | 240 | bool CHttpRequest::sendHeader(const char *szName, const char *szValue) { 241 | if (m_bHeadersSent || !m_bResponseStarted || !m_pSocket) 242 | return false; 243 | int nNameLen=strlen(szName); 244 | int nValueLen=strlen(szValue); 245 | char *szTemp = new char[nNameLen + 2 + nValueLen + 2]; 246 | memcpy(szTemp,szName,nNameLen); 247 | memcpy(&szTemp[nNameLen],": ",2); 248 | memcpy(&szTemp[nNameLen+2],szValue,nValueLen); 249 | memcpy(&szTemp[nNameLen+2+nValueLen],"\r\n",2); 250 | bool bRetval = m_pSocket->send((uint8 *)szTemp, nNameLen+2+nValueLen+2); 251 | delete[] szTemp; 252 | return bRetval; 253 | } 254 | bool CHttpRequest::sendHeader(const char *szName, unsigned int nValue) { 255 | char szTemp[16]; 256 | os_sprintf(szTemp,"%u", nValue); 257 | return sendHeader(szName, szTemp); 258 | } 259 | 260 | void CHttpRequest::endHeaders() { 261 | if (!m_pSocket || m_bHeadersSent) 262 | return; 263 | m_pSocket->send((const uint8_t *)"\r\n",2); 264 | m_bHeadersSent = true; 265 | } 266 | 267 | bool CHttpRequest::sendData(const uint8_t *pData, size_t nLength) { 268 | if (!m_bResponseStarted || !m_pSocket) 269 | return false; 270 | endHeaders(); 271 | return m_pSocket->send(pData, nLength); 272 | } 273 | 274 | bool CHttpRequest::sendData(const char *szData) { 275 | return sendData((const uint8_t *)szData, strlen(szData)); 276 | } 277 | 278 | void CHttpRequest::end(bool bForce) { 279 | if (m_pSocket) 280 | m_pSocket->disconnect(bForce); 281 | } 282 | 283 | void CHttpRequest::dispatchDataDone() { 284 | for (auto listener : m_sListeners) 285 | listener->onDataDone(this); 286 | if (m_sListeners.empty()) 287 | onError(404,"File not found","File not found"); 288 | } 289 | -------------------------------------------------------------------------------- /user/httpd/CHttpRequest.h: -------------------------------------------------------------------------------- 1 | #ifndef HTTPD_CHTTPREQUEST_H 2 | #define HTTPD_CHTTPREQUEST_H 3 | #include "CTcpSocket.h" 4 | #include 5 | #include 6 | 7 | #define HTTP_BUFFER_SIZE 512 8 | class CHttpServer; 9 | class IHttpRequestListener; 10 | class CHttpRequest : ITcpSocketListener { 11 | public: 12 | CHttpRequest(CHttpServer *pOwner, CTcpSocket *pSocket); 13 | void addRef(); 14 | void release(); 15 | void addListener(IHttpRequestListener *pListener); 16 | void removeListener(IHttpRequestListener *pListener); 17 | std::string getUri(); 18 | bool startHeaders(unsigned int nCode, const char *szMessage); 19 | bool sendHeader(const char *szName, const char *szValue); 20 | bool sendHeader(const char *szName, unsigned int nValue); 21 | void endHeaders(); 22 | bool sendData(const uint8_t *pData, size_t nLength); 23 | bool sendData(const char *szData); 24 | void end(bool bForce); 25 | private: 26 | ~CHttpRequest(); 27 | void onSocketRecv(CTcpSocket *pSocket, const uint8_t *pData, size_t nLen); 28 | void onSocketDisconnected(CTcpSocket *pSocket); 29 | void onSocketSent(CTcpSocket *pSocket); 30 | 31 | void dispatchDataDone(); 32 | 33 | bool process(); 34 | //szHeader[nLength] = '\0'; 35 | bool processHeader(char *szHeader, size_t nLength); 36 | void onError(unsigned int nCode, const char *szType, const char *szDescription); 37 | 38 | enum Verb { 39 | VERB_GET, 40 | VERB_POST 41 | }; 42 | 43 | CHttpServer *m_pOwner; 44 | CTcpSocket *m_pSocket; 45 | std::set m_sListeners; 46 | //m_bHadError: if this is true, an error occured somewhere, and the socket should be closed ASAP. 47 | bool m_bHadError; 48 | unsigned int m_nRef; 49 | uint8_t m_pBuffer[HTTP_BUFFER_SIZE]; 50 | size_t m_nBufferFilled; 51 | Verb m_vVerb; 52 | std::string m_szUri; 53 | bool m_bHeadersDone; 54 | size_t m_nDataLeft; 55 | bool m_bResponseStarted; 56 | bool m_bHeadersSent; 57 | }; 58 | 59 | class IHttpRequestListener { 60 | public: 61 | virtual ~IHttpRequestListener() {}; 62 | virtual void onHeader(CHttpRequest *pRequest, const char *szName, const char *szValue) = 0; 63 | virtual void onHeadersDone(CHttpRequest *pRequest, size_t nDataLength) = 0; 64 | virtual void onData(CHttpRequest *pRequest, const uint8_t *pData, size_t nLength) = 0; 65 | virtual void onDataDone(CHttpRequest *pRequest) = 0; 66 | virtual void onSent(CHttpRequest *pRequest) = 0; 67 | virtual void onDisconnected(CHttpRequest *pRequest) = 0; 68 | }; 69 | #endif//HTTPD_CHTTPREQUEST_H 70 | -------------------------------------------------------------------------------- /user/httpd/CHttpServer.cpp: -------------------------------------------------------------------------------- 1 | #include "CHttpServer.h" 2 | #include "CHttpRequest.h" 3 | 4 | CHttpServer::CHttpServer(int nPort) : m_cParent(nPort) { 5 | m_cParent.addListener(this); 6 | } 7 | 8 | void CHttpServer::addListener(IHttpServerListener *pListener) { 9 | m_sListeners.insert(pListener); 10 | } 11 | 12 | void CHttpServer::removeListener(IHttpServerListener *pListener) { 13 | m_sListeners.erase(pListener); 14 | } 15 | 16 | void CHttpServer::onConnection(CTcpSocket *pSocket) { 17 | new CHttpRequest(this, pSocket); 18 | } 19 | 20 | void CHttpServer::onRequest(CHttpRequest *pRequest) { 21 | for (auto listener : m_sListeners) 22 | if (listener->onRequest(this, pRequest)) 23 | return; 24 | } 25 | -------------------------------------------------------------------------------- /user/httpd/CHttpServer.h: -------------------------------------------------------------------------------- 1 | #ifndef HTTPD_CHTTPSERVER_H 2 | #define HTTPD_CHTTPSERVER_H 3 | #include "CTcpServer.h" 4 | #include 5 | 6 | class CHttpRequest; 7 | class IHttpServerListener; 8 | class CHttpServer : ITcpServerListener { 9 | public: 10 | CHttpServer(int nPort); 11 | void addListener(IHttpServerListener *pListener); 12 | void removeListener(IHttpServerListener *pListener); 13 | protected: 14 | friend class CHttpRequest; 15 | void onRequest(CHttpRequest *pRequest); 16 | private: 17 | void onConnection(CTcpSocket *pSocket); 18 | 19 | CTcpServer m_cParent; 20 | std::set m_sListeners; 21 | }; 22 | 23 | class IHttpServerListener { 24 | public: 25 | virtual ~IHttpServerListener() {}; 26 | // Return true if you are going to handle the request, no further listeners will be informed. 27 | virtual bool onRequest(CHttpServer *pServer, CHttpRequest *pRequest) = 0; 28 | }; 29 | #endif//HTTPD_CHTTPSERVER_H 30 | -------------------------------------------------------------------------------- /user/httpd/CTcpServer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "CTcpServer.h" 3 | #include 4 | #include 5 | extern "C" { 6 | #include 7 | } 8 | #include "CTcpSocket.h" 9 | 10 | CTcpServer::CTcpServer(int nPort) { 11 | memset(&m_conn, 0, sizeof(struct espconn)); 12 | memset(&m_tcp, 0, sizeof(esp_tcp)); 13 | m_conn.type = ESPCONN_TCP; 14 | m_conn.state = ESPCONN_NONE; 15 | m_conn.proto.tcp = &m_tcp; 16 | m_tcp.local_port = nPort; 17 | fixConnectionParams(); 18 | espconn_accept(&m_conn); 19 | } 20 | 21 | CTcpServer::~CTcpServer() { 22 | // Maybe espconn_disconnect is better? unsure about this. 23 | espconn_delete(&m_conn); 24 | } 25 | 26 | void CTcpServer::fixConnectionParams() { 27 | // On connect, the server properties are copied to the client connection 28 | // However, on disconnect and reconnect, the properties are copied from client to server. 29 | // This function should be called from those callbacks to fix things up. 30 | m_conn.reverse = (void*)this; 31 | espconn_regist_connectcb(&m_conn, connect_callback); 32 | espconn_regist_disconcb(&m_conn, disconnect_callback); 33 | //Somehow register_reconcb isn't always defined 34 | m_tcp.reconnect_callback = reconnect_callback; 35 | } 36 | 37 | void CTcpServer::addListener(ITcpServerListener *pListener) { 38 | m_sListeners.insert(pListener); 39 | } 40 | 41 | void CTcpServer::removeListener(ITcpServerListener *pListener) { 42 | m_sListeners.erase(pListener); 43 | } 44 | 45 | void CTcpServer::setTimeout(unsigned int nTimeout) { 46 | //last arg 0 means set for all child connections. 47 | espconn_regist_time(&m_conn, nTimeout, 0); 48 | } 49 | 50 | void CTcpServer::connect_callback(void *arg) { 51 | // arg points to the new connection, 52 | // but "reverse" should be copied along. 53 | // So at this point, we can use that to get a pointer to our CTcpServer, 54 | // And then change it to a CHttpConnection 55 | struct espconn *conn = (struct espconn *)arg; 56 | CTcpServer *pServer = (CTcpServer *)conn->reverse; 57 | pServer->fixConnectionParams(); //Just in case 58 | CTcpSocket *pSocket = new CTcpSocket(pServer, conn); 59 | for (auto listener : pServer->m_sListeners) 60 | listener->onConnection(pSocket); 61 | pSocket->release(); 62 | } 63 | 64 | void CTcpServer::disconnect_callback(void *arg) { 65 | struct espconn *conn = (struct espconn *)arg; 66 | //Note: 67 | // this assumes the ->reverse of the client still points to the server. 68 | // If you change ->reverse of the client, make sure to set different connect/reconnect/disconnect callbacks too! 69 | // And be sure to call fixConnectionParams() on the server just after extracting the needed ->reverse 70 | CTcpServer *pServer = (CTcpServer *)conn->reverse; 71 | pServer->fixConnectionParams(); 72 | } 73 | 74 | void CTcpServer::reconnect_callback(void *arg, sint8) { 75 | struct espconn *conn = (struct espconn *)arg; 76 | //Note: 77 | // this assumes the ->reverse of the client still points to the server. 78 | // If you change ->reverse of the client, make sure to set different connect/reconnect/disconnect callbacks too! 79 | // And be sure to call fixConnectionParams() on the server just after extracting the needed ->reverse 80 | CTcpServer *pServer = (CTcpServer *)conn->reverse; 81 | pServer->fixConnectionParams(); 82 | } 83 | -------------------------------------------------------------------------------- /user/httpd/CTcpServer.h: -------------------------------------------------------------------------------- 1 | #ifndef HTTPD_CTCPSERVER_H 2 | #define HTTPD_CTCPSERVER_H 3 | #include 4 | extern "C" { 5 | #include 6 | #include 7 | } 8 | #include 9 | #include 10 | 11 | class ITcpServerListener; 12 | class CTcpSocket; 13 | class CTcpServer { 14 | public: 15 | CTcpServer(int nPort); 16 | ~CTcpServer(); 17 | void fixConnectionParams(); 18 | void addListener(ITcpServerListener *pListener); 19 | void removeListener(ITcpServerListener *pListener); 20 | void setTimeout(unsigned int nTimeout); 21 | private: 22 | struct espconn m_conn; 23 | esp_tcp m_tcp; 24 | std::set m_sListeners; 25 | 26 | static void connect_callback(void *arg); 27 | static void reconnect_callback(void *arg, sint8); 28 | static void disconnect_callback(void *arg); 29 | }; 30 | 31 | class ITcpServerListener { 32 | public: 33 | virtual void onConnection(CTcpSocket *pSocket) = 0; 34 | }; 35 | #endif//HTTPD_CTCPSERVER_H 36 | -------------------------------------------------------------------------------- /user/httpd/CTcpSocket.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "CTcpSocket.h" 3 | #include "CTcpServer.h" 4 | #include "string.h" 5 | extern "C" { 6 | #include 7 | } 8 | #include "debug/CDebugServer.h" 9 | 10 | CTcpSocket::CTcpSocket(CTcpServer *pServer, struct espconn *conn) { 11 | m_pServer = pServer; 12 | m_conn = conn; 13 | m_nRef = 1; 14 | setupConnectionParams(); 15 | DEBUG("CTcpSocket::CTcpSocket() = %08X",this); 16 | } 17 | CTcpSocket::~CTcpSocket() { 18 | //If all is well no cleanup is needed at this point. 19 | for (auto cur : m_lBacklog) 20 | delete[] cur.first; 21 | DEBUG("CTcpSocket::~CTcpSocket(%08X)", this); 22 | } 23 | 24 | void CTcpSocket::setupConnectionParams() { 25 | if (!m_conn) 26 | return; 27 | m_conn->reverse = this; 28 | espconn_regist_disconcb(m_conn, disconnect_callback); 29 | espconn_regist_connectcb(m_conn, connect_callback); 30 | m_conn->proto.tcp->reconnect_callback = reconnect_callback; 31 | espconn_regist_recvcb(m_conn, recv_callback); 32 | espconn_regist_sentcb(m_conn, sent_callback); 33 | } 34 | 35 | void CTcpSocket::dropConnectionParams() { 36 | if (!m_conn) 37 | return; 38 | m_conn->reverse = NULL; 39 | } 40 | 41 | void CTcpSocket::addListener(ITcpSocketListener *pListener) { 42 | if (m_sListeners.insert(pListener).second) 43 | addRef(); 44 | } 45 | void CTcpSocket::removeListener(ITcpSocketListener *pListener) { 46 | if (m_sListeners.erase(pListener) > 0) 47 | release(); 48 | } 49 | 50 | void CTcpSocket::addRef() { 51 | DEBUG("CTcpSocket::addRef(%08X): %d -> %d", this, m_nRef, m_nRef+1); 52 | m_nRef++; 53 | } 54 | void CTcpSocket::release() { 55 | DEBUG("CTcpSocket::release(%08X): %d -> %d", this, m_nRef, m_nRef-1); 56 | if (--m_nRef == 0) { 57 | if (!m_conn) { 58 | delete this; 59 | } else { 60 | espconn_disconnect(m_conn); 61 | } 62 | } 63 | } 64 | 65 | bool CTcpSocket::send(const uint8_t *pData, size_t nLen) { 66 | if (!m_conn || m_bDisconnecting) 67 | return false; 68 | if (m_bSending) { 69 | uint8_t *pCopy = new uint8_t[nLen]; 70 | memcpy(pCopy, pData, nLen); 71 | m_lBacklog.push_back(std::make_pair(pCopy, nLen)); 72 | return true; 73 | } 74 | m_bSending = true; 75 | int ret = espconn_sent(m_conn, (uint8_t *)pData, nLen); 76 | if (ret == ESPCONN_OK) 77 | return true; 78 | m_bSending = false; 79 | return false; 80 | } 81 | 82 | void CTcpSocket::setTimeout(unsigned int nTimeout) { 83 | if (!m_conn) 84 | return; 85 | // Last argument 0 means all connections, 1 means just this connection 86 | espconn_regist_time(m_conn, nTimeout, 1); 87 | } 88 | 89 | void CTcpSocket::disconnect(bool bForce) { 90 | if (!m_conn) 91 | return; 92 | if (bForce) { 93 | for (auto b : m_lBacklog) 94 | delete[] b.first; 95 | m_lBacklog.clear(); 96 | espconn_disconnect(m_conn); 97 | m_bDisconnecting = true; 98 | return; 99 | } 100 | if (!m_bDisconnecting) { 101 | m_bDisconnecting = true; 102 | if (!m_bSending) 103 | espconn_disconnect(m_conn); 104 | } 105 | } 106 | 107 | void CTcpSocket::connect_callback(void *arg) { 108 | struct espconn *conn = (struct espconn *)arg; 109 | CTcpSocket *pSocket = (CTcpSocket *)conn->reverse; 110 | if (pSocket->m_conn != conn) { 111 | //Assume ESP SDK fuckup 112 | if (pSocket->m_pServer) 113 | pSocket->m_pServer->fixConnectionParams(); 114 | } 115 | } 116 | 117 | void CTcpSocket::disconnect_callback(void *arg) { 118 | struct espconn *conn = (struct espconn *)arg; 119 | CTcpSocket *pSocket = (CTcpSocket *)conn->reverse; 120 | if (pSocket->m_conn != conn) { 121 | //Assume ESP SDK fuckup 122 | if (pSocket->m_pServer) 123 | pSocket->m_pServer->fixConnectionParams(); 124 | } 125 | pSocket->m_conn = (struct espconn *)NULL; 126 | std::set sListeners(pSocket->m_sListeners); 127 | pSocket->addRef(); 128 | pSocket->m_sListeners.clear(); 129 | for (auto listener : sListeners) { 130 | listener->onSocketDisconnected(pSocket); 131 | pSocket->release(); 132 | } 133 | //If this drops off to zero, the socket should be deallocated 134 | pSocket->release(); 135 | } 136 | void CTcpSocket::reconnect_callback(void *arg, sint8) { 137 | struct espconn *conn = (struct espconn *)arg; 138 | CTcpSocket *pSocket = (CTcpSocket *)conn->reverse; 139 | if (!pSocket) 140 | return; 141 | if (pSocket->m_conn != conn) { 142 | //Assume ESP SDK fuckup 143 | if (pSocket->m_pServer) 144 | pSocket->m_pServer->fixConnectionParams(); 145 | } 146 | } 147 | void CTcpSocket::recv_callback(void *arg, char *pData, unsigned short nLen) { 148 | struct espconn *conn = (struct espconn *)arg; 149 | CTcpSocket *pSocket = (CTcpSocket *)conn->reverse; 150 | if (!pSocket) 151 | return; 152 | for (auto listener : pSocket->m_sListeners) 153 | listener->onSocketRecv(pSocket, (const uint8_t *)pData, nLen); 154 | } 155 | void CTcpSocket::sent_callback(void *arg) { 156 | struct espconn *conn = (struct espconn *)arg; 157 | CTcpSocket *pSocket = (CTcpSocket *)conn->reverse; 158 | if (!pSocket) 159 | return; 160 | if (!pSocket->m_lBacklog.empty()) { 161 | std::pair current(pSocket->m_lBacklog.front()); 162 | pSocket->m_lBacklog.pop_front(); 163 | espconn_sent(pSocket->m_conn, current.first, current.second); 164 | delete[] current.first; 165 | return; 166 | } 167 | pSocket->m_bSending = false; 168 | if (pSocket->m_bDisconnecting) { 169 | espconn_disconnect(conn); 170 | return; 171 | } 172 | for (auto listener : pSocket->m_sListeners) 173 | listener->onSocketSent(pSocket); 174 | } 175 | -------------------------------------------------------------------------------- /user/httpd/CTcpSocket.h: -------------------------------------------------------------------------------- 1 | #ifndef HTTPD_CTCPSOCKET_H 2 | #define HTTPD_CTCPSOCKET_H 3 | #include 4 | extern "C" { 5 | #include 6 | #include 7 | } 8 | #include 9 | #include 10 | 11 | class CTcpServer; 12 | class ITcpSocketListener; 13 | class CTcpSocket { 14 | public: 15 | CTcpSocket(CTcpServer *pServer, struct espconn *conn); 16 | void addRef(); 17 | void release(); 18 | void addListener(ITcpSocketListener *pListener); 19 | void removeListener(ITcpSocketListener *pListener); 20 | bool send(const uint8_t *pData, size_t nLen); 21 | void setTimeout(unsigned int nTimeout); 22 | void disconnect(bool bForce); 23 | private: 24 | ~CTcpSocket(); 25 | void setupConnectionParams(); 26 | void dropConnectionParams(); 27 | 28 | unsigned int m_nRef; 29 | CTcpServer *m_pServer; 30 | struct espconn *m_conn; 31 | std::set m_sListeners; 32 | std::list> m_lBacklog; 33 | bool m_bSending; 34 | bool m_bDisconnecting; 35 | 36 | static void connect_callback(void *arg); 37 | static void reconnect_callback(void *arg, sint8); 38 | static void disconnect_callback(void *arg); 39 | static void recv_callback(void *arg, char *pData, unsigned short nLen); 40 | static void sent_callback(void *arg); 41 | }; 42 | class ITcpSocketListener { 43 | public: 44 | virtual void onSocketRecv(CTcpSocket *pSocket, const uint8_t *pData, size_t nLen) = 0; 45 | virtual void onSocketDisconnected(CTcpSocket *pSocket) = 0; 46 | virtual void onSocketSent(CTcpSocket *pSocket) = 0; 47 | virtual ~ITcpSocketListener() {}; 48 | }; 49 | #endif//HTTPD_CTCPSOCKET_H 50 | -------------------------------------------------------------------------------- /user/input_protocols/artnet.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * artnet.c 3 | * 4 | * Created on: Nov 18, 2014 5 | * Author: frans-willem 6 | */ 7 | #include 8 | extern "C" { 9 | #include "ets_sys.h" 10 | #include "osapi.h" 11 | #include "os_type.h" 12 | #include "user_interface.h" 13 | #include "espconn.h" 14 | } 15 | #include 16 | #include "output_protocols/COutput.h" 17 | #include "output_protocols/output.h" 18 | 19 | #define ARTNET_Port 0x1936 20 | 21 | bool artnet_enabled; 22 | char artnet_shortname[18]; 23 | char artnet_longname[64]; 24 | uint8_t artnet_net; 25 | uint8_t artnet_subnet; 26 | uint8_t artnet_universe; 27 | 28 | BEGIN_CONFIG(artnet, "artnet", "Art-Net"); 29 | CONFIG_BOOLEAN("enabled","Enabled",&artnet_enabled, 1); 30 | CONFIG_STRING("shortname","Short name", artnet_shortname, 18, "EspLightNode"); 31 | CONFIG_STRING("longname", "Long name", artnet_longname, 64, "EspLightNode v1.0.0 running on ESP8266"); 32 | CONFIG_INT("net", "Net", &artnet_net, 0, 127, 0); 33 | CONFIG_INT("subnet", "SubNet", &artnet_subnet, 0, 15, 0); 34 | CONFIG_INT("universe", "Universe", &artnet_universe, 0, 15, 0); 35 | END_CONFIG(); 36 | 37 | static void ICACHE_FLASH_ATTR artnet_recv_opoutput(unsigned char *packet, unsigned short packetlen) { 38 | if (packetlen >= 8) { 39 | uint16_t ProtVer=((uint16_t)packet[0] << 8) | packet[1]; 40 | if (ProtVer == 14) { 41 | //uint8_t Sequence = packet[2]; 42 | //uint8_t Physical = packet[3]; 43 | uint8_t SubUni = packet[4]; 44 | uint8_t Net = packet[5]; 45 | if (Net == artnet_net && (SubUni >> 4) == artnet_subnet && (SubUni & 0xF) == artnet_universe) { 46 | uint16_t Length = ((uint16_t)packet[6] << 8) | packet[7]; 47 | if (packetlen >= 8 + Length) 48 | Output::output(&packet[8], Length); 49 | } else { 50 | //Not intended for us... 51 | } 52 | } 53 | } else { 54 | //Invalid length 55 | } 56 | } 57 | 58 | #define ARTNET_OpPoll 0x2000 59 | #define ARTNET_OpPollReply 0x2100 60 | #define ARTNET_OpOutput 0x5000 61 | 62 | #define TTM_REPLY_MASK 0 63 | 64 | struct ArtNetPollReply { 65 | uint8_t ID[8]; 66 | uint8_t OpCode[2]; //low-first 67 | uint8_t IP[4]; 68 | uint8_t Port[2]; //Low-first 69 | uint8_t VersInfo[2]; //High-first 70 | uint8_t NetSwitch; 71 | uint8_t SubSwitch; 72 | uint8_t Oem[2]; //High-first 73 | uint8_t Ubea_Version; 74 | uint8_t Status1; 75 | uint8_t EstaMan[2]; //Low-first 76 | uint8_t ShortName[18]; 77 | uint8_t LongName[64]; 78 | uint8_t NodeReport[64]; 79 | uint8_t NumPorts[2]; //High-first 80 | uint8_t PortTypes[4]; 81 | uint8_t GoodInput[4]; 82 | uint8_t GoodOutput[4]; 83 | uint8_t SwIn[4]; 84 | uint8_t SwOut[4]; 85 | uint8_t SwVideo; 86 | uint8_t SwMacro; 87 | uint8_t SwRemote; 88 | uint8_t Spare[3]; 89 | uint8_t Style; 90 | uint8_t MAC[6]; //High-byte first 91 | uint8_t BindIp[4]; 92 | uint8_t BindIndex; 93 | uint8_t Status2; 94 | uint8_t Filler[26]; 95 | }; 96 | 97 | #define ARTNET_SET_SHORT_LOFIRST(target,value) (target)[0] = (value) & 0xFF; (target)[1] = (value) >> 8; 98 | #define ARTNET_SET_SHORT_HIFIRST(target,value) (target)[0] = (value) >> 8; (target)[1] = (value) & 0xFF; 99 | 100 | static void ICACHE_FLASH_ATTR artnet_recv_oppoll(struct espconn *conn, unsigned char *packet, unsigned short packetlen) { 101 | if (packetlen >= 3) { 102 | //uint16_t ProtVer=((uint16_t)packet[0] << 8) | packet[1]; 103 | uint8_t TalkToMe=packet[2]; 104 | //TODO 105 | if (TalkToMe & TTM_REPLY_MASK) { 106 | 107 | } else { 108 | 109 | } 110 | struct ip_info ipconfig; 111 | uint8_t hwaddr[6]; 112 | 113 | wifi_get_ip_info(STATION_IF, &ipconfig); 114 | wifi_get_macaddr(STATION_IF, hwaddr); 115 | 116 | struct ArtNetPollReply response; 117 | memset(&response, 0, sizeof(struct ArtNetPollReply)); 118 | strcpy((char*)response.ID,"Art-Net"); 119 | ARTNET_SET_SHORT_LOFIRST(response.OpCode, ARTNET_OpPollReply); 120 | memcpy(response.IP,&ipconfig.ip.addr,4); 121 | ARTNET_SET_SHORT_LOFIRST(response.Port, ARTNET_Port); 122 | ARTNET_SET_SHORT_HIFIRST(response.VersInfo, 0); 123 | response.NetSwitch = artnet_net; 124 | response.SubSwitch = artnet_subnet; 125 | ARTNET_SET_SHORT_HIFIRST(response.Oem,0); 126 | response.Ubea_Version = 0; 127 | response.Status1 = 0; 128 | ARTNET_SET_SHORT_LOFIRST(response.EstaMan,0); 129 | memcpy(response.ShortName,artnet_shortname, sizeof(response.ShortName)); 130 | memcpy(response.LongName,artnet_longname, sizeof(response.LongName)); 131 | strcpy((char *)response.NodeReport,""); 132 | ARTNET_SET_SHORT_HIFIRST(response.NumPorts,1); 133 | response.PortTypes[0]=0x80; 134 | //Not set is set to 0 135 | //response.GoodInput = 0; 136 | //response.GoodOutput = 0; 137 | response.SwOut[0] = artnet_universe; 138 | //response.SwVideo 139 | //response.SwMacro 140 | //response.SwRemote 141 | //response.Style 142 | memcpy(response.MAC,hwaddr,6); 143 | //response.BindIp 144 | //response.BindIndex 145 | //response.Status2 146 | espconn_sent(conn,(uint8_t *)&response,sizeof(struct ArtNetPollReply)); 147 | } else { 148 | //Invalid length 149 | } 150 | } 151 | 152 | static void ICACHE_FLASH_ATTR artnet_recv(void *arg, char *pusrdata, unsigned short length) { 153 | unsigned char *data =(unsigned char *)pusrdata; 154 | if (data && length>=10) { 155 | if (data[0]=='A' && data[1]=='r' && data[2]=='t' && data[3]=='-' && data[4]=='N' && data[5]=='e' && data[6]=='t' && data[7]==0) { 156 | uint16_t OpCode=data[8] | ((uint16_t)data[9] << 8); 157 | switch (OpCode) { 158 | case ARTNET_OpOutput: 159 | return artnet_recv_opoutput(&data[10],length-10); 160 | case ARTNET_OpPoll: 161 | return artnet_recv_oppoll((struct espconn *)arg,&data[10],length-10); 162 | } 163 | } else { 164 | //Header invalid 165 | } 166 | } else { 167 | //Package too small. 168 | } 169 | 170 | } 171 | 172 | void artnet_init() { 173 | static struct espconn artnetconn; 174 | static esp_udp artnetudp; 175 | 176 | 177 | artnetconn.type = ESPCONN_UDP; 178 | artnetconn.state = ESPCONN_NONE; 179 | artnetconn.proto.udp = &artnetudp; 180 | artnetudp.local_port=ARTNET_Port; 181 | artnetconn.reverse = NULL; 182 | if (artnet_enabled) { 183 | espconn_regist_recvcb(&artnetconn, artnet_recv); 184 | espconn_create(&artnetconn); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /user/input_protocols/artnet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * artnet.h 3 | * 4 | * Created on: Nov 18, 2014 5 | * Author: frans-willem 6 | */ 7 | 8 | #ifndef ESPLIGHTNODE_USER_INPUT_PROTOCOLS_ARTNET_H_ 9 | #define ESPLIGHTNODE_USER_INPUT_PROTOCOLS_ARTNET_H_ 10 | #include 11 | 12 | DEFINE_CONFIG(artnet); 13 | 14 | void artnet_init(); 15 | #endif /* ESPLIGHTNODE_USER_INPUT_PROTOCOLS_ARTNET_H_ */ 16 | -------------------------------------------------------------------------------- /user/input_protocols/tpm2net.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * tpm2net.c 3 | * 4 | * Created on: Nov 18, 2014 5 | * Author: frans-willem 6 | */ 7 | #include 8 | extern "C" { 9 | #include "ets_sys.h" 10 | #include "osapi.h" 11 | #include "os_type.h" 12 | #include "user_interface.h" 13 | #include "espconn.h" 14 | } 15 | #include 16 | #include "output_protocols/output.h" 17 | #include "output_protocols/COutput.h" 18 | #include "debug/CDebugServer.h" 19 | 20 | namespace tpm2net { 21 | bool bEnabled; 22 | size_t nLastPacket; 23 | size_t nPreviousLength; 24 | 25 | BEGIN_CONFIG(config,"tpm2","TPM2.net"); 26 | CONFIG_BOOLEAN("enabled","Enabled",&bEnabled, true); 27 | END_CONFIG(); 28 | 29 | static void recv(void *arg, char *pusrdata, unsigned short length) { 30 | DEBUG("Packet"); 31 | uint8_t *data =(uint8_t *)pusrdata; //pointer to espconn's returned data 32 | for (unsigned int i=0; i<16 && i = 6 && data[0]==0x9C) { // header identifier (packet start) 35 | uint8_t blocktype = data[1]; // block type 36 | uint16_t framelength = ((uint16_t)data[2] << 8) | (uint16_t)data[3]; // frame length 37 | uint8_t packagenum = data[4]; // packet number 0-255 (0x00 = no split) 38 | uint8_t numpackages = data[5]; // total packets 1-255 39 | if (blocktype == 0xDA) { // data command ... 40 | if (length >= framelength + 7 && data[6+framelength]==0x36) { // header end (packet stop) 41 | if (numpackages == 0x01) { // no frame split found 42 | Output::output(&data[6], framelength); 43 | } else { //frame split is found 44 | DEBUG("Package %d %d %u", packagenum, numpackages, nLastPacket, nPreviousLength); 45 | if (packagenum <= 1 || packagenum == nLastPacket + 1) { 46 | if (packagenum == 1) 47 | nPreviousLength = 0; 48 | Output::partial(nPreviousLength, &data[6], framelength, packagenum == numpackages); 49 | nPreviousLength += framelength; 50 | nLastPacket = packagenum; 51 | } 52 | } 53 | } 54 | } 55 | } 56 | } 57 | 58 | void init() { 59 | static struct espconn tpm2conn; 60 | static esp_udp tpm2udp; 61 | 62 | if (!bEnabled) 63 | return; 64 | 65 | tpm2conn.type = ESPCONN_UDP; 66 | tpm2conn.state = ESPCONN_NONE; 67 | tpm2conn.proto.udp = &tpm2udp; 68 | tpm2udp.local_port=0xFFE2; 69 | tpm2conn.reverse = NULL; 70 | espconn_regist_recvcb(&tpm2conn, recv); 71 | espconn_create(&tpm2conn); 72 | } 73 | 74 | void deinit() { 75 | 76 | } 77 | }//namespace tpm2net 78 | -------------------------------------------------------------------------------- /user/input_protocols/tpm2net.h: -------------------------------------------------------------------------------- 1 | /* 2 | * tpm2net.h 3 | * 4 | * Created on: Nov 18, 2014 5 | * Author: frans-willem 6 | */ 7 | 8 | #ifndef INPUT_PROTOCOLS_TPM2NET_H_ 9 | #define INPUT_PROTOCOLS_TPM2NET_H_ 10 | #include "config/config.h" 11 | 12 | namespace tpm2net { 13 | DEFINE_CONFIG(config); 14 | void init(); 15 | void deinit(); 16 | } 17 | #endif /* INPUT_PROTOCOLS_TPM2NET_H_ */ 18 | -------------------------------------------------------------------------------- /user/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * user_main.c 3 | * 4 | * Created on: Nov 15, 2014 5 | * Author: frans-willem 6 | */ 7 | #include 8 | extern "C" { 9 | #include "ets_sys.h" 10 | #include "osapi.h" 11 | #include "gpio.h" 12 | #include "os_type.h" 13 | #include "user_config.h" 14 | #include "user_interface.h" 15 | #include "espconn.h" 16 | #include "mem.h" 17 | } 18 | #include "input_protocols/artnet.h" 19 | #include "input_protocols/tpm2net.h" 20 | #include "config/config.h" 21 | #include "debug/CDebugServer.h" 22 | #include "httpd/CHttpServer.h" 23 | #include 24 | #include "wifisetup.h" 25 | #include "output_protocols/output.h" 26 | 27 | 28 | void start_services() { 29 | CHttpServer *pServer = new CHttpServer(80); 30 | 31 | config_init(pServer); 32 | tpm2net::init(); 33 | artnet_init(); 34 | } 35 | static os_timer_t client_timer; 36 | static void ICACHE_FLASH_ATTR wait_for_ip(uint8 flag) { 37 | LOCAL struct ip_info ipconfig; 38 | LOCAL int status; 39 | os_timer_disarm(&client_timer); 40 | 41 | status = wifi_station_get_connect_status(); 42 | if (status == STATION_GOT_IP) { 43 | wifi_get_ip_info(STATION_IF, &ipconfig); 44 | if( ipconfig.ip.addr != 0) { 45 | //Start UDP server 46 | DEBUG("Started %s", "OK"); 47 | start_services(); 48 | } else { 49 | os_timer_setfn(&client_timer, (os_timer_func_t *)wait_for_ip, NULL); 50 | os_timer_arm(&client_timer, 100, 0); 51 | } 52 | } else if (status == STATION_CONNECTING) { 53 | os_timer_setfn(&client_timer, (os_timer_func_t *)wait_for_ip, NULL); 54 | os_timer_arm(&client_timer, 100, 0); 55 | } else { //STATION_NO_AP_FOUND||STATION_CONNECT_FAIL||STATION_WRONG_PASSWORD 56 | //Connection failed, somehow :( 57 | //system_restart(); 58 | //TODO: Bring up SOFTAP here? 59 | } 60 | } 61 | 62 | static void ICACHE_FLASH_ATTR system_is_done(void){ 63 | //Bringing up WLAN 64 | if (wifi_get_opmode() == STATION_MODE) { 65 | wifi_station_connect(); 66 | //Wait for connection 67 | os_timer_disarm(&client_timer); 68 | os_timer_setfn(&client_timer, (os_timer_func_t *)wait_for_ip, NULL); 69 | os_timer_arm(&client_timer, 100, 0); 70 | } else if (wifi_get_opmode() == SOFTAP_MODE) { 71 | start_services(); 72 | } 73 | } 74 | 75 | //Init function 76 | extern "C" void ICACHE_FLASH_ATTR 77 | user_init() 78 | { 79 | wifi_setup_defaults(); 80 | config_load(); 81 | wifi_init(); 82 | Output::init(); 83 | 84 | //Wait for system to be done. 85 | system_init_done_cb(&system_is_done); 86 | //system_os_task() 87 | } 88 | -------------------------------------------------------------------------------- /user/output_protocols/C3WireEncoder.cpp: -------------------------------------------------------------------------------- 1 | #include "C3WireEncoder.h" 2 | 3 | //Nothing here... 4 | -------------------------------------------------------------------------------- /user/output_protocols/C3WireEncoder.h: -------------------------------------------------------------------------------- 1 | #ifndef C3WIREENCODER_H 2 | #define C3WIREENCODER_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class I3WireEncoder { 9 | public: 10 | virtual ~I3WireEncoder() {}; 11 | virtual size_t getMaxLength(size_t nInputLength) = 0; 12 | virtual size_t encode(const uint8_t *pInput, size_t nInputLength, uint32_t *pOutput) = 0; 13 | }; 14 | 15 | template 16 | class C3WireEncoder : public I3WireEncoder { 17 | public: 18 | size_t getMaxLength(size_t nInputLength) { 19 | unsigned int nBits = std::max(len0,len1) * 8 * nInputLength; 20 | return (nBits + 31)/32; 21 | } 22 | 23 | size_t encode(const uint8_t *pInput, size_t nInputLength, uint32_t *pOutput) { 24 | memset(pOutput, 0, getMaxLength(nInputLength)*sizeof(uint32_t)); 25 | size_t nBitsLeft = 32; 26 | size_t nEncoded = 0; 27 | for (size_t i=0; i>= 1) { 30 | uint32_t nBitValue; 31 | size_t nBitLength; 32 | if (nInput & bit) { 33 | nBitLength = len1; 34 | nBitValue = ((1 << num1)-1) << (len1-num1); 35 | } else { 36 | nBitLength = len0; 37 | nBitValue = ((1 << num0)-1) << (len0-num0); 38 | } 39 | if (nBitLength <= nBitsLeft) { 40 | nBitsLeft -= nBitLength; 41 | *pOutput |= nBitValue << nBitsLeft; 42 | } else { 43 | *pOutput |= nBitValue >> (nBitLength - nBitsLeft); 44 | nBitsLeft += 32 - nBitLength; 45 | pOutput++; 46 | nEncoded++; 47 | *pOutput |= nBitValue << nBitsLeft; 48 | } 49 | } 50 | } 51 | return nEncoded + ((nBitsLeft != 32)?1:0); 52 | } 53 | }; 54 | #endif//C3WIREENCODER_H 55 | -------------------------------------------------------------------------------- /user/output_protocols/C3WireOutput.cpp: -------------------------------------------------------------------------------- 1 | #pragma GCC diagnostic ignored "-Wparentheses" 2 | #include 3 | #include "C3WireOutput.h" 4 | extern "C" { 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #undef PIN_FUNC_SELECT 12 | #include 13 | } 14 | #include "C3WireEncoder.h" 15 | 16 | // TODO: We should probably move these defines to a header somewhere. 17 | #ifndef i2c_bbpll 18 | #define i2c_bbpll 0x67 19 | #define i2c_bbpll_en_audio_clock_out 4 20 | #define i2c_bbpll_en_audio_clock_out_msb 7 21 | #define i2c_bbpll_en_audio_clock_out_lsb 7 22 | #define i2c_bbpll_hostid 4 23 | 24 | #define i2c_writeReg_Mask(block, host_id, reg_add, Msb, Lsb, indata) \ 25 | rom_i2c_writeReg_Mask(block, host_id, reg_add, Msb, Lsb, indata) 26 | 27 | #define i2c_readReg_Mask(block, host_id, reg_add, Msb, Lsb) \ 28 | rom_i2c_readReg_Mask_(block, host_id, reg_add, Msb, Lsb) 29 | 30 | #define i2c_writeReg_Mask_def(block, reg_add, indata) \ 31 | i2c_writeReg_Mask(block, block##_hostid, reg_add, reg_add##_msb, reg_add##_lsb, indata) 32 | 33 | #define i2c_readReg_Mask_def(block, reg_add) \ 34 | i2c_readReg_Mask(block, block##_hostid, reg_add, reg_add##_msb, reg_add##_lsb) 35 | #endif 36 | 37 | extern "C" void rom_i2c_writeReg_Mask(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t,uint32_t); 38 | 39 | C3WireOutput::C3WireOutput( 40 | unsigned int nLength, 41 | unsigned int nBck, 42 | unsigned int nDiv, 43 | I3WireEncoder *pEncoder) 44 | : COutput(nLength) 45 | { 46 | // Final clock frequency is: 47 | // 160 / MAX(2, nBck) / MAX(2, nDiv) 48 | // 49 | // Example: 50 | // For the WS2811 800khz clock, 51 | // one bit should take 1.25usec or 1250nanosec 52 | // 1sec/1250nanosec = 800khz 53 | // Assuming we need 4 bits to encode each bit, we'd need a clock of 54 | // 4 * 800khz = 3.2mhz 55 | // So we need to find 160 / nBck / nDiv = 3.2 56 | // 160 / 3.2 = 50 57 | // So we need nBck * nDiv = 50, where nBck>=2 and nDiv>=2 58 | // We should use 5 and 10, or 2 and 25, etc 59 | m_pEncoder = pEncoder; 60 | m_nBufferLength = m_pEncoder->getMaxLength(m_nLength); 61 | m_pBuffer = new uint32_t[m_nBufferLength]; 62 | 63 | memset(&m_qBuffer, 0, sizeof(m_qBuffer)); 64 | memset(&m_qZeroes, 0, sizeof(m_qZeroes)); 65 | memset(m_pZeroes, 0, sizeof(m_pZeroes)); 66 | 67 | // DMA buffer structure. 68 | // Buffer points to actual data, zeroes points to zeroes 69 | // Both buffer and zeroes point to zeroes as "next buffer" 70 | m_qBuffer.owner = m_qZeroes.owner = 1; 71 | m_qBuffer.eof = m_qZeroes.eof = 1; 72 | m_qBuffer.sub_sof = m_qZeroes.sub_sof = 0; 73 | m_qBuffer.datalen = m_qBuffer.blocksize = m_nBufferLength * sizeof(uint32_t); 74 | m_qZeroes.datalen = m_qZeroes.blocksize = sizeof(m_pZeroes); 75 | m_qBuffer.buf_ptr = (uint32_t)m_pBuffer; 76 | m_qZeroes.buf_ptr = (uint32_t)m_pZeroes; 77 | m_qBuffer.unused = m_qZeroes.unused = 0; 78 | m_qBuffer.next_link_ptr = m_qZeroes.next_link_ptr = (uint32_t)&m_qZeroes; 79 | 80 | // Pin func select 81 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_I2SO_DATA); 82 | // We don't really care about anything other than data, 83 | // But you might want to un-comment these while debugging. 84 | // PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_I2SO_WS); 85 | // PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_I2SO_BCK); 86 | 87 | //Reset DMA 88 | SET_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST); 89 | CLEAR_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST); 90 | 91 | //Clear DMA int flags 92 | SET_PERI_REG_MASK(SLC_INT_CLR, 0xFFFFFFFF); 93 | CLEAR_PERI_REG_MASK(SLC_INT_CLR, 0xFFFFFFFF); 94 | 95 | //Enable and configure DMA 96 | CLEAR_PERI_REG_MASK(SLC_CONF0, (SLC_MODE << SLC_MODE_S)); 97 | SET_PERI_REG_MASK(SLC_CONF0, (1<encode(pData, m_nLength, m_pBuffer); 153 | // Ideally I'd like to adjust the buffer length, 154 | // but that will creep out the SLC when it's not properly stopped. 155 | // So assume that the rest of the buffer is 0 anyway. 156 | // m_qBuffer.datalen = m_qBuffer.blocksize = nOutputLength * 4; 157 | 158 | // Adjust SLC (DMA) to point to just encoded buffer 159 | CLEAR_PERI_REG_MASK(SLC_RX_LINK,SLC_RXLINK_DESCADDR_MASK); 160 | SET_PERI_REG_MASK(SLC_RX_LINK, ((uint32)&m_qBuffer) & SLC_RXLINK_DESCADDR_MASK); 161 | 162 | // Reset FIFO, toggle pin, don't leave high 163 | SET_PERI_REG_MASK(I2SCONF, I2S_I2S_TX_FIFO_RESET); 164 | CLEAR_PERI_REG_MASK(I2SCONF, I2S_I2S_TX_FIFO_RESET); 165 | 166 | // Start DMA 167 | SET_PERI_REG_MASK(SLC_RX_LINK, SLC_RXLINK_START); 168 | } 169 | -------------------------------------------------------------------------------- /user/output_protocols/C3WireOutput.h: -------------------------------------------------------------------------------- 1 | #ifndef OUTPUT_PROTOCOLS_CI2SHARDWARE_H 2 | #define OUTPUT_PROTOCOLS_CI2SHARDWARE_H 3 | #include 4 | #include "COutput.h" 5 | extern "C" { 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | } 13 | 14 | class I3WireEncoder; 15 | class C3WireOutput : public COutput { 16 | public: 17 | C3WireOutput(unsigned int nLength, unsigned int nBck, unsigned int nDiv, I3WireEncoder *pEncoder); 18 | ~C3WireOutput(); 19 | virtual void output(const uint8_t *pData); 20 | private: 21 | I3WireEncoder *m_pEncoder; 22 | sdio_queue m_qBuffer; 23 | uint32_t *m_pBuffer; 24 | size_t m_nBufferLength; 25 | sdio_queue m_qZeroes; 26 | uint32_t m_pZeroes[1]; 27 | }; 28 | #endif//OUTPUT_PROTOCOLS_CI2SHARDWARE_H 29 | -------------------------------------------------------------------------------- /user/output_protocols/CColorCorrector.cpp: -------------------------------------------------------------------------------- 1 | #include "CColorCorrector.h" 2 | #include 3 | 4 | CColorCorrector::CColorCorrector(COutput *pNext, bool bGamma, float fGamma, bool bLum2Duty) 5 | : COutput(pNext->getLength()) 6 | { 7 | m_pBuffer = new uint8_t[m_nLength]; 8 | m_pNext = pNext; 9 | initLookup(bGamma, fGamma, bLum2Duty); 10 | } 11 | 12 | CColorCorrector::~CColorCorrector() { 13 | delete[] m_pBuffer; 14 | delete m_pNext; 15 | } 16 | 17 | COutput* CColorCorrector::wrap(COutput *pNext, bool bGamma, float fGamma, bool bLum2Duty) { 18 | if (!bGamma && !bLum2Duty) 19 | return pNext; 20 | return new CColorCorrector(pNext, bGamma, fGamma, bLum2Duty); 21 | } 22 | 23 | void CColorCorrector::output(const uint8_t *pData) { 24 | for (unsigned int i = 0; i < m_nLength; i++) { 25 | m_pBuffer[i] = m_lookup[pData[i]]; 26 | } 27 | m_pNext->output(m_pBuffer); 28 | } 29 | 30 | void CColorCorrector::initLookup(bool bGamma, float fGamma, bool bLum2Duty) { 31 | for (unsigned int i=0; i<256; i++) { 32 | float fValue = ((float)i)/255.0f; 33 | if (bGamma) 34 | fValue = pow(fValue, fGamma); 35 | if (bLum2Duty) { 36 | //See: 37 | // https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/ 38 | if (fValue > 0.07999591993063804f) { 39 | fValue = ((fValue+0.16f)/1.16f); 40 | fValue *= fValue * fValue; 41 | } else { 42 | fValue /= 9.033f; 43 | } 44 | } 45 | 46 | long nValue = std::round(fValue*255.0f); 47 | if (nValue<0) m_lookup[i] = 0; 48 | else if (nValue>255) m_lookup[i] = 255; 49 | else m_lookup[i] = nValue; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /user/output_protocols/CColorCorrector.h: -------------------------------------------------------------------------------- 1 | #ifndef OUTPUT_PROTOCOLS_CCOLORCORRECTOR_H 2 | #define OUTPUT_PROTOCOLS_CCOLORCORRECTOR_H 3 | #include "COutput.h" 4 | 5 | class CColorCorrector : public COutput { 6 | public: 7 | CColorCorrector(COutput *pNext, bool bGamma, float fGamma, bool bLum2Duty); 8 | ~CColorCorrector(); 9 | static COutput* wrap(COutput *pNext, bool bGamma, float fGamma, bool bLum2Duty); 10 | virtual void output(const uint8_t *pData); 11 | private: 12 | void initLookup(bool bGamma, float fGamma, bool bLum2Duty); 13 | COutput *m_pNext; 14 | uint8_t *m_pBuffer; 15 | uint8_t m_lookup[256]; 16 | }; 17 | #endif//OUTPUT_PROTOCOLS_CCOLORCORRECTOR_H 18 | 19 | -------------------------------------------------------------------------------- /user/output_protocols/CLimiter.cpp: -------------------------------------------------------------------------------- 1 | #include "CLimiter.h" 2 | #include 3 | 4 | CLimiter::CLimiter(COutput *pNext, unsigned int nPeriod) 5 | : COutput(pNext->getLength()) 6 | { 7 | m_pNext = pNext; 8 | m_nPeriod = nPeriod; 9 | m_pBuffer = new uint8_t[m_nLength]; 10 | m_state = State::Idle; 11 | } 12 | 13 | CLimiter::~CLimiter() { 14 | delete m_pNext; 15 | delete[] m_pBuffer; 16 | } 17 | 18 | COutput* CLimiter::wrap(COutput *pNext, unsigned int nMaxFramerate) { 19 | if (nMaxFramerate == 0) 20 | return pNext; 21 | return new CLimiter(pNext, 1000/nMaxFramerate); 22 | } 23 | 24 | void CLimiter::output(const uint8_t *pData) { 25 | switch (m_state) { 26 | case State::Idle: // On idle, just output, and start timeout for next frame. 27 | m_state = State::Waiting; 28 | Start(m_nPeriod, false); 29 | m_pNext->output(pData); 30 | break; 31 | case State::Waiting: // When still waiting, queue up. 32 | m_state = State::Queued; 33 | memcpy(m_pBuffer, pData, m_nLength * sizeof(uint8_t)); 34 | break; 35 | case State::Queued: // When already queued, discard previous. 36 | m_state = State::Queued; 37 | memcpy(m_pBuffer, pData, m_nLength * sizeof(uint8_t)); 38 | break; 39 | } 40 | } 41 | 42 | void CLimiter::onTrigger() { 43 | switch (m_state) { 44 | case State::Idle: 45 | case State::Waiting: 46 | m_state = State::Idle; 47 | break; 48 | case State::Queued: 49 | m_state = State::Waiting; 50 | Start(m_nPeriod, false); 51 | m_pNext->output(m_pBuffer); 52 | break; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /user/output_protocols/CLimiter.h: -------------------------------------------------------------------------------- 1 | #ifndef OUTPUT_PROTOCOLS_CLIMITER_H 2 | #define OUTPUT_PROTOCOLS_CLIMITER_H 3 | #include "COutput.h" 4 | #include "../CTimer.h" 5 | 6 | class CLimiter : CTimer, public COutput { 7 | public: 8 | CLimiter(COutput *pNext, unsigned int nPeriod); 9 | ~CLimiter(); 10 | static COutput* wrap(COutput *pNext, unsigned int nMaxFramerate); 11 | 12 | virtual void output(const uint8_t *pData); 13 | private: 14 | virtual void onTrigger(); 15 | 16 | enum State { 17 | Idle, //Idle state 18 | Waiting, //Frame was recently sent, timer is running. 19 | Queued //Timer is still running, new frame already queued. 20 | }; 21 | 22 | COutput *m_pNext; 23 | unsigned int m_nPeriod; 24 | uint8_t *m_pBuffer; 25 | State m_state; 26 | 27 | }; 28 | #endif//OUTPUT_PROTOCOLS_CLIMITER_H 29 | 30 | -------------------------------------------------------------------------------- /user/output_protocols/COutput.cpp: -------------------------------------------------------------------------------- 1 | #include "COutput.h" 2 | 3 | COutput::COutput(unsigned int nLength) : m_nLength(nLength) { 4 | } 5 | COutput::~COutput() { 6 | } 7 | unsigned int COutput::getLength() { 8 | return m_nLength; 9 | } 10 | void COutput::output(const uint8_t *pData) { 11 | } 12 | -------------------------------------------------------------------------------- /user/output_protocols/COutput.h: -------------------------------------------------------------------------------- 1 | #ifndef OUTPUT_PROTOCOLS_COUTPUT_H 2 | #define OUTPUT_PROTOCOLS_COUTPUT_H 3 | #include 4 | 5 | class COutput { 6 | public: 7 | COutput(unsigned int nLength); 8 | unsigned int getLength(); 9 | virtual ~COutput(); 10 | virtual void output(const uint8_t *pData); 11 | protected: 12 | unsigned int m_nLength; 13 | }; 14 | #endif//OUTPUT_PROTOCOLS_COUTPUT_H 15 | -------------------------------------------------------------------------------- /user/output_protocols/CSPIBitbang.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "CSPIBitbang.h" 3 | extern "C" { 4 | #include 5 | #include 6 | #include 7 | #include 8 | } 9 | 10 | unsigned int CSPIBitbang::g_nDataPin = 0; 11 | unsigned int CSPIBitbang::g_nClockPin = 0; 12 | 13 | struct GpioInfo { 14 | const char *szName; 15 | unsigned int nBit; 16 | unsigned int nMuxReg; 17 | unsigned int nMuxVal; 18 | }; 19 | 20 | GpioInfo gpioInfo[] = { 21 | {"GPIO0/D3/SPICS2/CLK OUT", BIT0, PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0}, 22 | {"GPIO1/D10/U0TXD/SPI CS1/CLK RTC", BIT1, PERIPHS_IO_MUX_U0TXD_U, FUNC_GPIO1}, 23 | {"GPIO2/D4/I2SO WS/U1TXD/U0TXD", BIT2, PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2}, 24 | {"GPIO3/D9/U0RXD/I2SO DATA/CLK XTAL", BIT3, PERIPHS_IO_MUX_U0RXD_U, FUNC_GPIO3}, 25 | {"GPIO4/D2/CLK XTAL", BIT4, PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4}, 26 | {"GPIO5/D1/CLK RTC", BIT5, PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5}, 27 | {"GPIO9/SD_DATA2/SPIHD/HSPIHD", BIT9, PERIPHS_IO_MUX_SD_DATA2_U, FUNC_GPIO9}, 28 | {"GPIO10/SD_DATA3/SPIWP/HSPIWP", BIT10, PERIPHS_IO_MUX_SD_DATA3_U, FUNC_GPIO10}, 29 | {"GPIO12/D6/MTDI/I2SI DATA/HSPI MISO/U0DTR", BIT12, PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12}, 30 | {"GPIO13/D7/MTCK/I2SI BCK/HSPI MOSI/U0CTS", BIT13, PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13}, 31 | {"GPIO14/D5/MTMS/I2SI WS/HSPI CLK/U0DSR", BIT14, PERIPHS_IO_MUX_MTMS_U, FUNC_GPIO14}, 32 | {"GPIO15/D1/MTDO/I2SO BCK/HSPI CS/U0RTS", BIT15, PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO15} 33 | }; 34 | 35 | BEGIN_CONFIG(CSPIBitbang::config, "spibb", "SPI Bitbang configuration"); 36 | CONFIG_SELECTSTART("data","Data pin", &g_nDataPin, 2); 37 | for (unsigned int i=0; i>=1) { 66 | if (pData[i] & bitmask) GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, m_nDataBit); 67 | else GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, m_nDataBit); 68 | __asm("nop"); 69 | GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, m_nClockBit); 70 | __asm("nop"); 71 | GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, m_nClockBit); 72 | } 73 | } 74 | GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, m_nClockBit|m_nDataBit); 75 | ets_intr_unlock(); 76 | } 77 | -------------------------------------------------------------------------------- /user/output_protocols/CSPIBitbang.h: -------------------------------------------------------------------------------- 1 | #ifndef OUTPUT_PROTOCOLS_CSPIBITBANG_H 2 | #define OUTPUT_PROTOCOLS_CSPIBITBANG_H 3 | #include "ISPIInterface.h" 4 | #include "config/config.h" 5 | 6 | class CSPIBitbang : public ISPIInterface { 7 | public: 8 | CSPIBitbang(); 9 | ~CSPIBitbang(); 10 | void output(const uint8_t *pData, size_t nDataLen); 11 | 12 | static DEFINE_CONFIG(config); 13 | private: 14 | static unsigned int g_nDataPin; 15 | static unsigned int g_nClockPin; 16 | unsigned int m_nDataBit; 17 | unsigned int m_nClockBit; 18 | }; 19 | #endif//OUTPUT_PROTOCOLS_CSPIBITBANG_H 20 | -------------------------------------------------------------------------------- /user/output_protocols/CSPIHardware.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "CSPIHardware.h" 3 | extern "C" { 4 | #include 5 | #include 6 | #include 7 | } 8 | #include 9 | #include 10 | #pragma GCC diagnostic ignored "-Wparentheses" 11 | #include 12 | 13 | unsigned int CSPIHardware::g_nClockDiv = 0; 14 | bool CSPIHardware::g_bUseInterrupts = true; 15 | 16 | BEGIN_CONFIG(CSPIHardware::config,"hspi", "HSPI configuration"); 17 | CONFIG_SELECTSTART("clockdiv","Speed",&g_nClockDiv,0); 18 | CONFIG_SELECTOPTION("40mhz", 0); //80/(0+1) 19 | CONFIG_SELECTOPTION("20mhz", 1); //80/(1+1) 20 | CONFIG_SELECTOPTION("14mhz", 2); //80/(2+1) = 21 | CONFIG_SELECTOPTION("10mhz", 3); //80/(3+1) 22 | CONFIG_SELECTOPTION("5mhz", 7); 23 | CONFIG_SELECTOPTION("2.5mhz", 15); 24 | CONFIG_SELECTEND(); 25 | CONFIG_BOOLEAN("use_int", "Interrupt driven", &g_bUseInterrupts, true); 26 | END_CONFIG(); 27 | 28 | CSPIHardware::CSPIHardware() { 29 | m_nBytesLeft = 0; 30 | m_bTransmissionDone = true; 31 | m_pWords = m_pCurWords = 0; 32 | 33 | // TODO: Check this, what is this value before, and what exactly should be cleared? 34 | WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); //clear bit 9? 35 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2); // Clock 36 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2); // Data 37 | // Only use MOSI, disable all other options 38 | WRITE_PERI_REG(SPI_USER(1), SPI_USR_MOSI); 39 | //Clock 40 | WRITE_PERI_REG(SPI_CLOCK(1), 41 | ((g_nClockDiv&SPI_CLKDIV_PRE)<(nDataLen - (nCurWord * 4), 16 * 4); 84 | size_t nBits = (nBytes*8)-1; 85 | 86 | while (READ_PERI_REG(SPI_CMD(1)) & SPI_USR); // Wait for transmission to end 87 | for (unsigned int reg = SPI_W0(1); reg <= SPI_W15(1) && nCurWord < nWordsLen; reg+=4, nCurWord++) 88 | WRITE_PERI_REG(reg, pWords[nCurWord]); 89 | 90 | WRITE_PERI_REG(SPI_USER1(1), nBits << SPI_USR_MOSI_BITLEN_S); 91 | SET_PERI_REG_MASK(SPI_CMD(1), SPI_USR); 92 | } 93 | delete[] pWords; 94 | } 95 | } 96 | 97 | void __attribute__((section(".nospi"))) CSPIHardware::int_handler(void *pThis) { 98 | if (READ_PERI_REG(0x3FF00020) & BIT7) { 99 | // HSPI 100 | unsigned int regvalue = READ_PERI_REG(SPI_SLAVE(1)); 101 | CLEAR_PERI_REG_MASK(SPI_SLAVE(1), (SPI_TRANS_DONE|SPI_SLV_WR_STA_DONE|SPI_SLV_RD_STA_DONE | SPI_SLV_WR_BUF_DONE|SPI_SLV_RD_BUF_DONE) & regvalue); 102 | 103 | if (regvalue & SPI_TRANS_DONE) { 104 | ((CSPIHardware *)pThis)->int_handler_transmit_done(); 105 | } 106 | } 107 | if (READ_PERI_REG(0x3ff00020) & BIT4) { 108 | // SPI 109 | CLEAR_PERI_REG_MASK(SPI_SLAVE(0), 0x3FF); 110 | } 111 | } 112 | 113 | void __attribute__((section(".nospi"))) CSPIHardware::int_handler_transmit_done() { 114 | if (m_nBytesLeft) { 115 | size_t nBytes = std::min(m_nBytesLeft, 16 * 4); 116 | size_t nBits = (nBytes*8)-1; 117 | size_t nWords = (nBytes+3)/4; 118 | 119 | for (unsigned int reg = SPI_W0(1); reg < SPI_W0(1) + (4*nWords); reg+=4) 120 | WRITE_PERI_REG(reg, *(m_pCurWords++)); 121 | // Set number of bits 122 | WRITE_PERI_REG(SPI_USER1(1), nBits << SPI_USR_MOSI_BITLEN_S); 123 | // Mark as done 124 | m_nBytesLeft -= nBytes; 125 | // Start transmission 126 | SET_PERI_REG_MASK(SPI_CMD(1), SPI_USR); 127 | } else { 128 | m_bTransmissionDone = true; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /user/output_protocols/CSPIHardware.h: -------------------------------------------------------------------------------- 1 | #ifndef OUTPUT_PROTOCOLS_CSPIHARDWARE_H 2 | #define OUTPUT_PROTOCOLS_CSPIHARDWARE_H 3 | #include "ISPIInterface.h" 4 | #include "config/config.h" 5 | 6 | class CSPIHardware : public ISPIInterface { 7 | public: 8 | CSPIHardware(); 9 | ~CSPIHardware(); 10 | void output(const uint8_t *pData, size_t nDataLen); 11 | 12 | static DEFINE_CONFIG(config); 13 | private: 14 | static void int_handler(void *pThis); 15 | void int_handler_transmit_done(); 16 | static unsigned int g_nClockDiv; 17 | static bool g_bUseInterrupts; 18 | 19 | uint32_t *m_pWords; 20 | uint32_t *m_pCurWords; 21 | size_t m_nBytesLeft; 22 | bool m_bTransmissionDone; 23 | }; 24 | #endif//OUTPUT_PROTOCOLS_CSPIHARDWARE_H 25 | -------------------------------------------------------------------------------- /user/output_protocols/CWS2801Output.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * user_ws2801.c 3 | * 4 | * Created on: Nov 18, 2014 5 | * Author: frans-willem 6 | */ 7 | #include "CWS2801Output.h" 8 | #include "ISPIInterface.h" 9 | #include 10 | 11 | 12 | 13 | CWS2801Output::CWS2801Output(unsigned int nLength, ISPIInterface *pSpi) : COutput(nLength) { 14 | m_pSpi = pSpi; 15 | } 16 | 17 | CWS2801Output::~CWS2801Output() { 18 | delete m_pSpi; 19 | } 20 | 21 | void CWS2801Output::output(const uint8_t *pData) { 22 | m_pSpi->output(pData, m_nLength); 23 | } 24 | -------------------------------------------------------------------------------- /user/output_protocols/CWS2801Output.h: -------------------------------------------------------------------------------- 1 | #ifndef OUTPUT_PROTOCOLS_CWS2801OUTPUT_H 2 | #define OUTPUT_PROTOCOLS_CWS2801OUTPUT_H 3 | #include "COutput.h" 4 | #include "config/config.h" 5 | 6 | class ISPIInterface; 7 | class CWS2801Output : public COutput { 8 | public: 9 | CWS2801Output(unsigned int nLength, ISPIInterface *pSpi); 10 | ~CWS2801Output(); 11 | virtual void output(const uint8_t *pData); 12 | private: 13 | ISPIInterface *m_pSpi; 14 | }; 15 | #endif//OUTPUT_PROTOCOLS_CWS2801OUTPUT_H 16 | -------------------------------------------------------------------------------- /user/output_protocols/ISPIInterface.cpp: -------------------------------------------------------------------------------- 1 | #include "ISPIInterface.h" 2 | 3 | ISPIInterface::~ISPIInterface() { 4 | 5 | } 6 | 7 | void ISPIInterface::output(const uint8_t *pData, size_t nLength) { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /user/output_protocols/ISPIInterface.h: -------------------------------------------------------------------------------- 1 | #ifndef OUTPUT_PROTOCOLS_ISPIINTERFACE_H 2 | #define OUTPUT_PROTOCOLS_ISPIINTERFACE_H 3 | #include 4 | #include 5 | 6 | class ISPIInterface { 7 | public: 8 | virtual ~ISPIInterface(); 9 | virtual void output(const uint8_t *pData, size_t nDataLen); 10 | }; 11 | #endif//OUTPUT_PROTOCOLS_ISPIINTERFACE_H 12 | 13 | -------------------------------------------------------------------------------- /user/output_protocols/output.cpp: -------------------------------------------------------------------------------- 1 | #include "output.h" 2 | #include "config/config.h" 3 | #include "COutput.h" 4 | #include "CWS2801Output.h" 5 | #include "CSPIBitbang.h" 6 | #include "CSPIHardware.h" 7 | #include "C3WireOutput.h" 8 | #include "C3WireEncoder.h" 9 | #include 10 | #include "CColorCorrector.h" 11 | #include "CLimiter.h" 12 | 13 | namespace Output { 14 | enum OutputMode { 15 | Output_Dummy, 16 | Output_WS2801_BB, 17 | Output_WS2801_HSPI, 18 | Output_WS281X_800, 19 | Output_WS281X_400 20 | }; 21 | // Config 22 | uint32_t nOutputMode; 23 | uint32_t nOutputLength; 24 | bool bLum2Duty; 25 | bool bGamma; 26 | float fGamma; 27 | // Globals 28 | COutput* pOutput = NULL; 29 | uint8_t *pCurrentFrame; 30 | // Global related to framerate limiter 31 | uint32_t nLimiterFreq; 32 | 33 | BEGIN_CONFIG(config,"output","Output") 34 | CONFIG_SELECTSTART("mode", "Mode", &nOutputMode, Output_Dummy); 35 | CONFIG_SELECTOPTION("None", Output_Dummy); 36 | CONFIG_SELECTOPTION("WS2801 (SPI Bitbang)", Output_WS2801_BB); 37 | CONFIG_SELECTOPTION("WS2801 (HSPI)", Output_WS2801_HSPI); 38 | CONFIG_SELECTOPTION("WS2811/WS2812 @ 800khz", Output_WS281X_800); 39 | CONFIG_SELECTOPTION("WS2811/WS2812 @ 400khz", Output_WS281X_400); 40 | CONFIG_SELECTEND(); 41 | CONFIG_INT("length","Number of channels",&nOutputLength, 1, 512, 450); 42 | CONFIG_BOOLEAN("lum2duty","Luminance correction", &bLum2Duty, false); 43 | CONFIG_BOOLEAN("gamma","Gamma correction", &bGamma, false); 44 | CONFIG_FLOAT("gammaValue","Gamma", &fGamma, 1.5f); 45 | CONFIG_INT("frameratecap","Maximum framerate", &nLimiterFreq, 0, 1000, 30); 46 | CONFIG_SUB(CSPIBitbang::config); 47 | CONFIG_SUB(CSPIHardware::config); 48 | END_CONFIG(); 49 | 50 | 51 | 52 | void init() { 53 | pCurrentFrame = new uint8_t[nOutputLength]; 54 | switch (nOutputMode) { 55 | case Output_WS2801_BB: 56 | pOutput = new CWS2801Output(nOutputLength, new CSPIBitbang()); 57 | break; 58 | case Output_WS2801_HSPI: 59 | pOutput = new CWS2801Output(nOutputLength, new CSPIHardware()); 60 | break; 61 | case Output_WS281X_800: 62 | pOutput = new C3WireOutput(nOutputLength, 10, 5, new C3WireEncoder<4,4,1,2>()); 63 | break; 64 | case Output_WS281X_400: 65 | pOutput = new C3WireOutput(nOutputLength, 10, 10, new C3WireEncoder<4,4,1,2>()); 66 | break; 67 | default: 68 | pOutput = new COutput(nOutputLength); 69 | break; 70 | } 71 | pOutput = CColorCorrector::wrap(pOutput, bGamma, fGamma, bLum2Duty); 72 | pOutput = CLimiter::wrap(pOutput, nLimiterFreq); 73 | } 74 | 75 | void deinit() { 76 | delete pOutput; 77 | delete[] pCurrentFrame; 78 | } 79 | 80 | void output(const uint8_t *pData, size_t nLength) { 81 | partial(0,pData,nLength,true); 82 | } 83 | 84 | void partial(size_t nOffset, const uint8_t *pData, size_t nLength, bool bFlush) { 85 | if (nOffset < nOutputLength) { 86 | if (nLength + nOffset > nOutputLength) 87 | nLength= nOutputLength-nOffset; 88 | uint8_t *pTarget = &pCurrentFrame[nOffset]; 89 | memcpy(pTarget, pData, nLength * sizeof(uint8_t)); 90 | } 91 | if (bFlush) 92 | pOutput->output(pCurrentFrame); 93 | } 94 | }//namespace Output 95 | -------------------------------------------------------------------------------- /user/output_protocols/output.h: -------------------------------------------------------------------------------- 1 | #ifndef OUTPUT_PROTOCOLS_OUTPUT_H 2 | #define OUTPUT_PROTOCOLS_OUTPUT_H 3 | #include 4 | #include 5 | #include "config/config.h" 6 | 7 | namespace Output { 8 | DEFINE_CONFIG(config); 9 | void init(); 10 | void deinit(); 11 | void output(const uint8_t *pData, size_t nLength); 12 | void partial(size_t nOffset, const uint8_t *pData, size_t nLength, bool bFlush); 13 | void try_push_frame(); 14 | void limiter_timer_cb(void *); 15 | } 16 | #endif//OUTPUT_PROTOCOLS_OUTPUT_H 17 | -------------------------------------------------------------------------------- /user/wifisetup.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | extern "C" { 3 | #include 4 | #include 5 | #include 6 | } 7 | #include "wifisetup.h" 8 | #include "config/config.h" 9 | #include 10 | 11 | char szWifiDefaultSsid[32]; 12 | char szDefaultHostname[64]; 13 | 14 | unsigned int nWifiMode; 15 | char szWifiSsid[32]; 16 | char szWifiPassword[64]; 17 | bool bUseDhcp; 18 | char szHostname[64]; 19 | uint32_t aIP; 20 | uint32_t aNetmask; 21 | uint32_t aGateway; 22 | 23 | BEGIN_CONFIG(wifi, "wifi", "WiFi"); 24 | CONFIG_SELECTSTART("mode","Operation mode", &nWifiMode, SOFTAP_MODE); 25 | CONFIG_SELECTOPTION("Access point", SOFTAP_MODE); 26 | CONFIG_SELECTOPTION("Client", STATION_MODE); 27 | CONFIG_SELECTEND(); 28 | CONFIG_STRING("ssid", "SSID", szWifiSsid, sizeof(szWifiSsid)-1, szWifiDefaultSsid); 29 | CONFIG_STRING("password","Password", szWifiPassword, sizeof(szWifiPassword)-1,""); 30 | END_CONFIG(); 31 | BEGIN_CONFIG(network, "net", "Network"); 32 | CONFIG_STRING("hostname", "Hostname", szHostname, sizeof(szHostname)-1, szDefaultHostname); 33 | CONFIG_BOOLEAN("dhcp","Automatic configuration (DHCP)", &bUseDhcp, true); 34 | CONFIG_IP("ip","IP Address", &aIP, 192, 168, 1, 1); 35 | CONFIG_IP("netmask","Netmask", &aNetmask, 255, 255, 255, 0); 36 | CONFIG_IP("gateway","Gateway", &aGateway, 192, 168, 1, 1); 37 | END_CONFIG(); 38 | 39 | void wifi_setup_defaults() { 40 | os_sprintf(szWifiDefaultSsid,"EspLightNode%X", system_get_chip_id()); 41 | os_sprintf(szDefaultHostname, "EspLightNode%X", system_get_chip_id()); 42 | } 43 | 44 | void wifi_init() { 45 | wifi_set_opmode(NULL_MODE); //Next time start up in NULL mode 46 | wifi_set_opmode_current(NULL_MODE); 47 | 48 | //Initialize station config parameters 49 | struct station_config stconf; 50 | memset(&stconf, 0, sizeof(stconf)); 51 | strncpy((char *)stconf.ssid, szWifiSsid, sizeof(stconf.ssid)); 52 | strncpy((char *)stconf.password, szWifiPassword, sizeof(stconf.password)); 53 | stconf.ssid[sizeof(stconf.ssid)-1]='\0'; 54 | stconf.password[sizeof(stconf.password)-1]='\0'; 55 | 56 | //Initialize AP config parameters 57 | struct softap_config apconf; 58 | memset(&apconf, 0, sizeof(apconf)); 59 | // SSID 60 | strncpy((char *)apconf.ssid, szWifiSsid, sizeof(apconf.ssid)); 61 | apconf.ssid[sizeof(apconf.ssid)-1]='\0'; 62 | // Password & encryption 63 | strncpy((char *)apconf.password, szWifiPassword, sizeof(apconf.password)); 64 | apconf.password[sizeof(apconf.password)-1]='\0'; 65 | if (strlen(szWifiPassword) >= 8) { 66 | apconf.authmode = AUTH_WPA_WPA2_PSK; 67 | } else { 68 | // if password <8 characters, don't use password. 69 | apconf.authmode = AUTH_WEP; 70 | memset(apconf.password, 0, sizeof(apconf.password)); 71 | } 72 | apconf.max_connection = 255; 73 | apconf.beacon_interval = 100; 74 | 75 | wifi_set_opmode_current(nWifiMode); 76 | wifi_softap_set_config_current(&apconf); 77 | wifi_station_set_config_current(&stconf); 78 | 79 | struct ip_info ipinfo; 80 | memset(&ipinfo, 0, sizeof(ipinfo)); 81 | ipinfo.ip.addr = aIP; 82 | ipinfo.netmask.addr = aNetmask; 83 | ipinfo.gw.addr = aGateway; 84 | 85 | if (nWifiMode == STATION_MODE) { 86 | wifi_station_dhcpc_stop(); 87 | wifi_station_set_hostname(szHostname); 88 | if (bUseDhcp) { 89 | wifi_station_dhcpc_start(); 90 | } else { 91 | wifi_set_ip_info(STATION_IF, &ipinfo); 92 | } 93 | } else { 94 | // DHCP Server should be stopped to change IP information 95 | wifi_softap_dhcps_stop(); 96 | wifi_set_ip_info(SOFTAP_IF, &ipinfo); 97 | 98 | uint32_t aFirstIp = (aIP & aNetmask) | 1; 99 | uint32_t aLastIp = (aIP & aNetmask) | (-1 & ~aNetmask); 100 | struct dhcps_lease leases; 101 | memset(&leases, 0, sizeof(leases)); 102 | // Determine whether the range before or after our IP is bigger 103 | if (aIP - aFirstIp > aLastIp - aIP) { 104 | leases.start_ip.addr = aFirstIp; 105 | leases.end_ip.addr = aIP - 1; 106 | } else { 107 | leases.start_ip.addr = aIP + 1; 108 | leases.end_ip.addr = aLastIp; 109 | } 110 | wifi_softap_set_dhcps_lease(&leases); 111 | uint8_t offer_router = 0; 112 | wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, &offer_router); 113 | wifi_softap_dhcps_start(); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /user/wifisetup.h: -------------------------------------------------------------------------------- 1 | #ifndef WIFISETUP_H 2 | #define WIFISETUP_H 3 | void wifi_setup_defaults(); 4 | void wifi_init(); 5 | #endif//WIFISETUP_H 6 | --------------------------------------------------------------------------------