Initial commit
This commit is contained in:
		
						commit
						1375656363
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| build | ||||
| old.w | ||||
							
								
								
									
										14
									
								
								.vimspector.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								.vimspector.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| { | ||||
|   "configurations": { | ||||
|     "Launch": { | ||||
|       "adapter": "vscode-cpptools", | ||||
|       "configuration": { | ||||
|         "request": "launch", | ||||
|         "program": "./build/librnode_test", | ||||
|         "args": [], | ||||
|         "cwd": "~/Work/Repos/librnode/", | ||||
|         "MIMode": "gdb" | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										619
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										619
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,619 @@ | ||||
|                     GNU GENERAL PUBLIC LICENSE | ||||
|                        Version 3, 29 June 2007 | ||||
| 
 | ||||
|  Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> | ||||
|  Everyone is permitted to copy and distribute verbatim copies | ||||
|  of this license document, but changing it is not allowed. | ||||
| 
 | ||||
|                             Preamble | ||||
| 
 | ||||
|   The GNU General Public License is a free, copyleft license for | ||||
| software and other kinds of works. | ||||
| 
 | ||||
|   The licenses for most software and other practical works are designed | ||||
| to take away your freedom to share and change the works.  By contrast, | ||||
| the GNU General Public License is intended to guarantee your freedom to | ||||
| share and change all versions of a program--to make sure it remains free | ||||
| software for all its users.  We, the Free Software Foundation, use the | ||||
| GNU General Public License for most of our software; it applies also to | ||||
| any other work released this way by its authors.  You can apply it to | ||||
| your programs, too. | ||||
| 
 | ||||
|   When we speak of free software, we are referring to freedom, not | ||||
| price.  Our General Public Licenses are designed to make sure that you | ||||
| have the freedom to distribute copies of free software (and charge for | ||||
| them if you wish), that you receive source code or can get it if you | ||||
| want it, that you can change the software or use pieces of it in new | ||||
| free programs, and that you know you can do these things. | ||||
| 
 | ||||
|   To protect your rights, we need to prevent others from denying you | ||||
| these rights or asking you to surrender the rights.  Therefore, you have | ||||
| certain responsibilities if you distribute copies of the software, or if | ||||
| you modify it: responsibilities to respect the freedom of others. | ||||
| 
 | ||||
|   For example, if you distribute copies of such a program, whether | ||||
| gratis or for a fee, you must pass on to the recipients the same | ||||
| freedoms that you received.  You must make sure that they, too, receive | ||||
| or can get the source code.  And you must show them these terms so they | ||||
| know their rights. | ||||
| 
 | ||||
|   Developers that use the GNU GPL protect your rights with two steps: | ||||
| (1) assert copyright on the software, and (2) offer you this License | ||||
| giving you legal permission to copy, distribute and/or modify it. | ||||
| 
 | ||||
|   For the developers' and authors' protection, the GPL clearly explains | ||||
| that there is no warranty for this free software.  For both users' and | ||||
| authors' sake, the GPL requires that modified versions be marked as | ||||
| changed, so that their problems will not be attributed erroneously to | ||||
| authors of previous versions. | ||||
| 
 | ||||
|   Some devices are designed to deny users access to install or run | ||||
| modified versions of the software inside them, although the manufacturer | ||||
| can do so.  This is fundamentally incompatible with the aim of | ||||
| protecting users' freedom to change the software.  The systematic | ||||
| pattern of such abuse occurs in the area of products for individuals to | ||||
| use, which is precisely where it is most unacceptable.  Therefore, we | ||||
| have designed this version of the GPL to prohibit the practice for those | ||||
| products.  If such problems arise substantially in other domains, we | ||||
| stand ready to extend this provision to those domains in future versions | ||||
| of the GPL, as needed to protect the freedom of users. | ||||
| 
 | ||||
|   Finally, every program is threatened constantly by software patents. | ||||
| States should not allow patents to restrict development and use of | ||||
| software on general-purpose computers, but in those that do, we wish to | ||||
| avoid the special danger that patents applied to a free program could | ||||
| make it effectively proprietary.  To prevent this, the GPL assures that | ||||
| patents cannot be used to render the program non-free. | ||||
| 
 | ||||
|   The precise terms and conditions for copying, distribution and | ||||
| modification follow. | ||||
| 
 | ||||
|                        TERMS AND CONDITIONS | ||||
| 
 | ||||
|   0. Definitions. | ||||
| 
 | ||||
|   "This License" refers to version 3 of the GNU General Public License. | ||||
| 
 | ||||
|   "Copyright" also means copyright-like laws that apply to other kinds of | ||||
| works, such as semiconductor masks. | ||||
| 
 | ||||
|   "The Program" refers to any copyrightable work licensed under this | ||||
| License.  Each licensee is addressed as "you".  "Licensees" and | ||||
| "recipients" may be individuals or organizations. | ||||
| 
 | ||||
|   To "modify" a work means to copy from or adapt all or part of the work | ||||
| in a fashion requiring copyright permission, other than the making of an | ||||
| exact copy.  The resulting work is called a "modified version" of the | ||||
| earlier work or a work "based on" the earlier work. | ||||
| 
 | ||||
|   A "covered work" means either the unmodified Program or a work based | ||||
| on the Program. | ||||
| 
 | ||||
|   To "propagate" a work means to do anything with it that, without | ||||
| permission, would make you directly or secondarily liable for | ||||
| infringement under applicable copyright law, except executing it on a | ||||
| computer or modifying a private copy.  Propagation includes copying, | ||||
| distribution (with or without modification), making available to the | ||||
| public, and in some countries other activities as well. | ||||
| 
 | ||||
|   To "convey" a work means any kind of propagation that enables other | ||||
| parties to make or receive copies.  Mere interaction with a user through | ||||
| a computer network, with no transfer of a copy, is not conveying. | ||||
| 
 | ||||
|   An interactive user interface displays "Appropriate Legal Notices" | ||||
| to the extent that it includes a convenient and prominently visible | ||||
| feature that (1) displays an appropriate copyright notice, and (2) | ||||
| tells the user that there is no warranty for the work (except to the | ||||
| extent that warranties are provided), that licensees may convey the | ||||
| work under this License, and how to view a copy of this License.  If | ||||
| the interface presents a list of user commands or options, such as a | ||||
| menu, a prominent item in the list meets this criterion. | ||||
| 
 | ||||
|   1. Source Code. | ||||
| 
 | ||||
|   The "source code" for a work means the preferred form of the work | ||||
| for making modifications to it.  "Object code" means any non-source | ||||
| form of a work. | ||||
| 
 | ||||
|   A "Standard Interface" means an interface that either is an official | ||||
| standard defined by a recognized standards body, or, in the case of | ||||
| interfaces specified for a particular programming language, one that | ||||
| is widely used among developers working in that language. | ||||
| 
 | ||||
|   The "System Libraries" of an executable work include anything, other | ||||
| than the work as a whole, that (a) is included in the normal form of | ||||
| packaging a Major Component, but which is not part of that Major | ||||
| Component, and (b) serves only to enable use of the work with that | ||||
| Major Component, or to implement a Standard Interface for which an | ||||
| implementation is available to the public in source code form.  A | ||||
| "Major Component", in this context, means a major essential component | ||||
| (kernel, window system, and so on) of the specific operating system | ||||
| (if any) on which the executable work runs, or a compiler used to | ||||
| produce the work, or an object code interpreter used to run it. | ||||
| 
 | ||||
|   The "Corresponding Source" for a work in object code form means all | ||||
| the source code needed to generate, install, and (for an executable | ||||
| work) run the object code and to modify the work, including scripts to | ||||
| control those activities.  However, it does not include the work's | ||||
| System Libraries, or general-purpose tools or generally available free | ||||
| programs which are used unmodified in performing those activities but | ||||
| which are not part of the work.  For example, Corresponding Source | ||||
| includes interface definition files associated with source files for | ||||
| the work, and the source code for shared libraries and dynamically | ||||
| linked subprograms that the work is specifically designed to require, | ||||
| such as by intimate data communication or control flow between those | ||||
| subprograms and other parts of the work. | ||||
| 
 | ||||
|   The Corresponding Source need not include anything that users | ||||
| can regenerate automatically from other parts of the Corresponding | ||||
| Source. | ||||
| 
 | ||||
|   The Corresponding Source for a work in source code form is that | ||||
| same work. | ||||
| 
 | ||||
|   2. Basic Permissions. | ||||
| 
 | ||||
|   All rights granted under this License are granted for the term of | ||||
| copyright on the Program, and are irrevocable provided the stated | ||||
| conditions are met.  This License explicitly affirms your unlimited | ||||
| permission to run the unmodified Program.  The output from running a | ||||
| covered work is covered by this License only if the output, given its | ||||
| content, constitutes a covered work.  This License acknowledges your | ||||
| rights of fair use or other equivalent, as provided by copyright law. | ||||
| 
 | ||||
|   You may make, run and propagate covered works that you do not | ||||
| convey, without conditions so long as your license otherwise remains | ||||
| in force.  You may convey covered works to others for the sole purpose | ||||
| of having them make modifications exclusively for you, or provide you | ||||
| with facilities for running those works, provided that you comply with | ||||
| the terms of this License in conveying all material for which you do | ||||
| not control copyright.  Those thus making or running the covered works | ||||
| for you must do so exclusively on your behalf, under your direction | ||||
| and control, on terms that prohibit them from making any copies of | ||||
| your copyrighted material outside their relationship with you. | ||||
| 
 | ||||
|   Conveying under any other circumstances is permitted solely under | ||||
| the conditions stated below.  Sublicensing is not allowed; section 10 | ||||
| makes it unnecessary. | ||||
| 
 | ||||
|   3. Protecting Users' Legal Rights From Anti-Circumvention Law. | ||||
| 
 | ||||
|   No covered work shall be deemed part of an effective technological | ||||
| measure under any applicable law fulfilling obligations under article | ||||
| 11 of the WIPO copyright treaty adopted on 20 December 1996, or | ||||
| similar laws prohibiting or restricting circumvention of such | ||||
| measures. | ||||
| 
 | ||||
|   When you convey a covered work, you waive any legal power to forbid | ||||
| circumvention of technological measures to the extent such circumvention | ||||
| is effected by exercising rights under this License with respect to | ||||
| the covered work, and you disclaim any intention to limit operation or | ||||
| modification of the work as a means of enforcing, against the work's | ||||
| users, your or third parties' legal rights to forbid circumvention of | ||||
| technological measures. | ||||
| 
 | ||||
|   4. Conveying Verbatim Copies. | ||||
| 
 | ||||
|   You may convey verbatim copies of the Program's source code as you | ||||
| receive it, in any medium, provided that you conspicuously and | ||||
| appropriately publish on each copy an appropriate copyright notice; | ||||
| keep intact all notices stating that this License and any | ||||
| non-permissive terms added in accord with section 7 apply to the code; | ||||
| keep intact all notices of the absence of any warranty; and give all | ||||
| recipients a copy of this License along with the Program. | ||||
| 
 | ||||
|   You may charge any price or no price for each copy that you convey, | ||||
| and you may offer support or warranty protection for a fee. | ||||
| 
 | ||||
|   5. Conveying Modified Source Versions. | ||||
| 
 | ||||
|   You may convey a work based on the Program, or the modifications to | ||||
| produce it from the Program, in the form of source code under the | ||||
| terms of section 4, provided that you also meet all of these conditions: | ||||
| 
 | ||||
|     a) The work must carry prominent notices stating that you modified | ||||
|     it, and giving a relevant date. | ||||
| 
 | ||||
|     b) The work must carry prominent notices stating that it is | ||||
|     released under this License and any conditions added under section | ||||
|     7.  This requirement modifies the requirement in section 4 to | ||||
|     "keep intact all notices". | ||||
| 
 | ||||
|     c) You must license the entire work, as a whole, under this | ||||
|     License to anyone who comes into possession of a copy.  This | ||||
|     License will therefore apply, along with any applicable section 7 | ||||
|     additional terms, to the whole of the work, and all its parts, | ||||
|     regardless of how they are packaged.  This License gives no | ||||
|     permission to license the work in any other way, but it does not | ||||
|     invalidate such permission if you have separately received it. | ||||
| 
 | ||||
|     d) If the work has interactive user interfaces, each must display | ||||
|     Appropriate Legal Notices; however, if the Program has interactive | ||||
|     interfaces that do not display Appropriate Legal Notices, your | ||||
|     work need not make them do so. | ||||
| 
 | ||||
|   A compilation of a covered work with other separate and independent | ||||
| works, which are not by their nature extensions of the covered work, | ||||
| and which are not combined with it such as to form a larger program, | ||||
| in or on a volume of a storage or distribution medium, is called an | ||||
| "aggregate" if the compilation and its resulting copyright are not | ||||
| used to limit the access or legal rights of the compilation's users | ||||
| beyond what the individual works permit.  Inclusion of a covered work | ||||
| in an aggregate does not cause this License to apply to the other | ||||
| parts of the aggregate. | ||||
| 
 | ||||
|   6. Conveying Non-Source Forms. | ||||
| 
 | ||||
|   You may convey a covered work in object code form under the terms | ||||
| of sections 4 and 5, provided that you also convey the | ||||
| machine-readable Corresponding Source under the terms of this License, | ||||
| in one of these ways: | ||||
| 
 | ||||
|     a) Convey the object code in, or embodied in, a physical product | ||||
|     (including a physical distribution medium), accompanied by the | ||||
|     Corresponding Source fixed on a durable physical medium | ||||
|     customarily used for software interchange. | ||||
| 
 | ||||
|     b) Convey the object code in, or embodied in, a physical product | ||||
|     (including a physical distribution medium), accompanied by a | ||||
|     written offer, valid for at least three years and valid for as | ||||
|     long as you offer spare parts or customer support for that product | ||||
|     model, to give anyone who possesses the object code either (1) a | ||||
|     copy of the Corresponding Source for all the software in the | ||||
|     product that is covered by this License, on a durable physical | ||||
|     medium customarily used for software interchange, for a price no | ||||
|     more than your reasonable cost of physically performing this | ||||
|     conveying of source, or (2) access to copy the | ||||
|     Corresponding Source from a network server at no charge. | ||||
| 
 | ||||
|     c) Convey individual copies of the object code with a copy of the | ||||
|     written offer to provide the Corresponding Source.  This | ||||
|     alternative is allowed only occasionally and noncommercially, and | ||||
|     only if you received the object code with such an offer, in accord | ||||
|     with subsection 6b. | ||||
| 
 | ||||
|     d) Convey the object code by offering access from a designated | ||||
|     place (gratis or for a charge), and offer equivalent access to the | ||||
|     Corresponding Source in the same way through the same place at no | ||||
|     further charge.  You need not require recipients to copy the | ||||
|     Corresponding Source along with the object code.  If the place to | ||||
|     copy the object code is a network server, the Corresponding Source | ||||
|     may be on a different server (operated by you or a third party) | ||||
|     that supports equivalent copying facilities, provided you maintain | ||||
|     clear directions next to the object code saying where to find the | ||||
|     Corresponding Source.  Regardless of what server hosts the | ||||
|     Corresponding Source, you remain obligated to ensure that it is | ||||
|     available for as long as needed to satisfy these requirements. | ||||
| 
 | ||||
|     e) Convey the object code using peer-to-peer transmission, provided | ||||
|     you inform other peers where the object code and Corresponding | ||||
|     Source of the work are being offered to the general public at no | ||||
|     charge under subsection 6d. | ||||
| 
 | ||||
|   A separable portion of the object code, whose source code is excluded | ||||
| from the Corresponding Source as a System Library, need not be | ||||
| included in conveying the object code work. | ||||
| 
 | ||||
|   A "User Product" is either (1) a "consumer product", which means any | ||||
| tangible personal property which is normally used for personal, family, | ||||
| or household purposes, or (2) anything designed or sold for incorporation | ||||
| into a dwelling.  In determining whether a product is a consumer product, | ||||
| doubtful cases shall be resolved in favor of coverage.  For a particular | ||||
| product received by a particular user, "normally used" refers to a | ||||
| typical or common use of that class of product, regardless of the status | ||||
| of the particular user or of the way in which the particular user | ||||
| actually uses, or expects or is expected to use, the product.  A product | ||||
| is a consumer product regardless of whether the product has substantial | ||||
| commercial, industrial or non-consumer uses, unless such uses represent | ||||
| the only significant mode of use of the product. | ||||
| 
 | ||||
|   "Installation Information" for a User Product means any methods, | ||||
| procedures, authorization keys, or other information required to install | ||||
| and execute modified versions of a covered work in that User Product from | ||||
| a modified version of its Corresponding Source.  The information must | ||||
| suffice to ensure that the continued functioning of the modified object | ||||
| code is in no case prevented or interfered with solely because | ||||
| modification has been made. | ||||
| 
 | ||||
|   If you convey an object code work under this section in, or with, or | ||||
| specifically for use in, a User Product, and the conveying occurs as | ||||
| part of a transaction in which the right of possession and use of the | ||||
| User Product is transferred to the recipient in perpetuity or for a | ||||
| fixed term (regardless of how the transaction is characterized), the | ||||
| Corresponding Source conveyed under this section must be accompanied | ||||
| by the Installation Information.  But this requirement does not apply | ||||
| if neither you nor any third party retains the ability to install | ||||
| modified object code on the User Product (for example, the work has | ||||
| been installed in ROM). | ||||
| 
 | ||||
|   The requirement to provide Installation Information does not include a | ||||
| requirement to continue to provide support service, warranty, or updates | ||||
| for a work that has been modified or installed by the recipient, or for | ||||
| the User Product in which it has been modified or installed.  Access to a | ||||
| network may be denied when the modification itself materially and | ||||
| adversely affects the operation of the network or violates the rules and | ||||
| protocols for communication across the network. | ||||
| 
 | ||||
|   Corresponding Source conveyed, and Installation Information provided, | ||||
| in accord with this section must be in a format that is publicly | ||||
| documented (and with an implementation available to the public in | ||||
| source code form), and must require no special password or key for | ||||
| unpacking, reading or copying. | ||||
| 
 | ||||
|   7. Additional Terms. | ||||
| 
 | ||||
|   "Additional permissions" are terms that supplement the terms of this | ||||
| License by making exceptions from one or more of its conditions. | ||||
| Additional permissions that are applicable to the entire Program shall | ||||
| be treated as though they were included in this License, to the extent | ||||
| that they are valid under applicable law.  If additional permissions | ||||
| apply only to part of the Program, that part may be used separately | ||||
| under those permissions, but the entire Program remains governed by | ||||
| this License without regard to the additional permissions. | ||||
| 
 | ||||
|   When you convey a copy of a covered work, you may at your option | ||||
| remove any additional permissions from that copy, or from any part of | ||||
| it.  (Additional permissions may be written to require their own | ||||
| removal in certain cases when you modify the work.)  You may place | ||||
| additional permissions on material, added by you to a covered work, | ||||
| for which you have or can give appropriate copyright permission. | ||||
| 
 | ||||
|   Notwithstanding any other provision of this License, for material you | ||||
| add to a covered work, you may (if authorized by the copyright holders of | ||||
| that material) supplement the terms of this License with terms: | ||||
| 
 | ||||
|     a) Disclaiming warranty or limiting liability differently from the | ||||
|     terms of sections 15 and 16 of this License; or | ||||
| 
 | ||||
|     b) Requiring preservation of specified reasonable legal notices or | ||||
|     author attributions in that material or in the Appropriate Legal | ||||
|     Notices displayed by works containing it; or | ||||
| 
 | ||||
|     c) Prohibiting misrepresentation of the origin of that material, or | ||||
|     requiring that modified versions of such material be marked in | ||||
|     reasonable ways as different from the original version; or | ||||
| 
 | ||||
|     d) Limiting the use for publicity purposes of names of licensors or | ||||
|     authors of the material; or | ||||
| 
 | ||||
|     e) Declining to grant rights under trademark law for use of some | ||||
|     trade names, trademarks, or service marks; or | ||||
| 
 | ||||
|     f) Requiring indemnification of licensors and authors of that | ||||
|     material by anyone who conveys the material (or modified versions of | ||||
|     it) with contractual assumptions of liability to the recipient, for | ||||
|     any liability that these contractual assumptions directly impose on | ||||
|     those licensors and authors. | ||||
| 
 | ||||
|   All other non-permissive additional terms are considered "further | ||||
| restrictions" within the meaning of section 10.  If the Program as you | ||||
| received it, or any part of it, contains a notice stating that it is | ||||
| governed by this License along with a term that is a further | ||||
| restriction, you may remove that term.  If a license document contains | ||||
| a further restriction but permits relicensing or conveying under this | ||||
| License, you may add to a covered work material governed by the terms | ||||
| of that license document, provided that the further restriction does | ||||
| not survive such relicensing or conveying. | ||||
| 
 | ||||
|   If you add terms to a covered work in accord with this section, you | ||||
| must place, in the relevant source files, a statement of the | ||||
| additional terms that apply to those files, or a notice indicating | ||||
| where to find the applicable terms. | ||||
| 
 | ||||
|   Additional terms, permissive or non-permissive, may be stated in the | ||||
| form of a separately written license, or stated as exceptions; | ||||
| the above requirements apply either way. | ||||
| 
 | ||||
|   8. Termination. | ||||
| 
 | ||||
|   You may not propagate or modify a covered work except as expressly | ||||
| provided under this License.  Any attempt otherwise to propagate or | ||||
| modify it is void, and will automatically terminate your rights under | ||||
| this License (including any patent licenses granted under the third | ||||
| paragraph of section 11). | ||||
| 
 | ||||
|   However, if you cease all violation of this License, then your | ||||
| license from a particular copyright holder is reinstated (a) | ||||
| provisionally, unless and until the copyright holder explicitly and | ||||
| finally terminates your license, and (b) permanently, if the copyright | ||||
| holder fails to notify you of the violation by some reasonable means | ||||
| prior to 60 days after the cessation. | ||||
| 
 | ||||
|   Moreover, your license from a particular copyright holder is | ||||
| reinstated permanently if the copyright holder notifies you of the | ||||
| violation by some reasonable means, this is the first time you have | ||||
| received notice of violation of this License (for any work) from that | ||||
| copyright holder, and you cure the violation prior to 30 days after | ||||
| your receipt of the notice. | ||||
| 
 | ||||
|   Termination of your rights under this section does not terminate the | ||||
| licenses of parties who have received copies or rights from you under | ||||
| this License.  If your rights have been terminated and not permanently | ||||
| reinstated, you do not qualify to receive new licenses for the same | ||||
| material under section 10. | ||||
| 
 | ||||
|   9. Acceptance Not Required for Having Copies. | ||||
| 
 | ||||
|   You are not required to accept this License in order to receive or | ||||
| run a copy of the Program.  Ancillary propagation of a covered work | ||||
| occurring solely as a consequence of using peer-to-peer transmission | ||||
| to receive a copy likewise does not require acceptance.  However, | ||||
| nothing other than this License grants you permission to propagate or | ||||
| modify any covered work.  These actions infringe copyright if you do | ||||
| not accept this License.  Therefore, by modifying or propagating a | ||||
| covered work, you indicate your acceptance of this License to do so. | ||||
| 
 | ||||
|   10. Automatic Licensing of Downstream Recipients. | ||||
| 
 | ||||
|   Each time you convey a covered work, the recipient automatically | ||||
| receives a license from the original licensors, to run, modify and | ||||
| propagate that work, subject to this License.  You are not responsible | ||||
| for enforcing compliance by third parties with this License. | ||||
| 
 | ||||
|   An "entity transaction" is a transaction transferring control of an | ||||
| organization, or substantially all assets of one, or subdividing an | ||||
| organization, or merging organizations.  If propagation of a covered | ||||
| work results from an entity transaction, each party to that | ||||
| transaction who receives a copy of the work also receives whatever | ||||
| licenses to the work the party's predecessor in interest had or could | ||||
| give under the previous paragraph, plus a right to possession of the | ||||
| Corresponding Source of the work from the predecessor in interest, if | ||||
| the predecessor has it or can get it with reasonable efforts. | ||||
| 
 | ||||
|   You may not impose any further restrictions on the exercise of the | ||||
| rights granted or affirmed under this License.  For example, you may | ||||
| not impose a license fee, royalty, or other charge for exercise of | ||||
| rights granted under this License, and you may not initiate litigation | ||||
| (including a cross-claim or counterclaim in a lawsuit) alleging that | ||||
| any patent claim is infringed by making, using, selling, offering for | ||||
| sale, or importing the Program or any portion of it. | ||||
| 
 | ||||
|   11. Patents. | ||||
| 
 | ||||
|   A "contributor" is a copyright holder who authorizes use under this | ||||
| License of the Program or a work on which the Program is based.  The | ||||
| work thus licensed is called the contributor's "contributor version". | ||||
| 
 | ||||
|   A contributor's "essential patent claims" are all patent claims | ||||
| owned or controlled by the contributor, whether already acquired or | ||||
| hereafter acquired, that would be infringed by some manner, permitted | ||||
| by this License, of making, using, or selling its contributor version, | ||||
| but do not include claims that would be infringed only as a | ||||
| consequence of further modification of the contributor version.  For | ||||
| purposes of this definition, "control" includes the right to grant | ||||
| patent sublicenses in a manner consistent with the requirements of | ||||
| this License. | ||||
| 
 | ||||
|   Each contributor grants you a non-exclusive, worldwide, royalty-free | ||||
| patent license under the contributor's essential patent claims, to | ||||
| make, use, sell, offer for sale, import and otherwise run, modify and | ||||
| propagate the contents of its contributor version. | ||||
| 
 | ||||
|   In the following three paragraphs, a "patent license" is any express | ||||
| agreement or commitment, however denominated, not to enforce a patent | ||||
| (such as an express permission to practice a patent or covenant not to | ||||
| sue for patent infringement).  To "grant" such a patent license to a | ||||
| party means to make such an agreement or commitment not to enforce a | ||||
| patent against the party. | ||||
| 
 | ||||
|   If you convey a covered work, knowingly relying on a patent license, | ||||
| and the Corresponding Source of the work is not available for anyone | ||||
| to copy, free of charge and under the terms of this License, through a | ||||
| publicly available network server or other readily accessible means, | ||||
| then you must either (1) cause the Corresponding Source to be so | ||||
| available, or (2) arrange to deprive yourself of the benefit of the | ||||
| patent license for this particular work, or (3) arrange, in a manner | ||||
| consistent with the requirements of this License, to extend the patent | ||||
| license to downstream recipients.  "Knowingly relying" means you have | ||||
| actual knowledge that, but for the patent license, your conveying the | ||||
| covered work in a country, or your recipient's use of the covered work | ||||
| in a country, would infringe one or more identifiable patents in that | ||||
| country that you have reason to believe are valid. | ||||
| 
 | ||||
|   If, pursuant to or in connection with a single transaction or | ||||
| arrangement, you convey, or propagate by procuring conveyance of, a | ||||
| covered work, and grant a patent license to some of the parties | ||||
| receiving the covered work authorizing them to use, propagate, modify | ||||
| or convey a specific copy of the covered work, then the patent license | ||||
| you grant is automatically extended to all recipients of the covered | ||||
| work and works based on it. | ||||
| 
 | ||||
|   A patent license is "discriminatory" if it does not include within | ||||
| the scope of its coverage, prohibits the exercise of, or is | ||||
| conditioned on the non-exercise of one or more of the rights that are | ||||
| specifically granted under this License.  You may not convey a covered | ||||
| work if you are a party to an arrangement with a third party that is | ||||
| in the business of distributing software, under which you make payment | ||||
| to the third party based on the extent of your activity of conveying | ||||
| the work, and under which the third party grants, to any of the | ||||
| parties who would receive the covered work from you, a discriminatory | ||||
| patent license (a) in connection with copies of the covered work | ||||
| conveyed by you (or copies made from those copies), or (b) primarily | ||||
| for and in connection with specific products or compilations that | ||||
| contain the covered work, unless you entered into that arrangement, | ||||
| or that patent license was granted, prior to 28 March 2007. | ||||
| 
 | ||||
|   Nothing in this License shall be construed as excluding or limiting | ||||
| any implied license or other defenses to infringement that may | ||||
| otherwise be available to you under applicable patent law. | ||||
| 
 | ||||
|   12. No Surrender of Others' Freedom. | ||||
| 
 | ||||
|   If conditions are imposed on you (whether by court order, agreement or | ||||
| otherwise) that contradict the conditions of this License, they do not | ||||
| excuse you from the conditions of this License.  If you cannot convey a | ||||
| covered work so as to satisfy simultaneously your obligations under this | ||||
| License and any other pertinent obligations, then as a consequence you may | ||||
| not convey it at all.  For example, if you agree to terms that obligate you | ||||
| to collect a royalty for further conveying from those to whom you convey | ||||
| the Program, the only way you could satisfy both those terms and this | ||||
| License would be to refrain entirely from conveying the Program. | ||||
| 
 | ||||
|   13. Use with the GNU Affero General Public License. | ||||
| 
 | ||||
|   Notwithstanding any other provision of this License, you have | ||||
| permission to link or combine any covered work with a work licensed | ||||
| under version 3 of the GNU Affero General Public License into a single | ||||
| combined work, and to convey the resulting work.  The terms of this | ||||
| License will continue to apply to the part which is the covered work, | ||||
| but the special requirements of the GNU Affero General Public License, | ||||
| section 13, concerning interaction through a network will apply to the | ||||
| combination as such. | ||||
| 
 | ||||
|   14. Revised Versions of this License. | ||||
| 
 | ||||
|   The Free Software Foundation may publish revised and/or new versions of | ||||
| the GNU General Public License from time to time.  Such new versions will | ||||
| be similar in spirit to the present version, but may differ in detail to | ||||
| address new problems or concerns. | ||||
| 
 | ||||
|   Each version is given a distinguishing version number.  If the | ||||
| Program specifies that a certain numbered version of the GNU General | ||||
| Public License "or any later version" applies to it, you have the | ||||
| option of following the terms and conditions either of that numbered | ||||
| version or of any later version published by the Free Software | ||||
| Foundation.  If the Program does not specify a version number of the | ||||
| GNU General Public License, you may choose any version ever published | ||||
| by the Free Software Foundation. | ||||
| 
 | ||||
|   If the Program specifies that a proxy can decide which future | ||||
| versions of the GNU General Public License can be used, that proxy's | ||||
| public statement of acceptance of a version permanently authorizes you | ||||
| to choose that version for the Program. | ||||
| 
 | ||||
|   Later license versions may give you additional or different | ||||
| permissions.  However, no additional obligations are imposed on any | ||||
| author or copyright holder as a result of your choosing to follow a | ||||
| later version. | ||||
| 
 | ||||
|   15. Disclaimer of Warranty. | ||||
| 
 | ||||
|   THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY | ||||
| APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT | ||||
| HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY | ||||
| OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, | ||||
| THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||||
| PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM | ||||
| IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF | ||||
| ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | ||||
| 
 | ||||
|   16. Limitation of Liability. | ||||
| 
 | ||||
|   IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||||
| WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS | ||||
| THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY | ||||
| GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE | ||||
| USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF | ||||
| DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD | ||||
| PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), | ||||
| EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF | ||||
| SUCH DAMAGES. | ||||
| 
 | ||||
|   17. Interpretation of Sections 15 and 16. | ||||
| 
 | ||||
|   If the disclaimer of warranty and limitation of liability provided | ||||
| above cannot be given local legal effect according to their terms, | ||||
| reviewing courts shall apply local law that most closely approximates | ||||
| an absolute waiver of all civil liability in connection with the | ||||
| Program, unless a warranty or assumption of liability accompanies a | ||||
| copy of the Program in return for a fee. | ||||
							
								
								
									
										40
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | ||||
| # Copyright (c) 2025 Jacob Eva (Liberated Embedded Systems)
 | ||||
| # This program is free software: you can redistribute it and/or modify it
 | ||||
| # under the terms of the GNU General Public License as published by the Free
 | ||||
| # Software Foundation, either version 3 of the License, or (at your option)
 | ||||
| # any later version.
 | ||||
| # This program is distributed in the hope that it will be useful, but WITHOUT
 | ||||
| # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | ||||
| # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 | ||||
| # more details.
 | ||||
| # You should have received a copy of the GNU General Public License along
 | ||||
| # with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| # This makefile is for GNU / Linux.
 | ||||
| 
 | ||||
| CC=gcc | ||||
| FLAGS=-DLOG_USE_COLOR -l crypto | ||||
| LIB=librnode | ||||
| SRCS=$(shell find src ! -name '*win32.c' -name '*.c' -type f) | ||||
| OBJS=$(patsubst %.c,%.o,$(SRCS)) | ||||
| F_OBJS=$(notdir $(OBJS)) | ||||
| 
 | ||||
| all: $(OBJS) | ||||
| 	ar cr build/$(LIB).a -o $(F_OBJS) | ||||
| 	mv *.o build | ||||
| 
 | ||||
| %.o: %.c | ||||
| 	$(CC) $(FLAGS) $< -c | ||||
| 
 | ||||
| debug: FLAGS+=-g | ||||
| debug: all | ||||
| 
 | ||||
| test: all | ||||
| 	$(CC) tests/test.c -L build -l rnode -l tap -l crypto -l md -o build/librnode_test | ||||
| 
 | ||||
| test-debug: debug | ||||
| 	$(CC) tests/test.c -L build -l rnode -l tap -l crypto -l md -g -o build/librnode_test | ||||
| 
 | ||||
| clean: | ||||
| 	- rm -rf build | ||||
| 	- mkdir build | ||||
							
								
								
									
										37
									
								
								Makefile.win32
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								Makefile.win32
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| CC = gcc | ||||
| CFLAGS = -Wall -O2 -I. -DWIN32 | ||||
| BIN = UartSecureDFU | ||||
| 
 | ||||
| DEPS = crc32.h \
 | ||||
|        delay_connect.h \
 | ||||
|        dfu.h \
 | ||||
|        dfu_serial.h \
 | ||||
|        logging.h \
 | ||||
|        slip_enc.h \
 | ||||
|        uart_drv.h \
 | ||||
|        uart_slip.h \
 | ||||
|        zip.h \
 | ||||
|        miniz.h \
 | ||||
|        jsmn.h \
 | ||||
|        Makefile | ||||
| 
 | ||||
| OBJS = crc32.o \
 | ||||
|        delay_connect.o \
 | ||||
|        dfu.o \
 | ||||
|        dfu_serial.o \
 | ||||
|        jsmn.o \
 | ||||
|        logging.o \
 | ||||
|        slip_enc.o \
 | ||||
|        uart_win32.o \
 | ||||
|        UartSecureDFU.o \
 | ||||
|        uart_slip.o \
 | ||||
|        zip.o | ||||
| 
 | ||||
| %.o: %.c $(DEPS) | ||||
| 	$(CC) $(CFLAGS) -c $< -o $@ | ||||
| 
 | ||||
| $(BIN): $(OBJS) | ||||
| 	$(CC) $(OBJS) -o $(BIN) | ||||
| 
 | ||||
| clean:  | ||||
| 	rm -f $(BIN) $(OBJS) | ||||
							
								
								
									
										3
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| `librnode` is a C library which provides an object to interface with | ||||
| transcievers built on the RNode platform. It is intended for use in RNode | ||||
| configuration applications. | ||||
							
								
								
									
										1769
									
								
								src/librnode.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										1769
									
								
								src/librnode.c
									
									
									
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										476
									
								
								src/librnode.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										476
									
								
								src/librnode.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,476 @@ | ||||
| /* Copyright (c) 2025 - Jacob Eva (Liberated Embedded Systems)
 | ||||
|  * This program is free software: you can redistribute it and/or modify it | ||||
|  * under the terms of the GNU General Public License as published by the Free | ||||
|  * Software Foundation, either version 3 of the License, or (at your option) | ||||
|  * any later version. | ||||
|  * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
|  * more details. | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #ifndef LIBRNODE_H | ||||
| 
 | ||||
| #define LIBRNODE_H | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <openssl/evp.h> | ||||
| #include <openssl/rsa.h> | ||||
| 
 | ||||
| #define MIN_FW_VER 1.66 | ||||
| 
 | ||||
| // PLATFORMS
 | ||||
| #define PLATFORM_ESP32 0x80 | ||||
| #define PLATFORM_NRF52 0x70 | ||||
| //
 | ||||
| 
 | ||||
| #define SERIAL_SIZE 4 | ||||
| 
 | ||||
| #define MADE_SIZE 4 | ||||
| 
 | ||||
| #define CHECKSUM_SIZE 16 | ||||
| 
 | ||||
| #define SIGNATURE_SIZE 128 | ||||
| 
 | ||||
| #define FW_HASH_SIZE 256 / 8 | ||||
| 
 | ||||
| #define RESP_BUF_SIZE 512 | ||||
| 
 | ||||
| #define EEPROM_SIZE 296 | ||||
| 
 | ||||
| #define MAX_INTERFACES 256 | ||||
| 
 | ||||
| #define FILE_MAX_SIZE 4 * 1024 * 1024 // 4MB max file size for single fw binary
 | ||||
| 
 | ||||
| // BLUETOOTH VALUES
 | ||||
| #define BT_OFF 0 | ||||
| #define BT_ON 1 | ||||
| #define BT_PAIRING 2 | ||||
| //
 | ||||
| 
 | ||||
| struct RNode { | ||||
|     char* port; | ||||
|     int fd; | ||||
|     uint32_t baud; | ||||
| 
 | ||||
|     uint8_t platform; | ||||
|     uint8_t mcu; | ||||
| 
 | ||||
|     // EEPROM below here!
 | ||||
| 
 | ||||
|     uint8_t product; | ||||
|     uint8_t model; | ||||
|     uint8_t hw_rev; | ||||
| 
 | ||||
|     uint8_t serial[4]; | ||||
| 
 | ||||
|     uint8_t made[4]; | ||||
| 
 | ||||
|     uint8_t checksum[16]; | ||||
| 
 | ||||
|     uint8_t signature[128]; | ||||
| 
 | ||||
|     uint8_t lock_byte; | ||||
| 
 | ||||
|     // All these have their own getter functions as they can change on runtime; the cached EEPROM values may not reflect the true status of the radio
 | ||||
|     uint8_t sf; | ||||
|     uint8_t cr; | ||||
|     uint8_t txp; | ||||
|     uint32_t bw; | ||||
|     uint32_t freq; | ||||
| 
 | ||||
|     uint8_t cfg_ok; | ||||
| 
 | ||||
|     bool bt; | ||||
| 
 | ||||
|     bool disp_set; | ||||
|     uint8_t disp_int; | ||||
|     uint8_t disp_addr; | ||||
| 
 | ||||
|     // This is where the EEPROM read directly from the RNode is stored
 | ||||
|     uint8_t r_eeprom[EEPROM_SIZE];  | ||||
| 
 | ||||
|     // END EEPROM
 | ||||
| 
 | ||||
|     float st_alock; | ||||
|     float lt_alock; | ||||
| 
 | ||||
|     uint32_t bt_pairing_pin; | ||||
| 
 | ||||
|     // ESP32 only!
 | ||||
| 
 | ||||
|     uint32_t boot_app0_addr; | ||||
|     uint32_t bootloader_addr; | ||||
|     uint32_t bin_addr; | ||||
|     uint32_t partitions_addr; | ||||
|     uint32_t console_image_addr; | ||||
| 
 | ||||
|     //
 | ||||
| 
 | ||||
|     float fw_ver; | ||||
| 
 | ||||
|     bool connected; | ||||
| 
 | ||||
|     // Multiple modems
 | ||||
| 
 | ||||
|     uint8_t sel_int; | ||||
| 
 | ||||
|     uint8_t interfaces[MAX_INTERFACES]; | ||||
| 
 | ||||
|     //
 | ||||
| 
 | ||||
|     void (*prog_cb)(uint8_t); | ||||
| }; | ||||
| 
 | ||||
| /* Establishes communication with an RNode
 | ||||
|  * Params: port (e.g. /dev/ttyACM0), baud rate (e.g. 115200), detect (attempt | ||||
|  * to communicate with RNode), force_detect (fail if cannot communicate with | ||||
|  * RNode) | ||||
|  * Scope: public | ||||
|  * Returns: | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_init(struct RNode* rn, char* path, uint32_t baud, bool detect, bool force_detect); | ||||
| 
 | ||||
| /* Resets an RNode
 | ||||
|  * Scope: public | ||||
|  * Returns: | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_reset(struct RNode* rn); | ||||
| 
 | ||||
| /* Sets an RNode's platform attribute manually
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_platform(struct RNode* rn, uint8_t platform); | ||||
| 
 | ||||
| /* Enable / disable Bluetooth on an RNode
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * > 0 - bluetooth pairing pin value | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  * -4 - rnode did not respond | ||||
|  */ | ||||
| int rnode_set_bt(struct RNode* rn, uint8_t val); | ||||
| 
 | ||||
| /* Attempt to retrieve the BT pairing code of an RNode. Blocking function,
 | ||||
|  * should be run in a separate thread. | ||||
|  * Params: timeout (in ms, minimum value 200) | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * > 0 - bluetooth pairing code | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  * -4 - rnode did not respond | ||||
|  */ | ||||
| int rnode_get_bt_pin(struct RNode* rn, uint32_t timeout); | ||||
| 
 | ||||
| /* Display related functions */ | ||||
| 
 | ||||
| /* Set display intensity on an RNode
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_disp_int(struct RNode* rn, uint8_t disp_int); | ||||
| 
 | ||||
| /* Set display timeout on an RNode
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_disp_timeout(struct RNode* rn, uint8_t timeout); | ||||
| 
 | ||||
| /* Set display address on an RNode
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_disp_addr(struct RNode* rn, uint8_t addr); | ||||
| 
 | ||||
| #define DISPLAY_PORTRAIT 0 | ||||
| #define DISPLAY_LANDSCAPE 1 | ||||
| #define DISPLAY_PORTRAIT_INV 2 | ||||
| #define DISPLAY_LANDSCAPE_INV 3 | ||||
| /* Set display rotation on an RNode
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_disp_rot(struct RNode* rn, uint8_t rot); | ||||
| 
 | ||||
| /* Start display reconditioning on an RNode
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_start_disp_recon(struct RNode* rn); | ||||
| 
 | ||||
| /* Set neopixel intensity on an RNode
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_np_int(struct RNode* rn, uint8_t np_int); | ||||
| 
 | ||||
| /* Get available interfaces on an RNode
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_get_interfaces(struct RNode* rn); | ||||
| 
 | ||||
| /* Select interface on an RNode (in preparation for running rnode_set_freq, etc)
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_select_interface(struct RNode* rn, uint8_t modem); | ||||
| 
 | ||||
| /* Set frequency on an RNode (in preparation for TNC mode)
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_freq(struct RNode* rn, uint32_t freq); | ||||
| 
 | ||||
| /* Get frequency on an RNode
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_get_freq(struct RNode* rn); | ||||
| 
 | ||||
| /* Set bandwidth on an RNode (in preparation for TNC mode)
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_bw(struct RNode* rn, uint32_t bw); | ||||
| 
 | ||||
| /* Get bandwidth on an RNode 
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_get_bw(struct RNode* rn); | ||||
| 
 | ||||
| /* Set transmission power on an RNode 
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_txp(struct RNode* rn, uint8_t txp); | ||||
| 
 | ||||
| /* Get transmission power on an RNode 
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_get_txp(struct RNode* rn); | ||||
| 
 | ||||
| /* Set spreading factor on an RNode 
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_sf(struct RNode* rn, uint8_t sf); | ||||
| 
 | ||||
| /* Get spreading factor on an RNode 
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_get_sf(struct RNode* rn); | ||||
| 
 | ||||
| /* Set coding rate on an RNode 
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_cr(struct RNode* rn, uint8_t cr); | ||||
| 
 | ||||
| /* Get coding rate on an RNode 
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_get_cr(struct RNode* rn); | ||||
| 
 | ||||
| /* Set short term airtime limit on an RNode 
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| float rnode_set_st_alock(struct RNode* rn, float at_l); | ||||
| 
 | ||||
| /* Set long term airtime limit on an RNode 
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| float rnode_set_lt_alock(struct RNode* rn, float at_l); | ||||
| 
 | ||||
| /* Set radio modem state (on or off)
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_radio_state(struct RNode* rn, bool state); | ||||
| 
 | ||||
| /* Mode selection functions */ | ||||
| 
 | ||||
| /* Enable the host-controlled (normal) mode of operation on an RNode
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_normal_mode(struct RNode* rn); | ||||
| 
 | ||||
| /* Enable the serial TNC mode of operation on an RNode
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_tnc_mode(struct RNode* rn); | ||||
| 
 | ||||
| /* EEPROM related functions */ | ||||
| 
 | ||||
| /* Sets the firmware hash on an RNode.
 | ||||
|  * Scope: public | ||||
|  * Returns: | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_fw_hash(struct RNode* rn, uint8_t* hash); | ||||
| 
 | ||||
| /* Sets an RNode's product in its EEPROM
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_product(struct RNode* rn, uint8_t product); | ||||
| 
 | ||||
| /* Sets an RNode's model in its EEPROM
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_model(struct RNode* rn, uint8_t model); | ||||
| 
 | ||||
| /* Sets an RNode's hardware revision in its EEPROM
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_hw_rev(struct RNode* rn, uint8_t hw_rev); | ||||
| 
 | ||||
| /* Generate's an RNode's EEPROM signature from the checksum
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| void* rnode_generate_signature(struct RNode* rn, EVP_PKEY *signing_key); | ||||
| 
 | ||||
| /* Sets an RNode's signature in its EEPROM
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_signature(struct RNode* rn, uint8_t* data); | ||||
| 
 | ||||
| /* Sets an RNode's lock byte in its EEPROM
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_set_lock(struct RNode* rn); | ||||
| 
 | ||||
| /* Retrieve an RNode's EEPROM values into its struct
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_get_eeprom(struct RNode* rn); | ||||
| 
 | ||||
| /* Dump an RNode's entire EEPROM to r_eeprom
 | ||||
|  * Note: This will populate r_eeprom but not the cached EEPROM values. If you | ||||
|  * want to update the cached values, call rnode_get_eeprom instead. | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  */ | ||||
| int rnode_dump_eeprom(struct RNode* rn); | ||||
| 
 | ||||
| /* Verify an RNode's EEPROM matches the expected values
 | ||||
|  * Scope: public | ||||
|  * Returns | ||||
|  * 0 - success | ||||
|  * value > 0 or value < 0 - EEPROM invalid | ||||
|  */ | ||||
| int rnode_verify_eeprom(struct RNode* rn); | ||||
| 
 | ||||
| /* Wipes an RNode's EEPROM.
 | ||||
|  * Scope: public | ||||
|  * Returns: | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  * -2 - rnode not supported (firmware too old, please update) | ||||
|  */ | ||||
| int rnode_wipe_eeprom(struct RNode* rn); | ||||
| 
 | ||||
| 
 | ||||
| /* Flashes an RNode. 
 | ||||
|  * Scope: public | ||||
|  * Returns: | ||||
|  * 0 - success | ||||
|  * -1 - generic error | ||||
|  * -9 - ESP32 image invalid, SHA256 digest incorrect | ||||
|  */ | ||||
| int rnode_flash(struct RNode* rn, char* zip_path, bool update, uint8_t* serial, EVP_PKEY* priv_key, bool touch); | ||||
| 
 | ||||
| 
 | ||||
| int rnode_cleanup(struct RNode* rn); | ||||
| 
 | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										19
									
								
								src/libs/eeprom.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/libs/eeprom.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| #ifndef EEPROM_H | ||||
|     #define EEPROM_H | ||||
|     #define ADDR_PRODUCT   0x00 | ||||
|     #define ADDR_MODEL     0x01 | ||||
|     #define ADDR_HW_REV    0x02 | ||||
|     #define ADDR_SERIAL    0x03 | ||||
|     #define ADDR_MADE      0x07 | ||||
|     #define ADDR_CHKSUM    0x0B | ||||
|     #define ADDR_SIGNATURE 0x1B | ||||
|     #define ADDR_INFO_LOCK 0x9B | ||||
|     #define ADDR_CONF_SF   0x9C | ||||
|     #define ADDR_CONF_CR   0x9D | ||||
|     #define ADDR_CONF_TXP  0x9E | ||||
|     #define ADDR_CONF_BW   0x9F | ||||
|     #define ADDR_CONF_FREQ 0xA3 | ||||
|     #define ADDR_CONF_OK   0xA7 | ||||
|     #define INFO_LOCK_BYTE 0x73 | ||||
|     #define CONF_OK_BYTE   0x73 | ||||
| #endif | ||||
							
								
								
									
										21
									
								
								src/libs/flashers/esp32/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/libs/flashers/esp32/LICENSE
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| MIT License | ||||
| 
 | ||||
| Copyright (c) 2021,2022 Cesanta | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
							
								
								
									
										3
									
								
								src/libs/flashers/esp32/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/libs/flashers/esp32/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| Original repo can be found here: https://github.com/cpq/esputil | ||||
| 
 | ||||
| Modified for use in librnode. | ||||
							
								
								
									
										1218
									
								
								src/libs/flashers/esp32/esputil.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1218
									
								
								src/libs/flashers/esp32/esputil.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										8
									
								
								src/libs/flashers/esp32/esputil.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/libs/flashers/esp32/esputil.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| #ifndef ESPUTIL_H | ||||
| 
 | ||||
| #define ESPUTIL_H | ||||
| 
 | ||||
| #include "../../../librnode.h" | ||||
| 
 | ||||
| int flash_full(struct RNode* rn, char* boot_app0, size_t boot_app0_size, char* bootloader, size_t bootloader_size, char* bin, size_t bin_size, char* partitions, size_t partitions_size, char* console, size_t console_size); | ||||
| #endif | ||||
							
								
								
									
										20
									
								
								src/libs/flashers/nrf/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/libs/flashers/nrf/LICENSE
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| Copyright (c) 2010 Serge A. Zaitsev | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in | ||||
| all copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
| THE SOFTWARE. | ||||
| 
 | ||||
							
								
								
									
										39
									
								
								src/libs/flashers/nrf/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/libs/flashers/nrf/Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | ||||
| CC = gcc | ||||
| CFLAGS = -Wall -O2 -I. -g -O0 -DLOG_USE_COLOR | ||||
| BIN = UartSecureDFU | ||||
| 
 | ||||
| DEPS = crc16.h \
 | ||||
|        dfu.h \
 | ||||
|        dfu_serial.h \
 | ||||
| 	   hci.h \
 | ||||
|        slip_enc.h \
 | ||||
|        uart_drv.h \
 | ||||
|        uart_slip.h \
 | ||||
|        zip.h \
 | ||||
|        miniz.h \
 | ||||
|        jsmn.h \
 | ||||
| 	   ../../../util.h \
 | ||||
| 	   ../../logging/log.h \
 | ||||
|        Makefile | ||||
| 
 | ||||
| OBJS = crc16.o \
 | ||||
|        dfu.o \
 | ||||
|        dfu_serial.o \
 | ||||
| 	   hci.o \
 | ||||
|        jsmn.o \
 | ||||
|        slip_enc.o \
 | ||||
|        uart_linux.o \
 | ||||
|        UartSecureDFU.o \
 | ||||
|        uart_slip.o \
 | ||||
| 	   ../../../util.o \
 | ||||
| 	   ../../logging/log.o \
 | ||||
|        zip.o | ||||
| 
 | ||||
| %.o: %.c $(DEPS) | ||||
| 	$(CC) $(CFLAGS) -c $< -o $@ | ||||
| 
 | ||||
| $(BIN): $(OBJS) | ||||
| 	$(CC) $(OBJS) -o $(BIN) | ||||
| 
 | ||||
| clean:  | ||||
| 	rm -f $(BIN) $(OBJS) | ||||
							
								
								
									
										37
									
								
								src/libs/flashers/nrf/Makefile.win32
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/libs/flashers/nrf/Makefile.win32
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| CC = gcc | ||||
| CFLAGS = -Wall -O2 -I. -DWIN32 | ||||
| BIN = UartSecureDFU | ||||
| 
 | ||||
| DEPS = crc32.h \
 | ||||
|        delay_connect.h \
 | ||||
|        dfu.h \
 | ||||
|        dfu_serial.h \
 | ||||
|        logging.h \
 | ||||
|        slip_enc.h \
 | ||||
|        uart_drv.h \
 | ||||
|        uart_slip.h \
 | ||||
|        zip.h \
 | ||||
|        miniz.h \
 | ||||
|        jsmn.h \
 | ||||
|        Makefile | ||||
| 
 | ||||
| OBJS = crc32.o \
 | ||||
|        delay_connect.o \
 | ||||
|        dfu.o \
 | ||||
|        dfu_serial.o \
 | ||||
|        jsmn.o \
 | ||||
|        logging.o \
 | ||||
|        slip_enc.o \
 | ||||
|        uart_win32.o \
 | ||||
|        UartSecureDFU.o \
 | ||||
|        uart_slip.o \
 | ||||
|        zip.o | ||||
| 
 | ||||
| %.o: %.c $(DEPS) | ||||
| 	$(CC) $(CFLAGS) -c $< -o $@ | ||||
| 
 | ||||
| $(BIN): $(OBJS) | ||||
| 	$(CC) $(OBJS) -o $(BIN) | ||||
| 
 | ||||
| clean:  | ||||
| 	rm -f $(BIN) $(OBJS) | ||||
							
								
								
									
										17
									
								
								src/libs/flashers/nrf/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/libs/flashers/nrf/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | ||||
| # librnode - nRF52 serial DFU flasher | ||||
| 
 | ||||
| This utility is for flashing nRF52-based modules which run the Adafruit bootloader, for example the RAK4631. | ||||
| 
 | ||||
| It is based on the `nrf-slim-serial-uart-dfu-host-c-code` project by [Jimmy Wong](https://github.com/jimmywong2003/nrf-slim-serial-uart-dfu-host-c-code), which has been extended to specifically support devices with an Adafruit bootloader. This has been achieved by referencing Adafruit nRFutil and [Liam Cottle's web flasher for RNodes](https://github.com/liamcottle/rnode-flasher). | ||||
| 
 | ||||
| UART bit rate is 115200bps with 8-N-1 data format. RTS/CTS flow control is | ||||
| disabled. This program takes the DFU package ZIP file generated by | ||||
| `adafruit-nrfutil`, which is used in the | ||||
| [RNode_Firmware](https://github.com/markqvist/RNode_Firmware) project's build | ||||
| system. | ||||
| 
 | ||||
| ## Supports  | ||||
| 
 | ||||
| nRF52840 (tested). | ||||
| 
 | ||||
| Whether this flasher will work on other nRF52 chips is currently unknown, but it is expected they *should* work. | ||||
							
								
								
									
										67
									
								
								src/libs/flashers/nrf/crc16.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/libs/flashers/nrf/crc16.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,67 @@ | ||||
| /**
 | ||||
|  * Copyright (c) 2013 - 2018, Nordic Semiconductor ASA | ||||
|  *  | ||||
|  * All rights reserved. | ||||
|  *  | ||||
|  * Redistribution and use in source and binary forms, with or without modification, | ||||
|  * are permitted provided that the following conditions are met: | ||||
|  *  | ||||
|  * 1. Redistributions of source code must retain the above copyright notice, this | ||||
|  *    list of conditions and the following disclaimer. | ||||
|  *  | ||||
|  * 2. Redistributions in binary form, except as embedded into a Nordic | ||||
|  *    Semiconductor ASA integrated circuit in a product or a software update for | ||||
|  *    such product, must reproduce the above copyright notice, this list of | ||||
|  *    conditions and the following disclaimer in the documentation and/or other | ||||
|  *    materials provided with the distribution. | ||||
|  *  | ||||
|  * 3. Neither the name of Nordic Semiconductor ASA nor the names of its | ||||
|  *    contributors may be used to endorse or promote products derived from this | ||||
|  *    software without specific prior written permission. | ||||
|  *  | ||||
|  * 4. This software, with or without modification, must only be used with a | ||||
|  *    Nordic Semiconductor ASA integrated circuit. | ||||
|  *  | ||||
|  * 5. Any software provided in binary form under this license must not be reverse | ||||
|  *    engineered, decompiled, modified and/or disassembled. | ||||
|  *  | ||||
|  * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS | ||||
|  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
|  * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE | ||||
|  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
|  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||||
|  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
|  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
|  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | ||||
|  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  *  | ||||
|  * Modified by Jacob Eva (Liberated Embedded Systems) (c) 2025. | ||||
|  * Changes licensed under the GPL. | ||||
|  * This program is free software: you can redistribute it and/or modify it | ||||
|  * under the terms of the GNU General Public License as published by the Free | ||||
|  * Software Foundation, either version 3 of the License, or (at your option) | ||||
|  * any later version. | ||||
|  * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
|  * more details. | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| #include "crc16.h" | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| uint16_t crc16_compute(uint8_t const * p_data, uint16_t data_len) | ||||
| { | ||||
|     uint16_t crc = 0xFFFF; | ||||
|     for (int i = 0; i < data_len; i++) { | ||||
|         crc = (crc >> 8 & 0x00FF) | (crc << 8 & 0xFF00); | ||||
|         crc = crc ^ p_data[i]; | ||||
|         crc = crc ^ (crc & 0x00FF) >> 4; | ||||
|         crc = crc ^ (crc << 8) << 4; | ||||
|         crc = crc ^ ((crc & 0x00FF) << 4) << 1; | ||||
|     } | ||||
|     return crc; | ||||
| } | ||||
							
								
								
									
										91
									
								
								src/libs/flashers/nrf/crc16.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								src/libs/flashers/nrf/crc16.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,91 @@ | ||||
| /**
 | ||||
|  * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA | ||||
|  *  | ||||
|  * All rights reserved. | ||||
|  *  | ||||
|  * Redistribution and use in source and binary forms, with or without modification, | ||||
|  * are permitted provided that the following conditions are met: | ||||
|  *  | ||||
|  * 1. Redistributions of source code must retain the above copyright notice, this | ||||
|  *    list of conditions and the following disclaimer. | ||||
|  *  | ||||
|  * 2. Redistributions in binary form, except as embedded into a Nordic | ||||
|  *    Semiconductor ASA integrated circuit in a product or a software update for | ||||
|  *    such product, must reproduce the above copyright notice, this list of | ||||
|  *    conditions and the following disclaimer in the documentation and/or other | ||||
|  *    materials provided with the distribution. | ||||
|  *  | ||||
|  * 3. Neither the name of Nordic Semiconductor ASA nor the names of its | ||||
|  *    contributors may be used to endorse or promote products derived from this | ||||
|  *    software without specific prior written permission. | ||||
|  *  | ||||
|  * 4. This software, with or without modification, must only be used with a | ||||
|  *    Nordic Semiconductor ASA integrated circuit. | ||||
|  *  | ||||
|  * 5. Any software provided in binary form under this license must not be reverse | ||||
|  *    engineered, decompiled, modified and/or disassembled. | ||||
|  *  | ||||
|  * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS | ||||
|  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
|  * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE | ||||
|  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
|  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||||
|  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
|  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
|  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | ||||
|  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  *  | ||||
|  * Modified by Jacob Eva (Liberated Embedded Systems) (c) 2025. | ||||
|  * Changes licensed under the GPL. | ||||
|  * This program is free software: you can redistribute it and/or modify it | ||||
|  * under the terms of the GNU General Public License as published by the Free | ||||
|  * Software Foundation, either version 3 of the License, or (at your option) | ||||
|  * any later version. | ||||
|  * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
|  * more details. | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| /** @file
 | ||||
|  * | ||||
|  * @defgroup crc16 CRC16 compute | ||||
|  * @{ | ||||
|  * @ingroup hci_transport | ||||
|  * | ||||
|  * @brief    This module implements the CRC-16 calculation in the blocks. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef CRC16_H__ | ||||
| #define CRC16_H__ | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /**@brief Function for calculating CRC-16 in blocks.
 | ||||
|  * | ||||
|  * Feed each consecutive data block into this function, along with the current value of p_crc as | ||||
|  * returned by the previous call of this function. The first call of this function should pass NULL | ||||
|  * as the initial value of the crc in p_crc. | ||||
|  * | ||||
|  * @param[in] p_data The input data block for computation. | ||||
|  * @param[in] size   The size of the input data block in bytes. | ||||
|  * @param[in] p_crc  The previous calculated CRC-16 value or NULL if first call. | ||||
|  * | ||||
|  * @return The updated CRC-16 value, based on the input supplied. | ||||
|  */ | ||||
| uint16_t crc16_compute(uint8_t const * p_data, uint16_t data_len); | ||||
| 
 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif // CRC16_H__
 | ||||
| 
 | ||||
| /** @} */ | ||||
							
								
								
									
										673
									
								
								src/libs/flashers/nrf/dfu.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										673
									
								
								src/libs/flashers/nrf/dfu.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,673 @@ | ||||
| /**
 | ||||
| * Copyright (c) 2018, Nordic Semiconductor ASA | ||||
| * | ||||
| * All rights reserved. | ||||
| * | ||||
| * Redistribution and use in source and binary forms, with or without modification, | ||||
| * are permitted provided that the following conditions are met: | ||||
| * | ||||
| * 1. Redistributions of source code must retain the above copyright notice, this | ||||
| *    list of conditions and the following disclaimer. | ||||
| * | ||||
| * 2. Redistributions in binary form, except as embedded into a Nordic | ||||
| *    Semiconductor ASA integrated circuit in a product or a software update for | ||||
| *    such product, must reproduce the above copyright notice, this list of | ||||
| *    conditions and the following disclaimer in the documentation and/or other | ||||
| *    materials provided with the distribution. | ||||
| * | ||||
| * 3. Neither the name of Nordic Semiconductor ASA nor the names of its | ||||
| *    contributors may be used to endorse or promote products derived from this | ||||
| *    software without specific prior written permission. | ||||
| * | ||||
| * 4. This software, with or without modification, must only be used with a | ||||
| *    Nordic Semiconductor ASA integrated circuit. | ||||
| * | ||||
| * 5. Any software provided in binary form under this license must not be reverse | ||||
| *    engineered, decompiled, modified and/or disassembled. | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS | ||||
| * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
| * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE | ||||
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||||
| * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | ||||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| * | ||||
| * Modified by Jacob Eva (Liberated Embedded Systems) (c) 2025. | ||||
| * Changes licensed under the GPL. | ||||
| * This program is free software: you can redistribute it and/or modify it | ||||
| * under the terms of the GNU General Public License as published by the Free | ||||
| * Software Foundation, either version 3 of the License, or (at your option) | ||||
| * any later version. | ||||
| * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
| * more details. | ||||
| * You should have received a copy of the GNU General Public License along | ||||
| * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <stdbool.h> | ||||
| #include <openssl/sha.h> | ||||
| #include "dfu.h" | ||||
| #include "dfu_serial.h" | ||||
| #include "../../zip.h" | ||||
| #include "jsmn.h" | ||||
| #include "../../logging/log.h" | ||||
| 
 | ||||
| 
 | ||||
| // maximum number of JSON tokens to process
 | ||||
| #define JSON_TOKEN_NUM_MAX              30 | ||||
| 
 | ||||
| // maximum number of DFU objects to process
 | ||||
| #define DFU_OBJECT_NUM_MAX              3 | ||||
| 
 | ||||
| typedef enum { | ||||
| 	DFU_IMG_NIL = 0,                    //!< DFU image invalid
 | ||||
| 	DFU_IMG_APP = 1,                    //!< DFU application image
 | ||||
| 	DFU_IMG_BL = 2,                     //!< DFU bootloader image
 | ||||
| 	DFU_IMG_SD = 3,                     //!< DFU SoftDevice image
 | ||||
| 	DFU_IMG_SD_BL = 4                   //!< DFU SoftDevice & bootloader image
 | ||||
| } dfu_image_type_t; | ||||
| 
 | ||||
| typedef enum { | ||||
| 	STR_UNDEFINED = 0, | ||||
| 	STR_FILE_BIN = 1, | ||||
| 	STR_FILE_DAT = 2 | ||||
| } dfu_json_str_t; | ||||
| 
 | ||||
| typedef struct { | ||||
| 	jsmntype_t type;                    //!< Token type.
 | ||||
| 	int size;                           //!< Number of child tokens.
 | ||||
| 	char *str;                          //!< String value.
 | ||||
| 	dfu_json_str_t str_type;            //!< String usage type.
 | ||||
| } jsmn_entity_t; | ||||
| 
 | ||||
| typedef struct { | ||||
| 	dfu_image_type_t img_type;          //!< DFU image type.
 | ||||
| 	const jsmn_entity_t *p_pattern;     //!< JSMN token pattern.
 | ||||
| } dfu_image_jsmn_pattern; | ||||
| 
 | ||||
| typedef struct | ||||
| { | ||||
| 	dfu_image_type_t img_type;          //!< DFU image type.
 | ||||
| 
 | ||||
| 	char *file_bin;                     //!< BIN file name.
 | ||||
| 	char *file_dat;                     //!< DAT file name.
 | ||||
| } dfu_json_object_t; | ||||
| 
 | ||||
| typedef struct | ||||
| { | ||||
| 	uart_drv_t *p_uart; | ||||
| 
 | ||||
| 	uint8_t *p_img_dat;                 //!< Image DAT pointer.
 | ||||
| 	uint32_t n_dat_size;                //!< Image DAT size.
 | ||||
| 	uint8_t *p_img_bin;                 //!< Image BIN pointer.
 | ||||
| 	uint32_t n_bin_size;                //!< Image BIN size.
 | ||||
| } dfu_img_param_t; | ||||
| 
 | ||||
| // JSON tokens
 | ||||
| static jsmntok_t json_tokens[JSON_TOKEN_NUM_MAX]; | ||||
| 
 | ||||
| // DFU objects
 | ||||
| static dfu_json_object_t dfu_objects[DFU_OBJECT_NUM_MAX]; | ||||
| 
 | ||||
| // JSMN token pattern for Manifest
 | ||||
| static const jsmn_entity_t dfu_mft_pattern[] = | ||||
| { | ||||
| 	{ JSMN_OBJECT,    1, NULL,       STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    1, "manifest", STR_UNDEFINED }, | ||||
| 	{ JSMN_UNDEFINED, 0, NULL,       STR_UNDEFINED } | ||||
| }; | ||||
| 
 | ||||
| // JSMN token pattern for 1 DFU image
 | ||||
| static const jsmn_entity_t dfu_img_1_pattern[] = | ||||
| { | ||||
| 	{ JSMN_OBJECT,    2, NULL,       STR_UNDEFINED }, | ||||
| 	{ JSMN_UNDEFINED, 0, NULL,       STR_UNDEFINED } | ||||
| }; | ||||
| 
 | ||||
| // JSMN token pattern for 2 DFU images
 | ||||
| static const jsmn_entity_t dfu_img_2_pattern[] = | ||||
| { | ||||
| 	{ JSMN_OBJECT,    3, NULL,       STR_UNDEFINED }, | ||||
| 	{ JSMN_UNDEFINED, 0, NULL,       STR_UNDEFINED } | ||||
| }; | ||||
| 
 | ||||
| // JSMN token pattern for DFU application
 | ||||
| static const jsmn_entity_t dfu_app_pattern[] = | ||||
| { | ||||
| 	{ JSMN_STRING,    1, "application", STR_UNDEFINED }, | ||||
| 	{ JSMN_OBJECT,    3, NULL,          STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    1, "bin_file",    STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    0, NULL,          STR_FILE_BIN  }, | ||||
| 	{ JSMN_STRING,    1, "dat_file",    STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    0, NULL,          STR_FILE_DAT  }, | ||||
| 	{ JSMN_STRING,    1, "init_packet_data", STR_UNDEFINED }, | ||||
| 	{ JSMN_OBJECT,    5, NULL,          STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    1, "application_version", STR_UNDEFINED }, | ||||
| 	{ JSMN_PRIMITIVE,    0, NULL,          STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    1, "device_revision", STR_UNDEFINED }, | ||||
| 	{ JSMN_PRIMITIVE,    0, NULL,          STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    1, "device_type",    STR_UNDEFINED }, | ||||
| 	{ JSMN_PRIMITIVE,    0, NULL,          STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    1, "firmware_crc16", STR_UNDEFINED }, | ||||
| 	{ JSMN_PRIMITIVE,    0, NULL,          STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    1, "softdevice_req", STR_UNDEFINED }, | ||||
| 	{ JSMN_ARRAY,    1, NULL,          STR_UNDEFINED }, | ||||
| 	{ JSMN_PRIMITIVE,    0, NULL,          STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    1, "dfu_version", STR_UNDEFINED }, | ||||
| 	{ JSMN_PRIMITIVE,    0, NULL,          STR_UNDEFINED }, | ||||
| 	{ JSMN_UNDEFINED, 0, NULL,          STR_UNDEFINED } | ||||
| }; | ||||
| 
 | ||||
| // JSMN token pattern for DFU bootloader
 | ||||
| static const jsmn_entity_t dfu_bl_pattern[] = | ||||
| { | ||||
| 	{ JSMN_STRING,    1, "bootloader",  STR_UNDEFINED }, | ||||
| 	{ JSMN_OBJECT,    2, NULL,          STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    1, "bin_file",    STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    0, NULL,          STR_FILE_BIN  }, | ||||
| 	{ JSMN_STRING,    1, "dat_file",    STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    0, NULL,          STR_FILE_DAT  }, | ||||
| 	{ JSMN_UNDEFINED, 0, NULL,          STR_UNDEFINED } | ||||
| }; | ||||
| 
 | ||||
| // JSMN token pattern for DFU SoftDevice
 | ||||
| static const jsmn_entity_t dfu_sd_pattern[] = | ||||
| { | ||||
| 	{ JSMN_STRING,    1, "softdevice",  STR_UNDEFINED }, | ||||
| 	{ JSMN_OBJECT,    2, NULL,          STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    1, "bin_file",    STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    0, NULL,          STR_FILE_BIN  }, | ||||
| 	{ JSMN_STRING,    1, "dat_file",    STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    0, NULL,          STR_FILE_DAT  }, | ||||
| 	{ JSMN_UNDEFINED, 0, NULL,          STR_UNDEFINED } | ||||
| }; | ||||
| 
 | ||||
| // JSMN token pattern for DFU SoftDevice & bootloader
 | ||||
| static const jsmn_entity_t dfu_sd_bl_pattern[] = | ||||
| { | ||||
| 	{ JSMN_STRING,    1, "softdevice_bootloader",   STR_UNDEFINED }, | ||||
| 	{ JSMN_OBJECT,    3, NULL,                      STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    1, "bin_file",                STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    0, NULL,                      STR_FILE_BIN  }, | ||||
| 	{ JSMN_STRING,    1, "dat_file",                STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    0, NULL,                      STR_FILE_DAT  }, | ||||
| 	{ JSMN_STRING,    1, "info_read_only_metadata", STR_UNDEFINED }, | ||||
| 	{ JSMN_OBJECT,    2, NULL,                      STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    1, "bl_size",                 STR_UNDEFINED }, | ||||
| 	{ JSMN_PRIMITIVE, 0, NULL,                      STR_UNDEFINED }, | ||||
| 	{ JSMN_STRING,    1, "sd_size",                 STR_UNDEFINED }, | ||||
| 	{ JSMN_PRIMITIVE, 0, NULL,                      STR_UNDEFINED }, | ||||
| 	{ JSMN_UNDEFINED, 0, NULL,                      STR_UNDEFINED } | ||||
| }; | ||||
| 
 | ||||
| // JSMN token pattern table
 | ||||
| static const dfu_image_jsmn_pattern dfu_pattern_tbl[] = | ||||
| { | ||||
| 	{ DFU_IMG_APP,   dfu_app_pattern   }, | ||||
| 	{ DFU_IMG_BL,    dfu_bl_pattern    }, | ||||
| 	{ DFU_IMG_SD,    dfu_sd_pattern    }, | ||||
| 	{ DFU_IMG_SD_BL, dfu_sd_bl_pattern }, | ||||
| 	{ DFU_IMG_NIL,   NULL              } | ||||
| }; | ||||
| 
 | ||||
| static void free_dfu_json_obj(dfu_json_object_t *p_dfu_obj); | ||||
| 
 | ||||
| // allocate memory to store a JSON string
 | ||||
| static char *put_json_to_string(const uint8_t *p_data, int len) | ||||
| { | ||||
| 	char *p_str; | ||||
| 
 | ||||
| 	if (len >= 0) | ||||
| 		p_str = (char *)malloc(len + 1); | ||||
| 	else | ||||
| 		p_str = NULL; | ||||
| 
 | ||||
| 	if (p_str != NULL) | ||||
| 	{ | ||||
| 		memcpy(p_str, p_data, len); | ||||
| 		*(p_str + len) = '\0'; | ||||
| 	} | ||||
| 
 | ||||
| 	return p_str; | ||||
| } | ||||
| 
 | ||||
| // map a JSMN token to a DFU JSON pattern
 | ||||
| static int map_jsmn_token_to_pattern(dfu_json_object_t *p_dfu_obj, const jsmn_entity_t *p_pattern, const jsmntok_t *p_tokens, int num_tokens, const uint8_t *p_data) | ||||
| { | ||||
| 	int i, j = 0; | ||||
| 	jsmntype_t jsmn_type; | ||||
| 
 | ||||
| 	// compare the JSMN tokens one by one
 | ||||
| 	for (i = 0; (jsmn_type = (p_pattern + i)->type) != JSMN_UNDEFINED; i++) | ||||
| 	{ | ||||
|         jsmntype_t comp_type = (p_tokens + i)->type; | ||||
|         uint16_t size1 = (p_pattern + i)->size; | ||||
|         uint16_t size2 = (p_tokens + i)->size; | ||||
| 		if (i >= num_tokens ||  | ||||
| 			jsmn_type != (p_tokens + i)->type ||  | ||||
| 			(p_pattern + i)->size != (p_tokens + i)->size) | ||||
| 		{ | ||||
| 			// type or size mismatch...
 | ||||
| 			j = -1; | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		if (jsmn_type == JSMN_STRING) | ||||
| 		{ | ||||
| 			int len = (p_tokens + i)->end - (p_tokens + i)->start; | ||||
| 			char *p_str = put_json_to_string(p_data + (p_tokens + i)->start, len); | ||||
| 
 | ||||
| 			if (p_str == NULL) | ||||
| 			{ | ||||
| 				// cannot allocate memory...
 | ||||
| 				j = -1; | ||||
| 				break; | ||||
| 			} | ||||
| 
 | ||||
| 			// check the pattern string
 | ||||
|             char *comp_string = (p_pattern +i)->str; | ||||
| 			if ((p_pattern + i)->str != NULL && strcmp(p_str, (p_pattern + i)->str)) | ||||
| 			{ | ||||
| 				free(p_str); | ||||
| 
 | ||||
| 				// mismatch...
 | ||||
| 				j = -1; | ||||
| 				break; | ||||
| 			} | ||||
| 
 | ||||
| 			// store string target, if any
 | ||||
| 			switch ((p_pattern + i)->str_type) | ||||
| 			{ | ||||
| 			case STR_FILE_DAT: | ||||
| 				if (p_dfu_obj != NULL) | ||||
| 					p_dfu_obj->file_dat = p_str; | ||||
| 				break; | ||||
| 			case STR_FILE_BIN: | ||||
| 				if (p_dfu_obj != NULL) | ||||
| 					p_dfu_obj->file_bin = p_str; | ||||
| 				break; | ||||
| 			default: | ||||
| 				free(p_str); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (j < 0) | ||||
| 	{ | ||||
| 		i = j; | ||||
| 
 | ||||
| 		if (p_dfu_obj != NULL) | ||||
| 			free_dfu_json_obj(p_dfu_obj); | ||||
| 	} | ||||
| 
 | ||||
| 	return i; | ||||
| } | ||||
| 
 | ||||
| // free allocated strings
 | ||||
| static void free_dfu_json_obj(dfu_json_object_t *p_dfu_obj) | ||||
| { | ||||
| 	if (p_dfu_obj->file_dat != NULL) | ||||
| 	{ | ||||
| 		free(p_dfu_obj->file_dat); | ||||
| 		p_dfu_obj->file_dat = NULL; | ||||
| 	} | ||||
| 	if (p_dfu_obj->file_bin != NULL) | ||||
| 	{ | ||||
| 		free(p_dfu_obj->file_bin); | ||||
| 		p_dfu_obj->file_bin = NULL; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int dfu_send_image(dfu_img_param_t *p_dfu_img, struct RNode* rn) | ||||
| { | ||||
| 	int err_code; | ||||
| 
 | ||||
|     err_code = dfu_serial_send_start_dfu(p_dfu_img->p_uart, 4, 0, 0, p_dfu_img->n_bin_size); // todo remove hardcode to mode 4
 | ||||
| 
 | ||||
| 	if (!err_code) | ||||
| 	{ | ||||
| 		err_code = dfu_serial_send_init(p_dfu_img->p_uart, p_dfu_img->p_img_dat, p_dfu_img->n_dat_size); | ||||
| 	} | ||||
| 
 | ||||
| 	if (!err_code) | ||||
| 	{ | ||||
| 		err_code = dfu_serial_send_firmware(p_dfu_img->p_uart, rn, p_dfu_img->p_img_bin, p_dfu_img->n_bin_size); | ||||
| 	} | ||||
| 
 | ||||
| 	return err_code; | ||||
| } | ||||
| 
 | ||||
| static int dfu_send_object(uart_drv_t *p_uart, struct RNode* rn, dfu_json_object_t *p_dfu_obj, struct zip_t *p_zip_pkg) | ||||
| { | ||||
| 	int err_code = 0; | ||||
| 	uint8_t *buf_dat = NULL; | ||||
| 	size_t buf_dat_size; | ||||
| 	uint8_t *buf_bin = NULL; | ||||
| 	size_t buf_bin_size; | ||||
| 	dfu_img_param_t dfu_img; | ||||
| 
 | ||||
| 	if (zip_entry_open(p_zip_pkg, p_dfu_obj->file_dat)) | ||||
| 	{ | ||||
| 		log_error("Cannot open firmware package DAT file!"); | ||||
| 
 | ||||
| 		err_code = 1; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if (zip_entry_read(p_zip_pkg, (void **)&buf_dat, &buf_dat_size)) | ||||
| 		{ | ||||
| 			log_error("Cannot read firmware package DAT file!"); | ||||
| 
 | ||||
| 			err_code = 1; | ||||
| 		} | ||||
| 
 | ||||
| 		zip_entry_close(p_zip_pkg); | ||||
| 	} | ||||
| 
 | ||||
| 	if (!err_code) | ||||
| 	{ | ||||
| 		if (zip_entry_open(p_zip_pkg, p_dfu_obj->file_bin)) | ||||
| 		{ | ||||
| 			log_error("Cannot open firmware package BIN file!"); | ||||
| 
 | ||||
| 			err_code = 1; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if (zip_entry_read(p_zip_pkg, (void **)&buf_bin, &buf_bin_size)) | ||||
| 			{ | ||||
| 				log_error("Cannot read firmware package BIN file!"); | ||||
| 
 | ||||
| 				err_code = 1; | ||||
| 			} | ||||
| 
 | ||||
| 			zip_entry_close(p_zip_pkg); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (!err_code) | ||||
| 	{ | ||||
| 		dfu_img.p_uart = p_uart; | ||||
| 		dfu_img.p_img_dat = buf_dat; | ||||
| 		dfu_img.n_dat_size = buf_dat_size; | ||||
| 		dfu_img.p_img_bin = buf_bin; | ||||
| 		dfu_img.n_bin_size = buf_bin_size; | ||||
| 		err_code = dfu_send_image(&dfu_img, rn); | ||||
| 	} | ||||
| 
 | ||||
| 	if (buf_dat != NULL) | ||||
| 		free(buf_dat); | ||||
| 
 | ||||
| 	if (buf_bin != NULL) | ||||
| 		free(buf_bin); | ||||
| 
 | ||||
| 	return err_code; | ||||
| } | ||||
| 
 | ||||
| static dfu_json_object_t *find_dfu_object(dfu_json_object_t *p_dfu_obj, int num_obj, dfu_image_type_t img_type) | ||||
| { | ||||
| 	dfu_json_object_t *p_obj = NULL; | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < num_obj; i++) | ||||
| 	{ | ||||
| 		if ((p_dfu_obj + i)->img_type == img_type) | ||||
| 		{ | ||||
| 			p_obj = p_dfu_obj + i; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return p_obj; | ||||
| } | ||||
| 
 | ||||
| int dfu_send_package(dfu_param_t *p_dfu, struct RNode* rn, uint8_t* hash) | ||||
| { | ||||
| 	int err_code = 0; | ||||
| 	struct zip_t *zip_pkg; | ||||
| 	uint8_t *buf_json = NULL; | ||||
| 	size_t bufsize; | ||||
| 	jsmn_parser parser; | ||||
| 	int num_tokens; | ||||
| 	int num_images, img_n = 0; | ||||
| 	dfu_json_object_t *p_dfu_object; | ||||
| 	int i, n; | ||||
| 
 | ||||
| 	zip_pkg = zip_open(p_dfu->p_pkg_file, 0, 'r'); | ||||
| 	if (zip_pkg == NULL) | ||||
| 	{ | ||||
| 		log_error("Cannot open ZIP firmware package file!"); | ||||
| 
 | ||||
| 		err_code = 1; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if (zip_entry_open(zip_pkg, "manifest.json")) | ||||
| 		{ | ||||
| 			log_error("Cannot open firmware package manifest file!"); | ||||
| 
 | ||||
| 			err_code = 1; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if (zip_entry_read(zip_pkg, (void **)&buf_json, &bufsize)) | ||||
| 			{ | ||||
| 				log_error("Cannot read firmware package manifest file!"); | ||||
| 
 | ||||
| 				err_code = 1; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				zip_entry_close(zip_pkg); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (!err_code) | ||||
| 	{ | ||||
| 		jsmn_init(&parser); | ||||
| 
 | ||||
| 		num_tokens = jsmn_parse(&parser, (char *)buf_json, bufsize, json_tokens, JSON_TOKEN_NUM_MAX); | ||||
| 
 | ||||
| 		if (num_tokens < 0) | ||||
| 		{ | ||||
| 			log_error("Cannot parse firmware package manifest JSON (%d)!", num_tokens); | ||||
| 
 | ||||
| 			err_code = 1; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < DFU_OBJECT_NUM_MAX; i++) | ||||
| 	{ | ||||
| 		dfu_objects[i].file_bin = NULL; | ||||
| 		dfu_objects[i].file_dat = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!err_code) | ||||
| 	{ | ||||
| 		// check that JSON starts with a manifest object
 | ||||
| 		i = map_jsmn_token_to_pattern(NULL, dfu_mft_pattern, json_tokens, num_tokens, buf_json); | ||||
| 		if (i < 0) | ||||
| 		{ | ||||
| 			log_error("Cannot get JSON manifest object from firmware package!"); | ||||
| 
 | ||||
| 			err_code = 1; | ||||
| 		} | ||||
| 		n = i; | ||||
| 
 | ||||
| 		if (!err_code) | ||||
| 		{ | ||||
| 			// check whether there are 1 or 2 DFU images
 | ||||
| 			i = map_jsmn_token_to_pattern(NULL, dfu_img_1_pattern, json_tokens + n, num_tokens - n, buf_json); | ||||
| 			if (i > 0) | ||||
| 			{ | ||||
| 				num_images = 1; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				i = map_jsmn_token_to_pattern(NULL, dfu_img_2_pattern, json_tokens + n, num_tokens - n, buf_json); | ||||
| 				if (i > 0) | ||||
| 				{ | ||||
| 					num_images = 2; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if (i <= 0) | ||||
| 			{ | ||||
| 				log_error("Cannot get number of DFU images from manifest!"); | ||||
| 
 | ||||
| 				err_code = 1; | ||||
| 			} | ||||
| 		} | ||||
| 		n += i; | ||||
| 
 | ||||
| 		while (!err_code && n < num_tokens) | ||||
| 		{ | ||||
| 			int t; | ||||
| 
 | ||||
| 			if (img_n >= DFU_OBJECT_NUM_MAX) | ||||
| 			{ | ||||
| 				log_error("Too many DFU images in the manifest!"); | ||||
| 
 | ||||
| 				err_code = 1; | ||||
| 				break; | ||||
| 			} | ||||
| 
 | ||||
| 			// determine the DFU image type
 | ||||
| 			for (t = 0; dfu_pattern_tbl[t].img_type != DFU_IMG_NIL; t++) | ||||
| 			{ | ||||
| 				i = map_jsmn_token_to_pattern(dfu_objects + img_n, dfu_pattern_tbl[t].p_pattern, json_tokens + n, num_tokens - n, buf_json); | ||||
| 
 | ||||
| 				if (i > 0) | ||||
| 				{ | ||||
| 					dfu_objects[img_n].img_type = dfu_pattern_tbl[t].img_type; | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if (i <= 0) | ||||
| 			{ | ||||
| 				log_error("Cannot find JSON DFU image object in manifest!"); | ||||
| 
 | ||||
| 				err_code = 1; | ||||
| 				break; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				n += i; | ||||
| 
 | ||||
| 				img_n++; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (!err_code && (n != num_tokens || img_n != num_images)) | ||||
| 		{ | ||||
| 			log_error("Incoherent JSON object structure detected in manifest!"); | ||||
| 
 | ||||
| 			err_code = 1; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|     // todo, redo this section to support softdevice & bootloader flashing
 | ||||
| 	if (!err_code) | ||||
| 	{ | ||||
| 		// send SoftDevice & bootloader image, if any
 | ||||
| 		//p_dfu_object = find_dfu_object(dfu_objects, num_images, DFU_IMG_SD_BL);
 | ||||
| 		//if (p_dfu_object != NULL)
 | ||||
| 		//{
 | ||||
| 		//	//logger_info_1("Sending SoftDevice+Bootloader image.");
 | ||||
| 
 | ||||
| 		//	//err_code = dfu_send_object(p_dfu->p_uart, p_dfu_object, zip_pkg);
 | ||||
| 
 | ||||
| 		//	//if (!err_code && num_images > 1)
 | ||||
| 		//	// err_code = delay_connect();
 | ||||
| 		//}
 | ||||
| 	} | ||||
| 
 | ||||
| 	if (!err_code) | ||||
| 	{ | ||||
| 		// send SoftDevice image, if any
 | ||||
| 		//p_dfu_object = find_dfu_object(dfu_objects, num_images, DFU_IMG_SD);
 | ||||
| 		//if (p_dfu_object != NULL)
 | ||||
| 		//{
 | ||||
| 		//	//logger_info_1("Sending SoftDevice image.");
 | ||||
| 
 | ||||
| 		//	// err_code = dfu_send_object(p_dfu->p_uart, p_dfu_object, zip_pkg);
 | ||||
| 
 | ||||
| 		//	// if (!err_code && num_images > 1)
 | ||||
| 		//	// err_code = delay_connect();
 | ||||
| 		//}
 | ||||
| 	} | ||||
| 
 | ||||
| 	if (!err_code) | ||||
| 	{ | ||||
| 		// send bootloader image, if any
 | ||||
| 		//p_dfu_object = find_dfu_object(dfu_objects, num_images, DFU_IMG_BL);
 | ||||
| 		//if (p_dfu_object != NULL)
 | ||||
| 		//{
 | ||||
| 		//	//logger_info_1("Sending Bootloader image.");
 | ||||
| 
 | ||||
| 		//	// err_code = dfu_send_object(p_dfu->p_uart, p_dfu_object, zip_pkg);
 | ||||
| 
 | ||||
| 		//	// if (!err_code && num_images > 1)
 | ||||
| 		//	// err_code = delay_connect();
 | ||||
| 		//}
 | ||||
| 	} | ||||
| 
 | ||||
| 	if (!err_code) | ||||
| 	{ | ||||
| 		// send application image, if any
 | ||||
| 		p_dfu_object = find_dfu_object(dfu_objects, num_images, DFU_IMG_APP); | ||||
| 		if (p_dfu_object != NULL) | ||||
| 		{ | ||||
|             uint8_t *buf_bin = NULL; | ||||
|             size_t buf_bin_size; | ||||
| 
 | ||||
| 			log_info("Sending Application image to RNode..."); | ||||
| 
 | ||||
| 			err_code = dfu_send_object(p_dfu->p_uart, rn, p_dfu_object, zip_pkg); | ||||
| 
 | ||||
|             if (zip_entry_open(zip_pkg, p_dfu_object->file_bin)) | ||||
|             { | ||||
|                 log_error("Cannot open firmware package BIN file!"); | ||||
| 
 | ||||
|                 err_code = 1; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (zip_entry_read(zip_pkg, (void **)&buf_bin, &buf_bin_size)) | ||||
|                 { | ||||
|                     log_error("Cannot read firmware package BIN file!"); | ||||
| 
 | ||||
|                     err_code = 1; | ||||
|                 } | ||||
| 
 | ||||
|                 zip_entry_close(zip_pkg); | ||||
|             } | ||||
| 
 | ||||
|             // Set firmware hash
 | ||||
|             SHA256(buf_bin, buf_bin_size, hash); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < DFU_OBJECT_NUM_MAX; i++) | ||||
| 		free_dfu_json_obj(dfu_objects + i); | ||||
| 
 | ||||
| 	if (buf_json != NULL) | ||||
| 		free(buf_json); | ||||
| 
 | ||||
| 	if (zip_pkg != NULL) | ||||
| 		zip_close(zip_pkg); | ||||
| 
 | ||||
| 	return err_code; | ||||
| } | ||||
							
								
								
									
										82
									
								
								src/libs/flashers/nrf/dfu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/libs/flashers/nrf/dfu.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,82 @@ | ||||
| /**
 | ||||
| * Copyright (c) 2018, Nordic Semiconductor ASA | ||||
| * | ||||
| * All rights reserved. | ||||
| * | ||||
| * Redistribution and use in source and binary forms, with or without modification, | ||||
| * are permitted provided that the following conditions are met: | ||||
| * | ||||
| * 1. Redistributions of source code must retain the above copyright notice, this | ||||
| *    list of conditions and the following disclaimer. | ||||
| * | ||||
| * 2. Redistributions in binary form, except as embedded into a Nordic | ||||
| *    Semiconductor ASA integrated circuit in a product or a software update for | ||||
| *    such product, must reproduce the above copyright notice, this list of | ||||
| *    conditions and the following disclaimer in the documentation and/or other | ||||
| *    materials provided with the distribution. | ||||
| * | ||||
| * 3. Neither the name of Nordic Semiconductor ASA nor the names of its | ||||
| *    contributors may be used to endorse or promote products derived from this | ||||
| *    software without specific prior written permission. | ||||
| * | ||||
| * 4. This software, with or without modification, must only be used with a | ||||
| *    Nordic Semiconductor ASA integrated circuit. | ||||
| * | ||||
| * 5. Any software provided in binary form under this license must not be reverse | ||||
| *    engineered, decompiled, modified and/or disassembled. | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS | ||||
| * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
| * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE | ||||
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||||
| * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | ||||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| * | ||||
| * Modified by Jacob Eva (Liberated Embedded Systems) (c) 2025. | ||||
| * Changes licensed under the GPL. | ||||
| * This program is free software: you can redistribute it and/or modify it | ||||
| * under the terms of the GNU General Public License as published by the Free | ||||
| * Software Foundation, either version 3 of the License, or (at your option) | ||||
| * any later version. | ||||
| * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
| * more details. | ||||
| * You should have received a copy of the GNU General Public License along | ||||
| * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| 
 | ||||
| #pragma once | ||||
|   | ||||
| #ifndef _INC_DFU | ||||
| #define _INC_DFU | ||||
| 
 | ||||
| #include "uart_drv.h" | ||||
| #include "uart_slip.h" | ||||
| #include "../../../librnode.h" | ||||
| 
 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif  /* __cplusplus */ | ||||
| 
 | ||||
| 
 | ||||
| typedef struct | ||||
| { | ||||
| 	uart_drv_t *p_uart; | ||||
| 
 | ||||
| 	char *p_pkg_file; | ||||
| } dfu_param_t; | ||||
| 	 | ||||
| int dfu_send_package(dfu_param_t *p_dfu, struct RNode* rn, uint8_t* hash); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| }   /* ... extern "C" */ | ||||
| #endif  /* __cplusplus */ | ||||
| 
 | ||||
| 
 | ||||
| #endif // _INC_DFU
 | ||||
							
								
								
									
										356
									
								
								src/libs/flashers/nrf/dfu_serial.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										356
									
								
								src/libs/flashers/nrf/dfu_serial.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,356 @@ | ||||
| /**
 | ||||
| * Copyright (c) 2018, Nordic Semiconductor ASA | ||||
| * | ||||
| * All rights reserved. | ||||
| * | ||||
| * Redistribution and use in source and binary forms, with or without modification, | ||||
| * are permitted provided that the following conditions are met: | ||||
| * | ||||
| * 1. Redistributions of source code must retain the above copyright notice, this | ||||
| *    list of conditions and the following disclaimer. | ||||
| * | ||||
| * 2. Redistributions in binary form, except as embedded into a Nordic | ||||
| *    Semiconductor ASA integrated circuit in a product or a software update for | ||||
| *    such product, must reproduce the above copyright notice, this list of | ||||
| *    conditions and the following disclaimer in the documentation and/or other | ||||
| *    materials provided with the distribution. | ||||
| * | ||||
| * 3. Neither the name of Nordic Semiconductor ASA nor the names of its | ||||
| *    contributors may be used to endorse or promote products derived from this | ||||
| *    software without specific prior written permission. | ||||
| * | ||||
| * 4. This software, with or without modification, must only be used with a | ||||
| *    Nordic Semiconductor ASA integrated circuit. | ||||
| * | ||||
| * 5. Any software provided in binary form under this license must not be reverse | ||||
| *    engineered, decompiled, modified and/or disassembled. | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS | ||||
| * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
| * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE | ||||
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||||
| * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | ||||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| * | ||||
| * Modified by Jacob Eva (Liberated Embedded Systems) (c) 2025. | ||||
| * Changes licensed under the GPL. | ||||
| * This program is free software: you can redistribute it and/or modify it | ||||
| * under the terms of the GNU General Public License as published by the Free | ||||
| * Software Foundation, either version 3 of the License, or (at your option) | ||||
| * any later version. | ||||
| * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
| * more details. | ||||
| * You should have received a copy of the GNU General Public License along | ||||
| * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <time.h> | ||||
| #include <sys/param.h> | ||||
| #include "dfu_serial.h" | ||||
| #include "hci.h" | ||||
| #include "../../util.h" | ||||
| #include "../../logging/log.h" | ||||
| 
 | ||||
| // SLIP data log buffer size
 | ||||
| #define MAX_BUFF_SIZE           1024 | ||||
| 
 | ||||
| #define DFU_INIT_PACKET 1 | ||||
| #define DFU_START_PACKET 3 | ||||
| #define DFU_DATA_PACKET 4 | ||||
| #define DFU_STOP_DATA_PACKET 5 | ||||
| #define DFU_PACKET_MAX_SIZE 512 | ||||
| 
 | ||||
| #define FLASH_PAGE_SIZE 4096 | ||||
| #define FLASH_WORD_WRITE_TIME 0.000100 | ||||
| #define FLASH_PAGE_WRITE_TIME (FLASH_PAGE_SIZE / 4) * FLASH_WORD_WRITE_TIME | ||||
| #define FLASH_PAGE_ERASE_TIME 0.0897 | ||||
| #define FLASH_MAX_FW_SIZE 300000 | ||||
| 
 | ||||
| #define DAT_FILE_SIZE 14 | ||||
| 
 | ||||
| #define LOG_BUF_SIZE 2048 | ||||
| 
 | ||||
| static uint8_t send_data[UART_SLIP_SIZE_MAX]; | ||||
| static uint8_t receive_data[UART_SLIP_SIZE_MAX]; | ||||
| char logger_buf[LOG_BUF_SIZE]; | ||||
| void (*progress_cb)(uint8_t) = NULL; | ||||
| 
 | ||||
| static uint32_t get_uint32_le(const uint8_t *p_data) | ||||
| { | ||||
| 	uint32_t data; | ||||
| 
 | ||||
| 	data  = ((uint32_t)*(p_data + 0) <<  0); | ||||
| 	data += ((uint32_t)*(p_data + 1) <<  8); | ||||
| 	data += ((uint32_t)*(p_data + 2) << 16); | ||||
| 	data += ((uint32_t)*(p_data + 3) << 24); | ||||
| 
 | ||||
| 	return data; | ||||
| } | ||||
| 
 | ||||
| static void put_uint32_le(uint8_t *p_data, uint32_t data) | ||||
| { | ||||
| 	*(p_data + 0) = (uint8_t)(data >>  0); | ||||
| 	*(p_data + 1) = (uint8_t)(data >>  8); | ||||
| 	*(p_data + 2) = (uint8_t)(data >> 16); | ||||
| 	*(p_data + 3) = (uint8_t)(data >> 24); | ||||
| } | ||||
| 
 | ||||
| static void uart_data_to_buff(const uint8_t *pData, uint32_t nSize) | ||||
| { | ||||
| 	uint32_t n; | ||||
| 	int len, pos; | ||||
| 
 | ||||
| 	pos = 0; | ||||
| 
 | ||||
|     if (nSize*3 <= sizeof(logger_buf)) { | ||||
|         for (n = 0; n < nSize; n++) | ||||
|         { | ||||
|             sprintf(logger_buf+n*3, "%02x ", *(pData + n)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static int dfu_serial_send(uart_drv_t *p_uart, const uint8_t *pData, uint32_t nSize) | ||||
| { | ||||
|     uart_data_to_buff(pData, nSize); | ||||
|     log_trace("SLIP: --> [%s]", logger_buf); | ||||
| 
 | ||||
| 	return uart_drv_send(p_uart, pData, nSize); | ||||
| } | ||||
| 
 | ||||
| //static int dfu_serial_get_rsp(uart_drv_t *p_uart, nrf_dfu_op_t oper, uint32_t *p_data_cnt)
 | ||||
| //{
 | ||||
| //	int err_code;
 | ||||
| //
 | ||||
| //	err_code = uart_slip_receive(p_uart, receive_data, sizeof(receive_data), p_data_cnt);
 | ||||
| //
 | ||||
| //	if (!err_code)
 | ||||
| //	{
 | ||||
| //		//int info_lvl = //logger_get_info_level();
 | ||||
| //
 | ||||
| //		//if (info_lvl >= LOGGER_INFO_LVL_3)
 | ||||
| //		//{
 | ||||
| //		//	uart_data_to_buff(receive_data, *p_data_cnt);
 | ||||
| //		//	//logger_info_3("SLIP: <-- [%s]", //logger_buf);
 | ||||
| //		//}
 | ||||
| //
 | ||||
| //		if (*p_data_cnt >= 3 &&
 | ||||
| //			receive_data[0] == NRF_DFU_OP_RESPONSE &&
 | ||||
| //			receive_data[1] == oper)
 | ||||
| //		{
 | ||||
| //			if (receive_data[2] != NRF_DFU_RES_CODE_SUCCESS)
 | ||||
| //			{
 | ||||
| //				uint16_t rsp_error = receive_data[2];
 | ||||
| //
 | ||||
| //				// get 2-byte error code, if applicable
 | ||||
| //				if (*p_data_cnt >= 4)
 | ||||
| //					rsp_error = (rsp_error << 8) + receive_data[3];
 | ||||
| //
 | ||||
| //				//logger_error("Bad result code (0x%X)!", rsp_error);
 | ||||
| //
 | ||||
| //				err_code = 1;
 | ||||
| //			}
 | ||||
| //		}
 | ||||
| //		else
 | ||||
| //		{
 | ||||
| //			//logger_error("Invalid response!");
 | ||||
| //
 | ||||
| //			err_code = 1;
 | ||||
| //		}
 | ||||
| //	}
 | ||||
| //
 | ||||
| //	return err_code;
 | ||||
| //}
 | ||||
| 
 | ||||
| static void dfu_serial_u32_to_bytes(uint32_t val, uint8_t* array, uint16_t offset) { | ||||
|     array[offset]   =  val & 0x000000ff; | ||||
|     array[offset+1] = (val & 0x0000ff00) >> 8; | ||||
|     array[offset+2] = (val & 0x00ff0000) >> 16; | ||||
|     array[offset+3] = (val & 0xff000000) >> 24; | ||||
| } | ||||
| 
 | ||||
| // Waits the time necessary for the MCU to erase its flash before we begin sending the new image
 | ||||
| int dfu_serial_wait_for_erase(uint32_t total_img_size) { | ||||
|     return sleep_ms(MAX(0.5, (total_img_size / FLASH_PAGE_SIZE) * FLASH_PAGE_ERASE_TIME)); | ||||
| } | ||||
| 
 | ||||
| int dfu_serial_send_start_dfu(uart_drv_t *p_uart, uint8_t mode, uint32_t softdevice_size, uint32_t bootloader_size, uint32_t application_size) { | ||||
|     int error = 0; | ||||
|     uint8_t frame[5*4] = {0}; | ||||
|     uint8_t hci_frame[(5*4)*2]; | ||||
| 
 | ||||
|     dfu_serial_u32_to_bytes(DFU_START_PACKET, frame, 0); | ||||
|     dfu_serial_u32_to_bytes(mode, frame, 4); | ||||
|     dfu_serial_u32_to_bytes(softdevice_size, frame, 8); | ||||
|     dfu_serial_u32_to_bytes(bootloader_size, frame, 12); | ||||
|     dfu_serial_u32_to_bytes(application_size, frame, 16); | ||||
| 
 | ||||
|     uint32_t size = encode_hci(frame, 5*4, hci_frame); | ||||
| 
 | ||||
|     error = dfu_serial_wait_for_erase(softdevice_size + bootloader_size + application_size); | ||||
| 
 | ||||
|     if (!error) { | ||||
|         error = dfu_serial_send(p_uart, hci_frame, size); | ||||
|     } | ||||
| 
 | ||||
|     return error; | ||||
| } | ||||
| 
 | ||||
| int dfu_serial_send_init(uart_drv_t *p_uart, const uint8_t* dat_file, uint32_t dat_size) { | ||||
|     if (dat_size > DAT_FILE_SIZE) { | ||||
|         log_error("Firmware DAT file is invalid! Is your ZIP file corrupt?"); | ||||
|         return -1; | ||||
|     } | ||||
|     uint8_t frame[6+DAT_FILE_SIZE] = {0}; | ||||
|     uint8_t hci_frame[(6+DAT_FILE_SIZE) * 2]; | ||||
| 
 | ||||
|     dfu_serial_u32_to_bytes(DFU_INIT_PACKET, frame, 0); | ||||
| 
 | ||||
|     memcpy(frame+4, dat_file, DAT_FILE_SIZE); | ||||
| 
 | ||||
|     uint32_t size = encode_hci(frame, 6+DAT_FILE_SIZE, hci_frame); | ||||
| 
 | ||||
|     return dfu_serial_send(p_uart, hci_frame, size); | ||||
| } | ||||
| 
 | ||||
| // todo, may allow for firmware extraction from board?
 | ||||
| //static int dfu_serial_try_to_recover_fw(uart_drv_t *p_uart, const uint8_t *p_data, uint32_t data_size,
 | ||||
| //										nrf_dfu_response_select_t *p_rsp_recover,
 | ||||
| //										const nrf_dfu_response_select_t *p_rsp_select)
 | ||||
| //{
 | ||||
| //	int err_code = 0;
 | ||||
| //	uint32_t max_size, stp_size;
 | ||||
| //	uint32_t pos_start, len_remain;
 | ||||
| //	uint32_t crc_32 = 0;
 | ||||
| //	int obj_exec = 1;
 | ||||
| //
 | ||||
| //	*p_rsp_recover = *p_rsp_select;
 | ||||
| //
 | ||||
| //	pos_start = p_rsp_recover->offset;
 | ||||
| //
 | ||||
| //	if (pos_start > data_size)
 | ||||
| //	{
 | ||||
| //		//logger_error("Invalid firmware offset reported!");
 | ||||
| //
 | ||||
| //		err_code = 1;
 | ||||
| //	}
 | ||||
| //	else if (pos_start > 0)
 | ||||
| //	{
 | ||||
| //		max_size = p_rsp_select->max_size;
 | ||||
| //		//crc_32 = crc32_compute(p_data, pos_start, NULL);
 | ||||
| //		len_remain = pos_start % max_size;
 | ||||
| //
 | ||||
| //		if (p_rsp_select->crc != crc_32)
 | ||||
| //		{
 | ||||
| //			pos_start -= ((len_remain > 0) ? len_remain : max_size);
 | ||||
| //			p_rsp_recover->offset = pos_start;
 | ||||
| //
 | ||||
| //			return err_code;
 | ||||
| //		}
 | ||||
| //
 | ||||
| //		if (len_remain > 0)
 | ||||
| //		{
 | ||||
| //			stp_size = max_size - len_remain;
 | ||||
| //
 | ||||
| //			err_code = dfu_serial_stream_data_crc(p_uart, p_data + pos_start, stp_size, pos_start, &crc_32);
 | ||||
| //			if (!err_code)
 | ||||
| //			{
 | ||||
| //				pos_start += stp_size;
 | ||||
| //			}
 | ||||
| //			else if (err_code == 2)
 | ||||
| //			{
 | ||||
| //				err_code = 0;
 | ||||
| //
 | ||||
| //				pos_start -= len_remain;
 | ||||
| //
 | ||||
| //				obj_exec = 0;
 | ||||
| //			}
 | ||||
| //
 | ||||
| //			p_rsp_recover->offset = pos_start;
 | ||||
| //		}
 | ||||
| //
 | ||||
| //		if (!err_code && obj_exec)
 | ||||
| //		{
 | ||||
| //			err_code = dfu_serial_execute_obj(p_uart);
 | ||||
| //		}
 | ||||
| //	}
 | ||||
| //
 | ||||
| //	return err_code;
 | ||||
| //}
 | ||||
| 
 | ||||
| int dfu_serial_send_firmware(uart_drv_t *p_uart, struct RNode* rn, const uint8_t *p_data, uint32_t data_size) | ||||
| { | ||||
|     uint8_t frame[DFU_PACKET_MAX_SIZE + 4]; | ||||
|     uint8_t hci_frame[(DFU_PACKET_MAX_SIZE + 4) * 2]; | ||||
| 	int err_code = 0; | ||||
| 
 | ||||
| 	//logger_info_1("Sending firmware file...");
 | ||||
| 
 | ||||
| 	if (p_data == NULL || !data_size) | ||||
| 	{ | ||||
| 		log_error("Payload data is invalid! Is your ZIP file corrupt?"); | ||||
| 
 | ||||
| 		err_code = 1; | ||||
| 	} | ||||
| 
 | ||||
|     if (!err_code) { | ||||
|         uint16_t len; | ||||
|         uint32_t hci_len; | ||||
| 
 | ||||
|         for (int i = 0; i < data_size; i = i + DFU_PACKET_MAX_SIZE) { | ||||
|             dfu_serial_u32_to_bytes(DFU_DATA_PACKET, frame, 0); | ||||
|             if (data_size - i > DFU_PACKET_MAX_SIZE) { | ||||
|                 len = DFU_PACKET_MAX_SIZE; | ||||
|             } else { | ||||
|                 len = data_size - i; | ||||
|             } | ||||
|             memcpy(frame+4, p_data+i, len); | ||||
|             hci_len = encode_hci(frame, len+4, hci_frame); | ||||
| 
 | ||||
|             err_code = dfu_serial_send(p_uart, hci_frame, hci_len); | ||||
| 
 | ||||
|             if (err_code) { | ||||
|                 log_error("Sending firmware to RNode failed! Is the device still connected?"); | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             // Trigger callback and provide percentage of packets sent
 | ||||
|             if (rn->prog_cb != NULL) { | ||||
|                 (*rn->prog_cb)(i / data_size * 100); | ||||
|             } | ||||
| 
 | ||||
|             // nrf52 is erasing and writing to flash
 | ||||
|             if (i % 8 == 0) { | ||||
|                 err_code = sleep_ms(FLASH_PAGE_WRITE_TIME); | ||||
|                 if (err_code) { | ||||
|                     log_error("Timing failed during flash, please try flashing again!"); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (!err_code) { | ||||
|             err_code = sleep_ms(FLASH_PAGE_WRITE_TIME); | ||||
| 
 | ||||
|             if (err_code) { | ||||
|                 log_error("Timing failed during flash, please try flashing again!"); | ||||
|             } | ||||
| 
 | ||||
|             dfu_serial_u32_to_bytes(DFU_STOP_DATA_PACKET, frame, 0); | ||||
|             hci_len = encode_hci(frame, 4, hci_frame); | ||||
| 
 | ||||
|             err_code = dfu_serial_send(p_uart, hci_frame, hci_len); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 	return err_code; | ||||
| } | ||||
							
								
								
									
										78
									
								
								src/libs/flashers/nrf/dfu_serial.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/libs/flashers/nrf/dfu_serial.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,78 @@ | ||||
| /**
 | ||||
| * Copyright (c) 2018, Nordic Semiconductor ASA | ||||
| * | ||||
| * All rights reserved. | ||||
| * | ||||
| * Redistribution and use in source and binary forms, with or without modification, | ||||
| * are permitted provided that the following conditions are met: | ||||
| * | ||||
| * 1. Redistributions of source code must retain the above copyright notice, this | ||||
| *    list of conditions and the following disclaimer. | ||||
| * | ||||
| * 2. Redistributions in binary form, except as embedded into a Nordic | ||||
| *    Semiconductor ASA integrated circuit in a product or a software update for | ||||
| *    such product, must reproduce the above copyright notice, this list of | ||||
| *    conditions and the following disclaimer in the documentation and/or other | ||||
| *    materials provided with the distribution. | ||||
| * | ||||
| * 3. Neither the name of Nordic Semiconductor ASA nor the names of its | ||||
| *    contributors may be used to endorse or promote products derived from this | ||||
| *    software without specific prior written permission. | ||||
| * | ||||
| * 4. This software, with or without modification, must only be used with a | ||||
| *    Nordic Semiconductor ASA integrated circuit. | ||||
| * | ||||
| * 5. Any software provided in binary form under this license must not be reverse | ||||
| *    engineered, decompiled, modified and/or disassembled. | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS | ||||
| * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
| * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE | ||||
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||||
| * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | ||||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| * | ||||
| * Modified by Jacob Eva (Liberated Embedded Systems) (c) 2025. | ||||
| * Changes licensed under the GPL. | ||||
| * This program is free software: you can redistribute it and/or modify it | ||||
| * under the terms of the GNU General Public License as published by the Free | ||||
| * Software Foundation, either version 3 of the License, or (at your option) | ||||
| * any later version. | ||||
| * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
| * more details. | ||||
| * You should have received a copy of the GNU General Public License along | ||||
| * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| 
 | ||||
| #pragma once | ||||
|   | ||||
| #ifndef _INC_DFU_SERIAL | ||||
| #define _INC_DFU_SERIAL | ||||
| 
 | ||||
| #include "uart_drv.h" | ||||
| #include "uart_slip.h" | ||||
| #include "../../../librnode.h" | ||||
| 
 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif  /* __cplusplus */ | ||||
| 
 | ||||
| int dfu_serial_send_start_dfu(uart_drv_t *p_uart, uint8_t mode, uint32_t softdevice_size, uint32_t bootloader_size, uint32_t application_size); | ||||
| 
 | ||||
| int dfu_serial_send_init(uart_drv_t *p_uart, const uint8_t *p_data, uint32_t data_size); | ||||
| 
 | ||||
| int dfu_serial_send_firmware(uart_drv_t *p_uart, struct RNode* rn, const uint8_t *p_data, uint32_t data_size); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| }   /* ... extern "C" */ | ||||
| #endif  /* __cplusplus */ | ||||
| 
 | ||||
| 
 | ||||
| #endif // _INC_DFU_SERIAL
 | ||||
							
								
								
									
										42
									
								
								src/libs/flashers/nrf/hci.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/libs/flashers/nrf/hci.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| /* Copyright (c) 2025 / Jacob Eva (Liberated Embedded Systems)
 | ||||
|  * This file provides some helper functions for encapsulating frames into HCI | ||||
|  * commands | ||||
|  * This program is free software: you can redistribute it and/or modify it | ||||
|  * under the terms of the GNU General Public License as published by the Free | ||||
|  * Software Foundation, either version 3 of the License, or (at your option) | ||||
|  * any later version. | ||||
|  * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
|  * more details. | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| #include "hci.h" | ||||
| #include "../../slip_enc.h" | ||||
| #include <string.h> | ||||
| #include "crc16.h" | ||||
| 
 | ||||
| uint8_t hci_seq = 0; | ||||
| 
 | ||||
| uint32_t encode_hci(uint8_t* raw_data, uint32_t raw_data_len, uint8_t* encoded_data) { | ||||
|     uint32_t encoded_data_size; | ||||
|     uint8_t temp_data[HCI_TEMP_BUF_SIZE]; | ||||
| 
 | ||||
|     hci_seq = (hci_seq + 1) % 8; | ||||
| 
 | ||||
|     slip_header(hci_seq, true, true, HCI_PACKET_TYPE, raw_data_len, temp_data); | ||||
| 
 | ||||
|     // Copy in raw data
 | ||||
|     memcpy(temp_data + SLIP_HEADER_LEN, raw_data, raw_data_len); | ||||
| 
 | ||||
|     uint16_t crc = crc16_compute(temp_data, raw_data_len + SLIP_HEADER_LEN); | ||||
| 
 | ||||
|     temp_data[SLIP_HEADER_LEN + raw_data_len] = crc & 0xFF; | ||||
|     temp_data[SLIP_HEADER_LEN + raw_data_len + 1] = (crc & 0xFF00) >> 8; | ||||
| 
 | ||||
| 
 | ||||
|     encode_slip(encoded_data, &encoded_data_size, temp_data, raw_data_len + SLIP_HEADER_LEN + CRC_SIZE, true); | ||||
| 
 | ||||
|     return encoded_data_size; | ||||
| } | ||||
							
								
								
									
										27
									
								
								src/libs/flashers/nrf/hci.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/libs/flashers/nrf/hci.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| /* Copyright (c) 2025 / Jacob Eva (Liberated Embedded Systems)
 | ||||
|  * This file provides some helper functions for encapsulating frames into HCI | ||||
|  * commands | ||||
|  * This program is free software: you can redistribute it and/or modify it | ||||
|  * under the terms of the GNU General Public License as published by the Free | ||||
|  * Software Foundation, either version 3 of the License, or (at your option) | ||||
|  * any later version. | ||||
|  * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
|  * more details. | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __HCI_H | ||||
| #define __HCI_H | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #define HCI_PACKET_TYPE 14 | ||||
| #define CRC_SIZE 16 / 8 | ||||
| #define HCI_TEMP_BUF_SIZE 2048 | ||||
| 
 | ||||
| uint32_t encode_hci(uint8_t* raw_data, uint32_t raw_data_len, uint8_t* encoded_data); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										318
									
								
								src/libs/flashers/nrf/jsmn.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										318
									
								
								src/libs/flashers/nrf/jsmn.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,318 @@ | ||||
| /* Copyright (c) / Jimmy Wong
 | ||||
|  * Originally distributed under the MIT license | ||||
|  */ | ||||
| 
 | ||||
| #include "jsmn.h" | ||||
| 
 | ||||
| /**
 | ||||
|  * Allocates a fresh unused token from the token pull. | ||||
|  */ | ||||
| static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, | ||||
| 		jsmntok_t *tokens, size_t num_tokens) { | ||||
| 	jsmntok_t *tok; | ||||
| 	if (parser->toknext >= num_tokens) { | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	tok = &tokens[parser->toknext++]; | ||||
| 	tok->start = tok->end = -1; | ||||
| 	tok->size = 0; | ||||
| #ifdef JSMN_PARENT_LINKS | ||||
| 	tok->parent = -1; | ||||
| #endif | ||||
| 	return tok; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Fills token type and boundaries. | ||||
|  */ | ||||
| static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, | ||||
|                             int start, int end) { | ||||
| 	token->type = type; | ||||
| 	token->start = start; | ||||
| 	token->end = end; | ||||
| 	token->size = 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Fills next available token with JSON primitive. | ||||
|  */ | ||||
| static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, | ||||
| 		size_t len, jsmntok_t *tokens, size_t num_tokens) { | ||||
| 	jsmntok_t *token; | ||||
| 	int start; | ||||
| 
 | ||||
| 	start = parser->pos; | ||||
| 
 | ||||
| 	for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { | ||||
| 		switch (js[parser->pos]) { | ||||
| #ifndef JSMN_STRICT | ||||
| 			/* In strict mode primitive must be followed by "," or "}" or "]" */ | ||||
| 			case ':': | ||||
| #endif | ||||
| 			case '\t' : case '\r' : case '\n' : case ' ' : | ||||
| 			case ','  : case ']'  : case '}' : | ||||
| 				goto found; | ||||
| 		} | ||||
| 		if (js[parser->pos] < 32 || js[parser->pos] >= 127) { | ||||
| 			parser->pos = start; | ||||
| 			return JSMN_ERROR_INVAL; | ||||
| 		} | ||||
| 	} | ||||
| #ifdef JSMN_STRICT | ||||
| 	/* In strict mode primitive must be followed by a comma/object/array */ | ||||
| 	parser->pos = start; | ||||
| 	return JSMN_ERROR_PART; | ||||
| #endif | ||||
| 
 | ||||
| found: | ||||
| 	if (tokens == NULL) { | ||||
| 		parser->pos--; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	token = jsmn_alloc_token(parser, tokens, num_tokens); | ||||
| 	if (token == NULL) { | ||||
| 		parser->pos = start; | ||||
| 		return JSMN_ERROR_NOMEM; | ||||
| 	} | ||||
| 	jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); | ||||
| #ifdef JSMN_PARENT_LINKS | ||||
| 	token->parent = parser->toksuper; | ||||
| #endif | ||||
| 	parser->pos--; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Fills next token with JSON string. | ||||
|  */ | ||||
| static int jsmn_parse_string(jsmn_parser *parser, const char *js, | ||||
| 		size_t len, jsmntok_t *tokens, size_t num_tokens) { | ||||
| 	jsmntok_t *token; | ||||
| 
 | ||||
| 	int start = parser->pos; | ||||
| 
 | ||||
| 	parser->pos++; | ||||
| 
 | ||||
| 	/* Skip starting quote */ | ||||
| 	for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { | ||||
| 		char c = js[parser->pos]; | ||||
| 
 | ||||
| 		/* Quote: end of string */ | ||||
| 		if (c == '\"') { | ||||
| 			if (tokens == NULL) { | ||||
| 				return 0; | ||||
| 			} | ||||
| 			token = jsmn_alloc_token(parser, tokens, num_tokens); | ||||
| 			if (token == NULL) { | ||||
| 				parser->pos = start; | ||||
| 				return JSMN_ERROR_NOMEM; | ||||
| 			} | ||||
| 			jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos); | ||||
| #ifdef JSMN_PARENT_LINKS | ||||
| 			token->parent = parser->toksuper; | ||||
| #endif | ||||
| 			return 0; | ||||
| 		} | ||||
| 
 | ||||
| 		/* Backslash: Quoted symbol expected */ | ||||
| 		if (c == '\\' && parser->pos + 1 < len) { | ||||
| 			int i; | ||||
| 			parser->pos++; | ||||
| 			switch (js[parser->pos]) { | ||||
| 				/* Allowed escaped symbols */ | ||||
| 				case '\"': case '/' : case '\\' : case 'b' : | ||||
| 				case 'f' : case 'r' : case 'n'  : case 't' : | ||||
| 					break; | ||||
| 				/* Allows escaped symbol \uXXXX */ | ||||
| 				case 'u': | ||||
| 					parser->pos++; | ||||
| 					for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) { | ||||
| 						/* If it isn't a hex character we have an error */ | ||||
| 						if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ | ||||
| 									(js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ | ||||
| 									(js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ | ||||
| 							parser->pos = start; | ||||
| 							return JSMN_ERROR_INVAL; | ||||
| 						} | ||||
| 						parser->pos++; | ||||
| 					} | ||||
| 					parser->pos--; | ||||
| 					break; | ||||
| 				/* Unexpected symbol */ | ||||
| 				default: | ||||
| 					parser->pos = start; | ||||
| 					return JSMN_ERROR_INVAL; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	parser->pos = start; | ||||
| 	return JSMN_ERROR_PART; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Parse JSON string and fill tokens. | ||||
|  */ | ||||
| int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, | ||||
| 		jsmntok_t *tokens, unsigned int num_tokens) { | ||||
| 	int r; | ||||
| 	int i; | ||||
| 	jsmntok_t *token; | ||||
| 	int count = parser->toknext; | ||||
| 
 | ||||
| 	for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { | ||||
| 		char c; | ||||
| 		jsmntype_t type; | ||||
| 
 | ||||
| 		c = js[parser->pos]; | ||||
| 		switch (c) { | ||||
| 			case '{': case '[': | ||||
| 				count++; | ||||
| 				if (tokens == NULL) { | ||||
| 					break; | ||||
| 				} | ||||
| 				token = jsmn_alloc_token(parser, tokens, num_tokens); | ||||
| 				if (token == NULL) | ||||
| 					return JSMN_ERROR_NOMEM; | ||||
| 				if (parser->toksuper != -1) { | ||||
| 					tokens[parser->toksuper].size++; | ||||
| #ifdef JSMN_PARENT_LINKS | ||||
| 					token->parent = parser->toksuper; | ||||
| #endif | ||||
| 				} | ||||
| 				token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); | ||||
| 				token->start = parser->pos; | ||||
| 				parser->toksuper = parser->toknext - 1; | ||||
| 				break; | ||||
| 			case '}': case ']': | ||||
| 				if (tokens == NULL) | ||||
| 					break; | ||||
| 				type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); | ||||
| #ifdef JSMN_PARENT_LINKS | ||||
| 				if (parser->toknext < 1) { | ||||
| 					return JSMN_ERROR_INVAL; | ||||
| 				} | ||||
| 				token = &tokens[parser->toknext - 1]; | ||||
| 				for (;;) { | ||||
| 					if (token->start != -1 && token->end == -1) { | ||||
| 						if (token->type != type) { | ||||
| 							return JSMN_ERROR_INVAL; | ||||
| 						} | ||||
| 						token->end = parser->pos + 1; | ||||
| 						parser->toksuper = token->parent; | ||||
| 						break; | ||||
| 					} | ||||
| 					if (token->parent == -1) { | ||||
| 						if(token->type != type || parser->toksuper == -1) { | ||||
| 							return JSMN_ERROR_INVAL; | ||||
| 						} | ||||
| 						break; | ||||
| 					} | ||||
| 					token = &tokens[token->parent]; | ||||
| 				} | ||||
| #else | ||||
| 				for (i = parser->toknext - 1; i >= 0; i--) { | ||||
| 					token = &tokens[i]; | ||||
| 					if (token->start != -1 && token->end == -1) { | ||||
| 						if (token->type != type) { | ||||
| 							return JSMN_ERROR_INVAL; | ||||
| 						} | ||||
| 						parser->toksuper = -1; | ||||
| 						token->end = parser->pos + 1; | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 				/* Error if unmatched closing bracket */ | ||||
| 				if (i == -1) return JSMN_ERROR_INVAL; | ||||
| 				for (; i >= 0; i--) { | ||||
| 					token = &tokens[i]; | ||||
| 					if (token->start != -1 && token->end == -1) { | ||||
| 						parser->toksuper = i; | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| #endif | ||||
| 				break; | ||||
| 			case '\"': | ||||
| 				r = jsmn_parse_string(parser, js, len, tokens, num_tokens); | ||||
| 				if (r < 0) return r; | ||||
| 				count++; | ||||
| 				if (parser->toksuper != -1 && tokens != NULL) | ||||
| 					tokens[parser->toksuper].size++; | ||||
| 				break; | ||||
| 			case '\t' : case '\r' : case '\n' : case ' ': | ||||
| 				break; | ||||
| 			case ':': | ||||
| 				parser->toksuper = parser->toknext - 1; | ||||
| 				break; | ||||
| 			case ',': | ||||
| 				if (tokens != NULL && parser->toksuper != -1 && | ||||
| 						tokens[parser->toksuper].type != JSMN_ARRAY && | ||||
| 						tokens[parser->toksuper].type != JSMN_OBJECT) { | ||||
| #ifdef JSMN_PARENT_LINKS | ||||
| 					parser->toksuper = tokens[parser->toksuper].parent; | ||||
| #else | ||||
| 					for (i = parser->toknext - 1; i >= 0; i--) { | ||||
| 						if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { | ||||
| 							if (tokens[i].start != -1 && tokens[i].end == -1) { | ||||
| 								parser->toksuper = i; | ||||
| 								break; | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| #endif | ||||
| 				} | ||||
| 				break; | ||||
| #ifdef JSMN_STRICT | ||||
| 			/* In strict mode primitives are: numbers and booleans */ | ||||
| 			case '-': case '0': case '1' : case '2': case '3' : case '4': | ||||
| 			case '5': case '6': case '7' : case '8': case '9': | ||||
| 			case 't': case 'f': case 'n' : | ||||
| 				/* And they must not be keys of the object */ | ||||
| 				if (tokens != NULL && parser->toksuper != -1) { | ||||
| 					jsmntok_t *t = &tokens[parser->toksuper]; | ||||
| 					if (t->type == JSMN_OBJECT || | ||||
| 							(t->type == JSMN_STRING && t->size != 0)) { | ||||
| 						return JSMN_ERROR_INVAL; | ||||
| 					} | ||||
| 				} | ||||
| #else | ||||
| 			/* In non-strict mode every unquoted value is a primitive */ | ||||
| 			default: | ||||
| #endif | ||||
| 				r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); | ||||
| 				if (r < 0) return r; | ||||
| 				count++; | ||||
| 				if (parser->toksuper != -1 && tokens != NULL) | ||||
| 					tokens[parser->toksuper].size++; | ||||
| 				break; | ||||
| 
 | ||||
| #ifdef JSMN_STRICT | ||||
| 			/* Unexpected char in strict mode */ | ||||
| 			default: | ||||
| 				return JSMN_ERROR_INVAL; | ||||
| #endif | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (tokens != NULL) { | ||||
| 		for (i = parser->toknext - 1; i >= 0; i--) { | ||||
| 			/* Unmatched opened object or array */ | ||||
| 			if (tokens[i].start != -1 && tokens[i].end == -1) { | ||||
| 				return JSMN_ERROR_PART; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return count; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Creates a new parser based over a given  buffer with an array of tokens | ||||
|  * available. | ||||
|  */ | ||||
| void jsmn_init(jsmn_parser *parser) { | ||||
| 	parser->pos = 0; | ||||
| 	parser->toknext = 0; | ||||
| 	parser->toksuper = -1; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										80
									
								
								src/libs/flashers/nrf/jsmn.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								src/libs/flashers/nrf/jsmn.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,80 @@ | ||||
| /* Copyright (c) / Jimmy Wong
 | ||||
|  * Originally distributed under the MIT license | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __JSMN_H_ | ||||
| #define __JSMN_H_ | ||||
| 
 | ||||
| #include <stddef.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
|  * JSON type identifier. Basic types are: | ||||
|  * 	o Object | ||||
|  * 	o Array | ||||
|  * 	o String | ||||
|  * 	o Other primitive: number, boolean (true/false) or null | ||||
|  */ | ||||
| typedef enum { | ||||
| 	JSMN_UNDEFINED = 0, | ||||
| 	JSMN_OBJECT = 1, | ||||
| 	JSMN_ARRAY = 2, | ||||
| 	JSMN_STRING = 3, | ||||
| 	JSMN_PRIMITIVE = 4 | ||||
| } jsmntype_t; | ||||
| 
 | ||||
| enum jsmnerr { | ||||
| 	/* Not enough tokens were provided */ | ||||
| 	JSMN_ERROR_NOMEM = -1, | ||||
| 	/* Invalid character inside JSON string */ | ||||
| 	JSMN_ERROR_INVAL = -2, | ||||
| 	/* The string is not a full JSON packet, more bytes expected */ | ||||
| 	JSMN_ERROR_PART = -3 | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * JSON token description. | ||||
|  * type		type (object, array, string etc.) | ||||
|  * start	start position in JSON data string | ||||
|  * end		end position in JSON data string | ||||
|  */ | ||||
| typedef struct { | ||||
| 	jsmntype_t type; | ||||
| 	int start; | ||||
| 	int end; | ||||
| 	int size; | ||||
| #ifdef JSMN_PARENT_LINKS | ||||
| 	int parent; | ||||
| #endif | ||||
| } jsmntok_t; | ||||
| 
 | ||||
| /**
 | ||||
|  * JSON parser. Contains an array of token blocks available. Also stores | ||||
|  * the string being parsed now and current position in that string | ||||
|  */ | ||||
| typedef struct { | ||||
| 	unsigned int pos; /* offset in the JSON string */ | ||||
| 	unsigned int toknext; /* next token to allocate */ | ||||
| 	int toksuper; /* superior token node, e.g parent object or array */ | ||||
| } jsmn_parser; | ||||
| 
 | ||||
| /**
 | ||||
|  * Create JSON parser over an array of tokens | ||||
|  */ | ||||
| void jsmn_init(jsmn_parser *parser); | ||||
| 
 | ||||
| /**
 | ||||
|  * Run JSON parser. It parses a JSON data string into and array of tokens, each describing | ||||
|  * a single JSON object. | ||||
|  */ | ||||
| int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, | ||||
| 		jsmntok_t *tokens, unsigned int num_tokens); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif /* __JSMN_H_ */ | ||||
							
								
								
									
										94
									
								
								src/libs/flashers/nrf/uart_drv.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								src/libs/flashers/nrf/uart_drv.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,94 @@ | ||||
| /**
 | ||||
| * Copyright (c) 2018, Nordic Semiconductor ASA | ||||
| * | ||||
| * All rights reserved. | ||||
| * | ||||
| * Redistribution and use in source and binary forms, with or without modification, | ||||
| * are permitted provided that the following conditions are met: | ||||
| * | ||||
| * 1. Redistributions of source code must retain the above copyright notice, this | ||||
| *    list of conditions and the following disclaimer. | ||||
| * | ||||
| * 2. Redistributions in binary form, except as embedded into a Nordic | ||||
| *    Semiconductor ASA integrated circuit in a product or a software update for | ||||
| *    such product, must reproduce the above copyright notice, this list of | ||||
| *    conditions and the following disclaimer in the documentation and/or other | ||||
| *    materials provided with the distribution. | ||||
| * | ||||
| * 3. Neither the name of Nordic Semiconductor ASA nor the names of its | ||||
| *    contributors may be used to endorse or promote products derived from this | ||||
| *    software without specific prior written permission. | ||||
| * | ||||
| * 4. This software, with or without modification, must only be used with a | ||||
| *    Nordic Semiconductor ASA integrated circuit. | ||||
| * | ||||
| * 5. Any software provided in binary form under this license must not be reverse | ||||
| *    engineered, decompiled, modified and/or disassembled. | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS | ||||
| * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
| * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE | ||||
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||||
| * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | ||||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| * | ||||
| * Modified by Jacob Eva (Liberated Embedded Systems) (c) 2025. | ||||
| * Changes licensed under the GPL. | ||||
| * This program is free software: you can redistribute it and/or modify it | ||||
| * under the terms of the GNU General Public License as published by the Free | ||||
| * Software Foundation, either version 3 of the License, or (at your option) | ||||
| * any later version. | ||||
| * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
| * more details. | ||||
| * You should have received a copy of the GNU General Public License along | ||||
| * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| 
 | ||||
| #pragma once | ||||
|   | ||||
| #ifndef _INC_UART_DRV | ||||
| #define _INC_UART_DRV | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #ifdef WIN32 | ||||
| #include <windows.h> | ||||
| #endif | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif  /* __cplusplus */ | ||||
| 
 | ||||
| 
 | ||||
| typedef struct { | ||||
| 	const char *p_PortName; | ||||
| 
 | ||||
| #ifdef WIN32 | ||||
| 	HANDLE portHandle; | ||||
| #else | ||||
| 	int tty_fd; | ||||
| #endif | ||||
| } uart_drv_t; | ||||
| 
 | ||||
| 
 | ||||
| int uart_drv_open(uart_drv_t *p_uart, bool touch); | ||||
| 
 | ||||
| int uart_drv_close(uart_drv_t *p_uart); | ||||
| 
 | ||||
| int uart_drv_send(uart_drv_t *p_uart, const uint8_t *pData, uint32_t nSize); | ||||
| 
 | ||||
| int uart_drv_receive(uart_drv_t *p_uart, uint8_t *pData, uint32_t nSize, uint32_t *pSize); | ||||
| 
 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| }   /* ... extern "C" */ | ||||
| #endif  /* __cplusplus */ | ||||
| 
 | ||||
| 
 | ||||
| #endif // _INC_UART_DRV
 | ||||
							
								
								
									
										283
									
								
								src/libs/flashers/nrf/uart_linux.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								src/libs/flashers/nrf/uart_linux.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,283 @@ | ||||
| /**
 | ||||
| * Copyright (c) 2018, Nordic Semiconductor ASA | ||||
| * | ||||
| * All rights reserved. | ||||
| * | ||||
| * Redistribution and use in source and binary forms, with or without modification, | ||||
| * are permitted provided that the following conditions are met: | ||||
| * | ||||
| * 1. Redistributions of source code must retain the above copyright notice, this | ||||
| *    list of conditions and the following disclaimer. | ||||
| * | ||||
| * 2. Redistributions in binary form, except as embedded into a Nordic | ||||
| *    Semiconductor ASA integrated circuit in a product or a software update for | ||||
| *    such product, must reproduce the above copyright notice, this list of | ||||
| *    conditions and the following disclaimer in the documentation and/or other | ||||
| *    materials provided with the distribution. | ||||
| * | ||||
| * 3. Neither the name of Nordic Semiconductor ASA nor the names of its | ||||
| *    contributors may be used to endorse or promote products derived from this | ||||
| *    software without specific prior written permission. | ||||
| * | ||||
| * 4. This software, with or without modification, must only be used with a | ||||
| *    Nordic Semiconductor ASA integrated circuit. | ||||
| * | ||||
| * 5. Any software provided in binary form under this license must not be reverse | ||||
| *    engineered, decompiled, modified and/or disassembled. | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS | ||||
| * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
| * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE | ||||
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||||
| * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | ||||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| * | ||||
| * Modified by Jacob Eva (Liberated Embedded Systems) (c) 2025. | ||||
| * Changes licensed under the GPL. | ||||
| * This program is free software: you can redistribute it and/or modify it | ||||
| * under the terms of the GNU General Public License as published by the Free | ||||
| * Software Foundation, either version 3 of the License, or (at your option) | ||||
| * any later version. | ||||
| * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
| * more details. | ||||
| * You should have received a copy of the GNU General Public License along | ||||
| * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| 
 | ||||
| #include <unistd.h> | ||||
| #include <fcntl.h> | ||||
| #include <termios.h> | ||||
| #include <string.h> | ||||
| #include <time.h> | ||||
| #include "uart_drv.h" | ||||
| #include "../../util.h" | ||||
| #include "../../logging/log.h" | ||||
| 
 | ||||
| #define SERIAL_WAIT_TIME 100 // ms
 | ||||
| #define TOUCH_RESET_WAIT_TIME 1500 // ms
 | ||||
| #define NSEC_EXPONENT 1000000 | ||||
| 
 | ||||
| int uart_drv_open(uart_drv_t *p_uart, bool touch) | ||||
| { | ||||
| 	int err_code = 0; | ||||
| 	int fd = -1; | ||||
| 	char tty_path[200]; | ||||
| 	struct termios options; | ||||
| 
 | ||||
| 	strcpy(tty_path, p_uart->p_PortName); | ||||
| 	//if (strlen(tty_name) <= 14)
 | ||||
| 	//	strcat(tty_path, tty_name);
 | ||||
| 	//else
 | ||||
| 	//{
 | ||||
| 	//	log_error("Invalid access port for RNode!");
 | ||||
| 
 | ||||
| 	//	err_code = 1;
 | ||||
| 	//}
 | ||||
| 
 | ||||
| 	if (!err_code) | ||||
| 	{ | ||||
| 		fd = open(tty_path, O_RDWR | O_NOCTTY); | ||||
| 
 | ||||
| 		if (fd < 0) | ||||
| 		{ | ||||
| 			log_error("Cannot open RNode port! Is the RNode connected?"); | ||||
| 
 | ||||
| 			err_code = 1; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (!err_code) | ||||
| 	{ | ||||
|         tcgetattr(fd, &options); | ||||
| 
 | ||||
|         if (touch) { | ||||
|             log_debug("Touching RNode port."); | ||||
|             // 1200 bps
 | ||||
|             cfsetispeed(&options, B1200); | ||||
|             cfsetospeed(&options, B1200); | ||||
|         } else { | ||||
|             // 115200 bps
 | ||||
|             cfsetispeed(&options, B115200); | ||||
|             cfsetospeed(&options, B115200); | ||||
|         } | ||||
| 
 | ||||
| 		if (tcsetattr(fd, TCSANOW, &options)) | ||||
| 		{ | ||||
| 			log_error("Cannot set RNode port options!"); | ||||
| 
 | ||||
| 			err_code = 1; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (!err_code) | ||||
| 	{ | ||||
| 		if (tcflush(fd, TCIFLUSH)) | ||||
| 		{ | ||||
| 			log_error("Cannot flush RNode port reception buffer!"); | ||||
| 
 | ||||
| 			err_code = 1; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (err_code && fd >= 0) | ||||
| 	{ | ||||
| 		p_uart->tty_fd = fd; | ||||
| 		uart_drv_close(p_uart); | ||||
| 
 | ||||
| 		fd = -1; | ||||
| 	} | ||||
| 
 | ||||
|     // Opening and closing serial port once is necessary to enter DFU mode
 | ||||
|     if (touch) { | ||||
|         sleep_ms(SERIAL_WAIT_TIME); | ||||
| 
 | ||||
|         close(fd); | ||||
| 
 | ||||
|         // Wait, then open it again
 | ||||
|         sleep_ms(TOUCH_RESET_WAIT_TIME); | ||||
|          | ||||
| 		fd = open(tty_path, O_RDWR | O_NOCTTY); | ||||
| 
 | ||||
|         // 115200 bps
 | ||||
|         cfsetispeed(&options, B115200); | ||||
|         cfsetospeed(&options, B115200); | ||||
| 
 | ||||
|         log_debug("Opened RNode port after touch."); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     // 8N1
 | ||||
|     options.c_cflag &= ~PARENB; | ||||
|     options.c_cflag &= ~CSTOPB; | ||||
|     options.c_cflag &= ~CSIZE; | ||||
|     options.c_cflag |= CS8; | ||||
|     // ignore DCD line
 | ||||
|     options.c_cflag |= (CLOCAL | CREAD); | ||||
|     // disable RTS/CTS handshake
 | ||||
|     options.c_cflag &= CRTSCTS; | ||||
|     // disable XON/XOFF handshake
 | ||||
|     options.c_iflag &= ~(IXON | IXOFF | IXANY); | ||||
|     // disable input mapping options
 | ||||
|     options.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IUCLC); | ||||
|     // select RAW input
 | ||||
|     options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); | ||||
|     // select RAW output
 | ||||
|     options.c_oflag &= ~OPOST; | ||||
|     // disable output mapping options
 | ||||
|     options.c_oflag &= ~(OLCUC | ONLCR | OCRNL | ONOCR | ONLRET); | ||||
|     // set read timeout
 | ||||
|     options.c_cc[VMIN] = 0; | ||||
|     options.c_cc[VTIME] = 5;  // 0.5 seconds
 | ||||
|      | ||||
|     if (tcsetattr(fd, TCSANOW, &options)) | ||||
|     { | ||||
|         log_error("Cannot set RNode port options!"); | ||||
| 
 | ||||
|         err_code = 1; | ||||
|     } | ||||
| 	p_uart->tty_fd = fd; | ||||
| 
 | ||||
| 	return err_code; | ||||
| } | ||||
| 
 | ||||
| int uart_drv_close(uart_drv_t *p_uart) | ||||
| { | ||||
| 	int err_code = 0; | ||||
| 	int fd = p_uart->tty_fd; | ||||
| 
 | ||||
| 	if (fd >= 0) | ||||
| 	{ | ||||
| 		if (close(fd)) | ||||
| 		{ | ||||
| 			log_error("Cannot close RNode port!"); | ||||
| 
 | ||||
| 			err_code = 1; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 		err_code = 1; | ||||
| 	 | ||||
| 	return err_code; | ||||
| } | ||||
| 
 | ||||
| extern uint8_t hci_seq; | ||||
| uint8_t hci_errors = 0; | ||||
| 
 | ||||
| int uart_drv_send(uart_drv_t *p_uart, const uint8_t *pData, uint32_t nSize) | ||||
| { | ||||
| 	int err_code = 0; | ||||
| 	uint32_t length; | ||||
|     uint8_t rx[256]; | ||||
| 
 | ||||
| 	length = write(p_uart->tty_fd, pData, nSize); | ||||
| 	if (length != nSize) | ||||
| 	{ | ||||
| 		log_error("Cannot write to the RNode port!"); | ||||
| 
 | ||||
| 		err_code = 1; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if (tcdrain(p_uart->tty_fd)) | ||||
| 		{ | ||||
| 			log_error("Cannot empty RNode port transmission buffer!"); | ||||
| 
 | ||||
| 			err_code = 1; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|     if (err_code) { | ||||
|         return err_code; | ||||
|     } | ||||
| 
 | ||||
|     err_code = uart_drv_receive(p_uart, rx, sizeof(rx), &length); | ||||
| 
 | ||||
|     if (err_code) { | ||||
|         return err_code; | ||||
|     } | ||||
| 
 | ||||
|     if (length > 0) { | ||||
|         uint8_t hci_ack = (rx[1] >> 3) & 0x07; | ||||
|         if ((hci_seq + 1) % 8 != hci_ack) { | ||||
|             log_error("HCI sequence number returned from RNode was invalid!"); | ||||
|             log_trace("Expected %u, but got %u", (hci_seq + 1 % 8), hci_ack); | ||||
|             hci_errors++; | ||||
|         } else { | ||||
|             hci_errors = 0; | ||||
|         } | ||||
|     } else { | ||||
|         log_debug("RNode hasn't responded with a HCI sequence, ignoring for now..."); | ||||
|         hci_errors++; | ||||
|     } | ||||
| 
 | ||||
|     if (hci_errors >= 3) { | ||||
|         log_error("RNode hasn't responded with a HCI sequence 3 times, aborting..."); | ||||
|         err_code = 1; | ||||
|     } | ||||
| 
 | ||||
| 	return err_code; | ||||
| } | ||||
| 
 | ||||
| int uart_drv_receive(uart_drv_t *p_uart, uint8_t *pData, uint32_t nSize, uint32_t *pSize) | ||||
| { | ||||
| 	int err_code = 0; | ||||
| 	int32_t length; | ||||
| 	 | ||||
| 	length = read(p_uart->tty_fd, pData, nSize); | ||||
| 	if (length < 0) | ||||
| 	{ | ||||
| 		log_error("Cannot read RNode port!"); | ||||
| 
 | ||||
| 		err_code = 1; | ||||
| 	} | ||||
| 	else | ||||
| 		*pSize = length; | ||||
| 	 | ||||
| 	return err_code; | ||||
| } | ||||
							
								
								
									
										134
									
								
								src/libs/flashers/nrf/uart_slip.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								src/libs/flashers/nrf/uart_slip.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,134 @@ | ||||
| /**
 | ||||
| * Copyright (c) 2017, Nordic Semiconductor ASA | ||||
| * | ||||
| * All rights reserved. | ||||
| * | ||||
| * Redistribution and use in source and binary forms, with or without modification, | ||||
| * are permitted provided that the following conditions are met: | ||||
| * | ||||
| * 1. Redistributions of source code must retain the above copyright notice, this | ||||
| *    list of conditions and the following disclaimer. | ||||
| * | ||||
| * 2. Redistributions in binary form, except as embedded into a Nordic | ||||
| *    Semiconductor ASA integrated circuit in a product or a software update for | ||||
| *    such product, must reproduce the above copyright notice, this list of | ||||
| *    conditions and the following disclaimer in the documentation and/or other | ||||
| *    materials provided with the distribution. | ||||
| * | ||||
| * 3. Neither the name of Nordic Semiconductor ASA nor the names of its | ||||
| *    contributors may be used to endorse or promote products derived from this | ||||
| *    software without specific prior written permission. | ||||
| * | ||||
| * 4. This software, with or without modification, must only be used with a | ||||
| *    Nordic Semiconductor ASA integrated circuit. | ||||
| * | ||||
| * 5. Any software provided in binary form under this license must not be reverse | ||||
| *    engineered, decompiled, modified and/or disassembled. | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS | ||||
| * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
| * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE | ||||
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||||
| * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | ||||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| * | ||||
| * Modified by Jacob Eva (Liberated Embedded Systems) (c) 2025. | ||||
| * Changes licensed under the GPL. | ||||
| * This program is free software: you can redistribute it and/or modify it | ||||
| * under the terms of the GNU General Public License as published by the Free | ||||
| * Software Foundation, either version 3 of the License, or (at your option) | ||||
| * any later version. | ||||
| * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
| * more details. | ||||
| * You should have received a copy of the GNU General Public License along | ||||
| * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| 
 | ||||
| #include <string.h> | ||||
| #include "uart_slip.h" | ||||
| #include "../../slip_enc.h" | ||||
| #include "../../logging/log.h" | ||||
| 
 | ||||
| #define UART_SLIP_BUFF_SIZE		(UART_SLIP_SIZE_MAX * 2 + 1) | ||||
| 
 | ||||
| static uint8_t uart_slip_buff[UART_SLIP_BUFF_SIZE]; | ||||
| 
 | ||||
| int uart_slip_open(uart_drv_t *p_uart, bool touch) | ||||
| { | ||||
| 	return uart_drv_open(p_uart, touch); | ||||
| } | ||||
| 
 | ||||
| int uart_slip_close(uart_drv_t *p_uart) | ||||
| { | ||||
| 	return uart_drv_close(p_uart); | ||||
| } | ||||
| 
 | ||||
| int uart_slip_send(uart_drv_t *p_uart, const uint8_t *pData, uint32_t nSize) | ||||
| { | ||||
| 	int err_code = 0; | ||||
| 	uint32_t nSlipSize; | ||||
| 
 | ||||
| 	if (nSize > UART_SLIP_SIZE_MAX) | ||||
| 	{ | ||||
| 		log_error("Cannot encode SLIP, allocated buffer too small!"); | ||||
| 
 | ||||
| 		err_code = 1; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		encode_slip(uart_slip_buff, &nSlipSize, pData, nSize, true); | ||||
| 
 | ||||
| 		err_code = uart_drv_send(p_uart, uart_slip_buff, nSlipSize); | ||||
| 	} | ||||
| 
 | ||||
| 	return err_code; | ||||
| } | ||||
| 
 | ||||
| int uart_slip_receive(uart_drv_t *p_uart, uint8_t *pData, uint32_t nSize, uint32_t *pSize) | ||||
| { | ||||
| 	int err_code = 0; | ||||
| 	uint32_t sizeBuffer; | ||||
| 	uint32_t length, slip_len = 0; | ||||
| 
 | ||||
| 	do | ||||
| 	{ | ||||
| 		sizeBuffer = sizeof(uart_slip_buff) - slip_len; | ||||
| 		if (!sizeBuffer) | ||||
| 		{ | ||||
| 			log_error("RNode port buffer overflow!"); | ||||
| 
 | ||||
| 			err_code = 1; | ||||
| 
 | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		length = 0; | ||||
| 		err_code = uart_drv_receive(p_uart, uart_slip_buff + slip_len, sizeBuffer, &length); | ||||
| 		if (err_code) | ||||
| 			break; | ||||
| 
 | ||||
| 		if (!length) | ||||
| 		{ | ||||
| 			log_error("Read no data from RNode port!"); | ||||
| 
 | ||||
| 			err_code = 1; | ||||
| 
 | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		slip_len += length; | ||||
| 
 | ||||
| 		if (!decode_slip(pData, pSize, uart_slip_buff, slip_len)) | ||||
| 		{ | ||||
| 			break; | ||||
| 		} | ||||
| 	} while (!err_code); | ||||
| 
 | ||||
| 	return err_code; | ||||
| } | ||||
							
								
								
									
										85
									
								
								src/libs/flashers/nrf/uart_slip.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/libs/flashers/nrf/uart_slip.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,85 @@ | ||||
| /**
 | ||||
| * Copyright (c) 2017, Nordic Semiconductor ASA | ||||
| * | ||||
| * All rights reserved. | ||||
| * | ||||
| * Redistribution and use in source and binary forms, with or without modification, | ||||
| * are permitted provided that the following conditions are met: | ||||
| * | ||||
| * 1. Redistributions of source code must retain the above copyright notice, this | ||||
| *    list of conditions and the following disclaimer. | ||||
| * | ||||
| * 2. Redistributions in binary form, except as embedded into a Nordic | ||||
| *    Semiconductor ASA integrated circuit in a product or a software update for | ||||
| *    such product, must reproduce the above copyright notice, this list of | ||||
| *    conditions and the following disclaimer in the documentation and/or other | ||||
| *    materials provided with the distribution. | ||||
| * | ||||
| * 3. Neither the name of Nordic Semiconductor ASA nor the names of its | ||||
| *    contributors may be used to endorse or promote products derived from this | ||||
| *    software without specific prior written permission. | ||||
| * | ||||
| * 4. This software, with or without modification, must only be used with a | ||||
| *    Nordic Semiconductor ASA integrated circuit. | ||||
| * | ||||
| * 5. Any software provided in binary form under this license must not be reverse | ||||
| *    engineered, decompiled, modified and/or disassembled. | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS | ||||
| * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
| * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE | ||||
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||||
| * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | ||||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| * | ||||
| * Modified by Jacob Eva (Liberated Embedded Systems) (c) 2025. | ||||
| * Changes licensed under the GPL. | ||||
| * This program is free software: you can redistribute it and/or modify it | ||||
| * under the terms of the GNU General Public License as published by the Free | ||||
| * Software Foundation, either version 3 of the License, or (at your option) | ||||
| * any later version. | ||||
| * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
| * more details. | ||||
| * You should have received a copy of the GNU General Public License along | ||||
| * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| 
 | ||||
| #pragma once | ||||
|   | ||||
| #ifndef _INC_UART_SLIP | ||||
| #define _INC_UART_SLIP | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include "uart_drv.h" | ||||
| 
 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif  /* __cplusplus */ | ||||
| 
 | ||||
| 
 | ||||
| #define UART_SLIP_SIZE_MAX		128 | ||||
| 
 | ||||
| 
 | ||||
| int uart_slip_open(uart_drv_t *p_uart, bool touch); | ||||
| 
 | ||||
| int uart_slip_close(uart_drv_t *p_uart); | ||||
| 
 | ||||
| int uart_slip_send(uart_drv_t *p_uart, const uint8_t *pData, uint32_t nSize); | ||||
| 
 | ||||
| int uart_slip_receive(uart_drv_t *p_uart, uint8_t *pData, uint32_t nSize, uint32_t *pSize); | ||||
| 
 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| }   /* ... extern "C" */ | ||||
| #endif  /* __cplusplus */ | ||||
| 
 | ||||
| 
 | ||||
| #endif // _INC_UART_SLIP
 | ||||
							
								
								
									
										231
									
								
								src/libs/flashers/nrf/uart_win32.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										231
									
								
								src/libs/flashers/nrf/uart_win32.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,231 @@ | ||||
| /**
 | ||||
| * Copyright (c) 2018, Nordic Semiconductor ASA | ||||
| * | ||||
| * All rights reserved. | ||||
| * | ||||
| * Redistribution and use in source and binary forms, with or without modification, | ||||
| * are permitted provided that the following conditions are met: | ||||
| * | ||||
| * 1. Redistributions of source code must retain the above copyright notice, this | ||||
| *    list of conditions and the following disclaimer. | ||||
| * | ||||
| * 2. Redistributions in binary form, except as embedded into a Nordic | ||||
| *    Semiconductor ASA integrated circuit in a product or a software update for | ||||
| *    such product, must reproduce the above copyright notice, this list of | ||||
| *    conditions and the following disclaimer in the documentation and/or other | ||||
| *    materials provided with the distribution. | ||||
| * | ||||
| * 3. Neither the name of Nordic Semiconductor ASA nor the names of its | ||||
| *    contributors may be used to endorse or promote products derived from this | ||||
| *    software without specific prior written permission. | ||||
| * | ||||
| * 4. This software, with or without modification, must only be used with a | ||||
| *    Nordic Semiconductor ASA integrated circuit. | ||||
| * | ||||
| * 5. Any software provided in binary form under this license must not be reverse | ||||
| *    engineered, decompiled, modified and/or disassembled. | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS | ||||
| * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
| * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE | ||||
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||||
| * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | ||||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| * | ||||
| * Modified by Jacob Eva (Liberated Embedded Systems) (c) 2025. | ||||
| * Changes licensed under the GPL. | ||||
| * This program is free software: you can redistribute it and/or modify it | ||||
| * under the terms of the GNU General Public License as published by the Free | ||||
| * Software Foundation, either version 3 of the License, or (at your option) | ||||
| * any later version. | ||||
| * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
| * more details. | ||||
| * You should have received a copy of the GNU General Public License along | ||||
| * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| */ | ||||
| 
 | ||||
| #include <string.h> | ||||
| #include "uart_drv.h" | ||||
| #include "logging.h" | ||||
| 
 | ||||
| int uart_drv_open(uart_drv_t *p_uart, bool touch) | ||||
| { | ||||
| 	int err_code = 0; | ||||
| 	const char *portName = p_uart->p_PortName; | ||||
| 	CHAR portFileName[14]; | ||||
| 	HANDLE handlePort_ = INVALID_HANDLE_VALUE; | ||||
| 
 | ||||
| 	strcpy(portFileName, "\\\\.\\"); | ||||
| 	if (strlen(portName) <= 6) | ||||
| 		strcat(portFileName, portName); | ||||
| 	else | ||||
| 	{ | ||||
| 		logger_error("Invalid COM port!"); | ||||
| 
 | ||||
| 		err_code = 1; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!err_code) | ||||
| 	{ | ||||
| 		handlePort_ = CreateFile(portFileName,  // Specify port device: default "COM1"
 | ||||
| 			GENERIC_READ | GENERIC_WRITE,       // Specify mode that open device.
 | ||||
| 			0,                                  // the devide isn't shared.
 | ||||
| 			NULL,                               // the object gets a default security.
 | ||||
| 			OPEN_EXISTING,                      // Specify which action to take on file. 
 | ||||
| 			0,                                  // default.
 | ||||
| 			NULL);                              // default.
 | ||||
| 
 | ||||
| 		if (handlePort_ == INVALID_HANDLE_VALUE) | ||||
| 		{ | ||||
| 			logger_error("Cannot open COM port!"); | ||||
| 
 | ||||
| 			err_code = 1; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (!err_code) | ||||
| 	{ | ||||
| 		DCB config_; | ||||
| 
 | ||||
| 		// Get current configuration of serial communication port.
 | ||||
| 		if (GetCommState(handlePort_, &config_) == FALSE) | ||||
| 		{ | ||||
| 			logger_error("Cannot get COM configuration!"); | ||||
| 
 | ||||
| 			err_code = 1; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!err_code) | ||||
| 		{ | ||||
| 			config_.BaudRate = 115200;		// Specify buad rate of communicaiton.
 | ||||
| 			config_.StopBits = 0;			// Specify stopbit of communication.
 | ||||
| 			config_.Parity = 0;				// Specify parity of communication.
 | ||||
| 			config_.ByteSize = 8;			// Specify byte of size of communication.
 | ||||
| 			config_.fDtrControl = DTR_CONTROL_DISABLE; | ||||
| 			config_.fDsrSensitivity = 0; | ||||
| 			config_.fRtsControl = RTS_CONTROL_HANDSHAKE; | ||||
| 			config_.fInX = 0; | ||||
| 			config_.fOutX = 0; | ||||
| 			config_.fBinary = 1; | ||||
| 			if (SetCommState(handlePort_, &config_) == FALSE) | ||||
| 			{ | ||||
| 				logger_error("Cannot set COM configuration!"); | ||||
| 
 | ||||
| 				err_code = 1; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (!err_code) | ||||
| 	{ | ||||
| 		// instance an object of COMMTIMEOUTS.
 | ||||
| 		COMMTIMEOUTS comTimeOut; | ||||
| 		// Specify value is added to the product of the 
 | ||||
| 		// ReadTotalTimeoutMultiplier member
 | ||||
| 		comTimeOut.ReadTotalTimeoutConstant = 500; | ||||
| 		// Specify value that is multiplied 
 | ||||
| 		// by the requested number of bytes to be read. 
 | ||||
| 		comTimeOut.ReadTotalTimeoutMultiplier = 10; | ||||
| 		// Specify time-out between charactor for receiving.
 | ||||
| 		comTimeOut.ReadIntervalTimeout = 100; | ||||
| 		// Specify value that is multiplied 
 | ||||
| 		// by the requested number of bytes to be sent. 
 | ||||
| 		comTimeOut.WriteTotalTimeoutMultiplier = 15; | ||||
| 		// Specify value is added to the product of the 
 | ||||
| 		// WriteTotalTimeoutMultiplier member
 | ||||
| 		comTimeOut.WriteTotalTimeoutConstant = 300; | ||||
| 		// set the time-out parameter into device control.
 | ||||
| 		SetCommTimeouts(handlePort_, &comTimeOut); | ||||
| 	} | ||||
| 
 | ||||
| 	if (!err_code) | ||||
| 	{ | ||||
| 		if (PurgeComm(handlePort_, PURGE_RXCLEAR) == FALSE) | ||||
| 		{ | ||||
| 			logger_error("Cannot purge COM RX buffer!"); | ||||
| 
 | ||||
| 			err_code = 1; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (err_code && handlePort_ != INVALID_HANDLE_VALUE) | ||||
| 	{ | ||||
| 		p_uart->portHandle = handlePort_; | ||||
| 		uart_drv_close(p_uart); | ||||
| 
 | ||||
| 		handlePort_ = INVALID_HANDLE_VALUE; | ||||
| 	} | ||||
| 
 | ||||
| 	p_uart->portHandle = handlePort_; | ||||
| 
 | ||||
| 	return err_code; | ||||
| } | ||||
| 
 | ||||
| int uart_drv_close(uart_drv_t *p_uart) | ||||
| { | ||||
| 	int err_code = 0; | ||||
| 	HANDLE portHandle = p_uart->portHandle; | ||||
| 
 | ||||
| 	if (portHandle != INVALID_HANDLE_VALUE) | ||||
| 	{ | ||||
| 		if (CloseHandle(portHandle) == FALSE)    // Call this function to close port.
 | ||||
| 		{ | ||||
| 			logger_error("Cannot close COM port!"); | ||||
| 
 | ||||
| 			err_code = 1; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 		err_code = 1; | ||||
| 
 | ||||
| 	return err_code; | ||||
| } | ||||
| 
 | ||||
| int uart_drv_send(uart_drv_t *p_uart, const uint8_t *pData, uint32_t nSize) | ||||
| { | ||||
| 	int err_code = 0; | ||||
| 	HANDLE portHandle = p_uart->portHandle; | ||||
| 	DWORD length; | ||||
| 
 | ||||
| 	if (WriteFile(portHandle,           // handle to file to write to
 | ||||
| 		pData,                          // pointer to data to write to file
 | ||||
| 		nSize,                          // number of bytes to write
 | ||||
| 		&length, NULL) == FALSE ||      // pointer to number of bytes written
 | ||||
| 		length < nSize) | ||||
| 	{ | ||||
| 		logger_error("Cannot write COM port!"); | ||||
| 
 | ||||
| 		err_code = 1; | ||||
| 	} | ||||
| 
 | ||||
| 	return err_code; | ||||
| } | ||||
| 
 | ||||
| int uart_drv_receive(uart_drv_t *p_uart, uint8_t *pData, uint32_t nSize, uint32_t *pSize) | ||||
| { | ||||
| 	int err_code = 0; | ||||
| 	HANDLE portHandle = p_uart->portHandle; | ||||
| 	DWORD length = 0; | ||||
| 
 | ||||
| 	if (ReadFile(portHandle,            // handle of file to read
 | ||||
| 		pData,                          // pointer to data to read from file
 | ||||
| 		nSize,                          // number of bytes to read
 | ||||
| 		&length,                        // pointer to number of bytes read
 | ||||
| 		NULL) == FALSE)                 // pointer to structure for data
 | ||||
| 	{ | ||||
| 		logger_error("Cannot read COM port!"); | ||||
| 
 | ||||
| 		err_code = 1; | ||||
| 	} | ||||
| 
 | ||||
| 	*pSize = length; | ||||
| 
 | ||||
| 	return err_code; | ||||
| } | ||||
							
								
								
									
										109
									
								
								src/libs/framing.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								src/libs/framing.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,109 @@ | ||||
| // Copyright (C) 2024, Mark Qvist
 | ||||
| 
 | ||||
| // This program is free software: you can redistribute it and/or modify
 | ||||
| // it under the terms of the GNU General Public License as published by
 | ||||
| // the Free Software Foundation, either version 3 of the License, or
 | ||||
| // (at your option) any later version.
 | ||||
| 
 | ||||
| // This program is distributed in the hope that it will be useful,
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | ||||
| // GNU General Public License for more details.
 | ||||
| 
 | ||||
| // You should have received a copy of the GNU General Public License
 | ||||
| // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | ||||
| //
 | ||||
| // Modified by Jacob Eva (Liberated Embedded Systems), still under the terms of
 | ||||
| // the GPLv3.
 | ||||
| 
 | ||||
| #ifndef FRAMING_H | ||||
|   #define FRAMING_H | ||||
| 
 | ||||
|   #define FEND            0xC0 | ||||
|   #define FESC            0xDB | ||||
|   #define TFEND           0xDC | ||||
|   #define TFESC           0xDD | ||||
| 
 | ||||
|   #define CMD_UNKNOWN     0xFE | ||||
|   #define CMD_DATA        0x00 | ||||
|   #define CMD_FREQUENCY   0x01 | ||||
|   #define CMD_BANDWIDTH   0x02 | ||||
|   #define CMD_TXPOWER     0x03 | ||||
|   #define CMD_SF          0x04 | ||||
|   #define CMD_CR          0x05 | ||||
|   #define CMD_RADIO_STATE 0x06 | ||||
|   #define CMD_RADIO_LOCK  0x07 | ||||
|   #define CMD_DETECT      0x08 | ||||
|   #define CMD_IMPLICIT    0x09 | ||||
|   #define CMD_LEAVE       0x0A | ||||
|   #define CMD_ST_ALOCK    0x0B | ||||
|   #define CMD_LT_ALOCK    0x0C | ||||
|   #define CMD_PROMISC     0x0E | ||||
|   #define CMD_READY       0x0F | ||||
| 
 | ||||
|   #define CMD_STAT_RX     0x21 | ||||
|   #define CMD_STAT_TX     0x22 | ||||
|   #define CMD_STAT_RSSI   0x23 | ||||
|   #define CMD_STAT_SNR    0x24 | ||||
|   #define CMD_STAT_CHTM   0x25 | ||||
|   #define CMD_STAT_PHYPRM 0x26 | ||||
|   #define CMD_STAT_BAT    0x27 | ||||
|   #define CMD_STAT_CSMA   0x28 | ||||
|   #define CMD_BLINK       0x30 | ||||
|   #define CMD_RANDOM      0x40 | ||||
| 
 | ||||
|   #define CMD_FB_EXT      0x41 | ||||
|   #define CMD_FB_READ     0x42 | ||||
|   #define CMD_FB_WRITE    0x43 | ||||
|   #define CMD_FB_READL    0x44 | ||||
|   #define CMD_DISP_READ   0x66 | ||||
|   #define CMD_DISP_INT    0x45 | ||||
|   #define CMD_DISP_ADDR   0x63 | ||||
|   #define CMD_DISP_BLNK   0x64 | ||||
|   #define CMD_DISP_ROT    0x67 | ||||
|   #define CMD_DISP_RCND   0x68 | ||||
|   #define CMD_NP_INT      0x65 | ||||
|   #define CMD_BT_CTRL     0x46 | ||||
|   #define CMD_BT_PIN      0x62 | ||||
|   #define CMD_DIS_IA      0x69 | ||||
| 
 | ||||
|   #define CMD_BOARD       0x47 | ||||
|   #define CMD_PLATFORM    0x48 | ||||
|   #define CMD_MCU         0x49 | ||||
|   #define CMD_FW_VERSION  0x50 | ||||
|   #define CMD_ROM_READ    0x51 | ||||
|   #define CMD_ROM_WRITE   0x52 | ||||
|   #define CMD_CONF_SAVE   0x53 | ||||
|   #define CMD_CONF_DELETE 0x54 | ||||
|   #define CMD_DEV_HASH    0x56 | ||||
|   #define CMD_DEV_SIG     0x57 | ||||
|   #define CMD_FW_HASH     0x58 | ||||
|   #define CMD_HASHES      0x60 | ||||
|   #define CMD_FW_UPD      0x61 | ||||
|   #define CMD_UNLOCK_ROM  0x59 | ||||
|   #define ROM_UNLOCK_BYTE 0xF8 | ||||
|   #define CMD_RESET       0x55 | ||||
|   #define CMD_RESET_BYTE  0xF8 | ||||
| 
 | ||||
|   #define CMD_INTERFACES  0x64 | ||||
|   #define CMD_SEL_INT     0x1F | ||||
| 
 | ||||
|   #define DETECT_REQ      0x73 | ||||
|   #define DETECT_RESP     0x46 | ||||
| 
 | ||||
|   #define RADIO_STATE_OFF 0x00 | ||||
|   #define RADIO_STATE_ON  0x01 | ||||
| 
 | ||||
|   #define NIBBLE_SEQ      0xF0 | ||||
|   #define NIBBLE_FLAGS    0x0F | ||||
|   #define FLAG_SPLIT      0x01 | ||||
|   #define SEQ_UNSET       0xFF | ||||
| 
 | ||||
|   #define CMD_ERROR           0x90 | ||||
|   #define ERROR_INITRADIO     0x01 | ||||
|   #define ERROR_TXFAILED      0x02 | ||||
|   #define ERROR_EEPROM_LOCKED 0x03 | ||||
|   #define ERROR_QUEUE_FULL    0x04 | ||||
|   #define ERROR_MEMORY_LOW    0x05 | ||||
|   #define ERROR_MODEM_TIMEOUT 0x06 | ||||
| #endif | ||||
							
								
								
									
										19
									
								
								src/libs/logging/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/libs/logging/LICENSE
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| Copyright (c) 2020 rxi | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||
| this software and associated documentation files (the "Software"), to deal in | ||||
| the Software without restriction, including without limitation the rights to | ||||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||||
| of the Software, and to permit persons to whom the Software is furnished to do | ||||
| so, subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
							
								
								
									
										1
									
								
								src/libs/logging/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/libs/logging/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| Sourced from [here](https://github.com/rxi/log.c). | ||||
							
								
								
									
										171
									
								
								src/libs/logging/log.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								src/libs/logging/log.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,171 @@ | ||||
| /*
 | ||||
|  * Copyright (c) 2020 rxi | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to | ||||
|  * deal in the Software without restriction, including without limitation the | ||||
|  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
|  * sell copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
|  * IN THE SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| #include "log.h" | ||||
| 
 | ||||
| #define MAX_CALLBACKS 32 | ||||
| 
 | ||||
| const char library[] = "librnode"; | ||||
| 
 | ||||
| typedef struct { | ||||
|   log_LogFn fn; | ||||
|   void *udata; | ||||
|   int level; | ||||
| } Callback; | ||||
| 
 | ||||
| static struct { | ||||
|   void *udata; | ||||
|   log_LockFn lock; | ||||
|   int level; | ||||
|   bool quiet; | ||||
|   Callback callbacks[MAX_CALLBACKS]; | ||||
| } L; | ||||
| 
 | ||||
| 
 | ||||
| static const char *level_strings[] = { | ||||
|   "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" | ||||
| }; | ||||
| 
 | ||||
| #ifdef LOG_USE_COLOR | ||||
| static const char *level_colors[] = { | ||||
|   "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m" | ||||
| }; | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| static void stdout_callback(log_Event *ev) { | ||||
|   char buf[16]; | ||||
|   buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0'; | ||||
| #ifdef LOG_USE_COLOR | ||||
|   fprintf( | ||||
|     ev->udata, "%s %s%-5s\x1b[0m \x1b[90m(%s) %s:%d:\x1b[0m ", | ||||
|     buf, level_colors[ev->level], level_strings[ev->level], | ||||
|     library, ev->file, ev->line); | ||||
| #else | ||||
|   fprintf( | ||||
|     ev->udata, "%s %-5s (%s) %s:%d: ", | ||||
|     buf, level_strings[ev->level], library, ev->file, ev->line); | ||||
| #endif | ||||
|   vfprintf(ev->udata, ev->fmt, ev->ap); | ||||
|   fprintf(ev->udata, "\n"); | ||||
|   fflush(ev->udata); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void file_callback(log_Event *ev) { | ||||
|   char buf[64]; | ||||
|   buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0'; | ||||
|   fprintf( | ||||
|     ev->udata, "%s %-5s (%s) %s:%d: ", | ||||
|     buf, level_strings[ev->level], library, ev->file, ev->line); | ||||
|   vfprintf(ev->udata, ev->fmt, ev->ap); | ||||
|   fprintf(ev->udata, "\n"); | ||||
|   fflush(ev->udata); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void lock(void)   { | ||||
|   if (L.lock) { L.lock(true, L.udata); } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void unlock(void) { | ||||
|   if (L.lock) { L.lock(false, L.udata); } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| const char* log_level_string(int level) { | ||||
|   return level_strings[level]; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void log_set_lock(log_LockFn fn, void *udata) { | ||||
|   L.lock = fn; | ||||
|   L.udata = udata; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void log_set_level(int level) { | ||||
|   L.level = level; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void log_set_quiet(bool enable) { | ||||
|   L.quiet = enable; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int log_add_callback(log_LogFn fn, void *udata, int level) { | ||||
|   for (int i = 0; i < MAX_CALLBACKS; i++) { | ||||
|     if (!L.callbacks[i].fn) { | ||||
|       L.callbacks[i] = (Callback) { fn, udata, level }; | ||||
|       return 0; | ||||
|     } | ||||
|   } | ||||
|   return -1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int log_add_fp(FILE *fp, int level) { | ||||
|   return log_add_callback(file_callback, fp, level); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void init_event(log_Event *ev, void *udata) { | ||||
|   if (!ev->time) { | ||||
|     time_t t = time(NULL); | ||||
|     ev->time = localtime(&t); | ||||
|   } | ||||
|   ev->udata = udata; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void log_log(int level, const char *file, int line, const char *fmt, ...) { | ||||
|   log_Event ev = { | ||||
|     .fmt   = fmt, | ||||
|     .file  = file, | ||||
|     .line  = line, | ||||
|     .level = level, | ||||
|   }; | ||||
| 
 | ||||
|   lock(); | ||||
| 
 | ||||
|   if (!L.quiet && level >= L.level) { | ||||
|     init_event(&ev, stderr); | ||||
|     va_start(ev.ap, fmt); | ||||
|     stdout_callback(&ev); | ||||
|     va_end(ev.ap); | ||||
|   } | ||||
| 
 | ||||
|   for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) { | ||||
|     Callback *cb = &L.callbacks[i]; | ||||
|     if (level >= cb->level) { | ||||
|       init_event(&ev, cb->udata); | ||||
|       va_start(ev.ap, fmt); | ||||
|       cb->fn(&ev); | ||||
|       va_end(ev.ap); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   unlock(); | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										49
									
								
								src/libs/logging/log.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/libs/logging/log.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | ||||
| /**
 | ||||
|  * Copyright (c) 2020 rxi | ||||
|  * | ||||
|  * This library is free software; you can redistribute it and/or modify it | ||||
|  * under the terms of the MIT license. See `log.c` for details. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef LOG_H | ||||
| #define LOG_H | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <stdarg.h> | ||||
| #include <stdbool.h> | ||||
| #include <time.h> | ||||
| 
 | ||||
| #define LOG_VERSION "0.1.0" | ||||
| 
 | ||||
| typedef struct { | ||||
|   va_list ap; | ||||
|   const char *fmt; | ||||
|   const char *file; | ||||
|   struct tm *time; | ||||
|   void *udata; | ||||
|   int line; | ||||
|   int level; | ||||
| } log_Event; | ||||
| 
 | ||||
| typedef void (*log_LogFn)(log_Event *ev); | ||||
| typedef void (*log_LockFn)(bool lock, void *udata); | ||||
| 
 | ||||
| enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL }; | ||||
| 
 | ||||
| #define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) | ||||
| #define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) | ||||
| #define log_info(...)  log_log(LOG_INFO,  __FILE__, __LINE__, __VA_ARGS__) | ||||
| #define log_warn(...)  log_log(LOG_WARN,  __FILE__, __LINE__, __VA_ARGS__) | ||||
| #define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) | ||||
| #define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) | ||||
| 
 | ||||
| const char* log_level_string(int level); | ||||
| void log_set_lock(log_LockFn fn, void *udata); | ||||
| void log_set_level(int level); | ||||
| void log_set_quiet(bool enable); | ||||
| int log_add_callback(log_LogFn fn, void *udata, int level); | ||||
| int log_add_fp(FILE *fp, int level); | ||||
| 
 | ||||
| void log_log(int level, const char *file, int line, const char *fmt, ...); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										4926
									
								
								src/libs/miniz.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4926
									
								
								src/libs/miniz.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										26
									
								
								src/libs/serial.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/libs/serial.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| /* Copyright (c) 2025 - Jacob Eva (Liberated Embedded Systems)
 | ||||
|  * This program is free software: you can redistribute it and/or modify it | ||||
|  * under the terms of the GNU General Public License as published by the Free | ||||
|  * Software Foundation, either version 3 of the License, or (at your option) | ||||
|  * any later version. | ||||
|  * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
|  * more details. | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #ifndef SERIAL_H | ||||
| 
 | ||||
| #define SERIAL_H | ||||
| 
 | ||||
| int open_port(char* path, uint32_t baud); | ||||
| 
 | ||||
| int write_port(int fd, uint8_t* data, uint16_t data_len); | ||||
| 
 | ||||
| int read_port(int fd, uint8_t* rx_data, uint16_t size); | ||||
| 
 | ||||
| int close_port(int fd); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										96
									
								
								src/libs/serial_linux.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								src/libs/serial_linux.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,96 @@ | ||||
| /* Copyright (c) 2025 - Jacob Eva (Liberated Embedded Systems)
 | ||||
|  * This program is free software: you can redistribute it and/or modify it | ||||
|  * under the terms of the GNU General Public License as published by the Free | ||||
|  * Software Foundation, either version 3 of the License, or (at your option) | ||||
|  * any later version. | ||||
|  * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
|  * more details. | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <unistd.h> | ||||
| #include <fcntl.h> | ||||
| #include <termios.h> | ||||
| #include <stdint.h> | ||||
| #include "logging/log.h" | ||||
| 
 | ||||
| int open_port(char* path, uint32_t baud) { | ||||
|     struct termios options; | ||||
|     speed_t baud_s; | ||||
|      | ||||
|     // Currently RNodes only support a baud rate of 115200, add more support as needed in future.
 | ||||
|     switch (baud) { | ||||
|         case 115200: | ||||
|             baud_s = B115200; | ||||
|             break; | ||||
|         default: | ||||
|             baud_s = B115200; | ||||
|             break; | ||||
|     } | ||||
| 
 | ||||
|     int fd = open(path, O_RDWR | O_NOCTTY); | ||||
| 
 | ||||
|     tcgetattr(fd, &options); | ||||
| 
 | ||||
|     cfsetispeed(&options, baud_s); | ||||
|     cfsetospeed(&options, baud_s); | ||||
| 
 | ||||
|     // 8N1
 | ||||
|     options.c_cflag &= ~PARENB; | ||||
|     options.c_cflag &= ~CSTOPB; | ||||
|     options.c_cflag &= ~CSIZE; | ||||
|     options.c_cflag |= CS8; | ||||
|     // ignore DCD line
 | ||||
|     options.c_cflag |= (CLOCAL | CREAD); | ||||
|     // disable input mapping options
 | ||||
|     options.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IUCLC); | ||||
|     // select RAW input
 | ||||
|     options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); | ||||
|     // select RAW output
 | ||||
|     options.c_oflag &= ~OPOST; | ||||
|     // disable output mapping options
 | ||||
|     options.c_oflag &= ~(OLCUC | ONLCR | OCRNL | ONOCR | ONLRET); | ||||
|     // set read timeout
 | ||||
|     options.c_cc[VMIN] = 0; | ||||
|     options.c_cc[VTIME] = 5;  // 0.5 seconds
 | ||||
| 
 | ||||
|     if (tcsetattr(fd, TCSANOW, &options)) | ||||
|     { | ||||
|         log_error("Cannot set RNode port options!"); | ||||
|         return -1; | ||||
|     } else { | ||||
|         return fd; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| int write_port(int fd, uint8_t* data, uint16_t data_len) { | ||||
|     unsigned char data_str[1024] = ""; | ||||
|     for (int i = 0; i < data_len; i++) { | ||||
|         sprintf(data_str+(i*3), "%02x ", data[i]); | ||||
|     } | ||||
| 
 | ||||
|     log_trace("Writing [%s] to RNode serial port.", data_str); | ||||
| 
 | ||||
|     if (write(fd, data, data_len) != data_len) { | ||||
|         log_error("Could not write all data to the RNode port! Is the RNode still connected?"); | ||||
|         return -1; | ||||
|     } else { | ||||
|         return 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| int read_port(int fd, uint8_t* rx_data, uint16_t size) { | ||||
|     int ret = read(fd, rx_data, size); | ||||
|     if (ret == -1) { | ||||
|         log_error("Could not read from RNode port! Is the RNode still connected?"); | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| int close_port(int fd) { | ||||
|     return close(fd); | ||||
| } | ||||
							
								
								
									
										12
									
								
								src/libs/serial_win32.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/libs/serial_win32.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| /* Copyright (c) 2025 - Jacob Eva (Liberated Embedded Systems)
 | ||||
|  * This program is free software: you can redistribute it and/or modify it | ||||
|  * under the terms of the GNU General Public License as published by the Free | ||||
|  * Software Foundation, either version 3 of the License, or (at your option) | ||||
|  * any later version. | ||||
|  * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
|  * more details. | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
							
								
								
									
										175
									
								
								src/libs/slip_enc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								src/libs/slip_enc.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,175 @@ | ||||
| /**
 | ||||
| * Copyright (c) 2017, Nordic Semiconductor ASA | ||||
| * Modified by Jacob Eva (Liberated Embedded Systems) (c) 2025. | ||||
| * | ||||
| * All rights reserved. | ||||
| * | ||||
| * Redistribution and use in source and binary forms, with or without modification, | ||||
| * are permitted provided that the following conditions are met: | ||||
| * | ||||
| * 1. Redistributions of source code must retain the above copyright notice, this | ||||
| *    list of conditions and the following disclaimer. | ||||
| * | ||||
| * 2. Redistributions in binary form, except as embedded into a Nordic | ||||
| *    Semiconductor ASA integrated circuit in a product or a software update for | ||||
| *    such product, must reproduce the above copyright notice, this list of | ||||
| *    conditions and the following disclaimer in the documentation and/or other | ||||
| *    materials provided with the distribution. | ||||
| * | ||||
| * 3. Neither the name of Nordic Semiconductor ASA nor the names of its | ||||
| *    contributors may be used to endorse or promote products derived from this | ||||
| *    software without specific prior written permission. | ||||
| * | ||||
| * 4. This software, with or without modification, must only be used with a | ||||
| *    Nordic Semiconductor ASA integrated circuit. | ||||
| * | ||||
| * 5. Any software provided in binary form under this license must not be reverse | ||||
| *    engineered, decompiled, modified and/or disassembled. | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS | ||||
| * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
| * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE | ||||
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||||
| * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | ||||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| * | ||||
| * Modified by Jacob Eva (Liberated Embedded Systems) (c) 2025. | ||||
| * Changes licensed under the GPL. | ||||
| * This program is free software: you can redistribute it and/or modify it | ||||
| * under the terms of the GNU General Public License as published by the Free | ||||
| * Software Foundation, either version 3 of the License, or (at your option) | ||||
| * any later version. | ||||
| * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
| * more details. | ||||
| * You should have received a copy of the GNU General Public License along | ||||
| * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include "slip_enc.h" | ||||
| 
 | ||||
| #define	SLIP_ESC				0333 | ||||
| #define	SLIP_ESC_END			0334 | ||||
| #define	SLIP_ESC_ESC			0335 | ||||
| 
 | ||||
| // https://github.com/adafruit/Adafruit_nRF52_nrfutil/blob/master/nordicsemi/dfu/util.py#L82
 | ||||
| void slip_header(uint8_t seq, bool dip, bool rp, uint8_t pkt_type, uint32_t pkt_len, uint8_t* header) { | ||||
|     header[0] = seq | (((seq + 1) % 8) << 3) | (dip << 6) | (rp << 7); | ||||
|     header[1] = pkt_type | ((pkt_len & 0x000F) << 4); | ||||
|     header[2] = (pkt_len & 0x0FF0) >> 4; | ||||
|     header[3] = (~(header[0] + header[1] + header[2]) + 1) & 0xFF; | ||||
| } | ||||
| 
 | ||||
| void encode_slip(uint8_t *pDestData, uint32_t *pDestSize, const uint8_t *pSrcData, uint32_t nSrcSize, bool frame) | ||||
| { | ||||
| 	uint32_t n, nDestSize; | ||||
| 
 | ||||
| 	nDestSize = 0; | ||||
| 
 | ||||
|     if (frame) { | ||||
|         *pDestData++ = SLIP_END; | ||||
|         nDestSize++; | ||||
|     } | ||||
| 
 | ||||
| 	for (n = 0; n < nSrcSize; n++) | ||||
| 	{ | ||||
| 		uint8_t nSrcByte = *(pSrcData + n); | ||||
| 
 | ||||
| 		if (nSrcByte == SLIP_END) | ||||
| 		{ | ||||
| 			*pDestData++ = SLIP_ESC; | ||||
| 			*pDestData++ = SLIP_ESC_END; | ||||
| 			nDestSize += 2; | ||||
| 		} | ||||
| 		else if (nSrcByte == SLIP_ESC) | ||||
| 		{ | ||||
| 			*pDestData++ = SLIP_ESC; | ||||
| 			*pDestData++ = SLIP_ESC_ESC; | ||||
| 			nDestSize += 2; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			*pDestData++ = nSrcByte; | ||||
| 			nDestSize++; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|     if (frame) { | ||||
|         *pDestData = SLIP_END; | ||||
|         nDestSize++; | ||||
|     } | ||||
| 
 | ||||
| 	*pDestSize = nDestSize; | ||||
| } | ||||
| 
 | ||||
| int decode_slip(uint8_t *pDestData, uint32_t *pDestSize, const uint8_t *pSrcData, uint32_t nSrcSize) | ||||
| { | ||||
| 	int err_code = 1; | ||||
| 	uint32_t n, nDestSize = 0; | ||||
| 	bool is_escaped = false; | ||||
| 
 | ||||
| 	for (n = 0; n < nSrcSize; n++) | ||||
| 	{ | ||||
| 		uint8_t nSrcByte = *(pSrcData + n); | ||||
| 
 | ||||
| 		if (nSrcByte == SLIP_END) | ||||
| 		{ | ||||
| 			if (!is_escaped) | ||||
| 				err_code = 0;  // Done. OK
 | ||||
| 
 | ||||
| 			break; | ||||
| 		} | ||||
| 		else if (nSrcByte == SLIP_ESC) | ||||
| 		{ | ||||
| 			if (is_escaped) | ||||
| 			{ | ||||
| 				// should not get SLIP_ESC twice...
 | ||||
| 				err_code = 1; | ||||
| 				break; | ||||
| 			} | ||||
| 			else | ||||
| 				is_escaped = true; | ||||
| 		} | ||||
| 		else if (nSrcByte == SLIP_ESC_END) | ||||
| 		{ | ||||
| 			if (is_escaped) | ||||
| 			{ | ||||
| 				is_escaped = false; | ||||
| 
 | ||||
| 				*pDestData++ = SLIP_END; | ||||
| 			} | ||||
| 			else | ||||
| 				*pDestData++ = nSrcByte; | ||||
| 
 | ||||
| 			nDestSize++; | ||||
| 		} | ||||
| 		else if (nSrcByte == SLIP_ESC_ESC) | ||||
| 		{ | ||||
| 			if (is_escaped) | ||||
| 			{ | ||||
| 				is_escaped = false; | ||||
| 
 | ||||
| 				*pDestData++ = SLIP_ESC; | ||||
| 			} | ||||
| 			else | ||||
| 				*pDestData++ = nSrcByte; | ||||
| 
 | ||||
| 			nDestSize++; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			*pDestData++ = nSrcByte; | ||||
| 			nDestSize++; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	*pDestSize = nDestSize; | ||||
| 
 | ||||
| 	return err_code; | ||||
| } | ||||
							
								
								
									
										81
									
								
								src/libs/slip_enc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/libs/slip_enc.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,81 @@ | ||||
| /**
 | ||||
| * Copyright (c) 2017, Nordic Semiconductor ASA | ||||
| * | ||||
| * All rights reserved. | ||||
| * | ||||
| * Redistribution and use in source and binary forms, with or without modification, | ||||
| * are permitted provided that the following conditions are met: | ||||
| * | ||||
| * 1. Redistributions of source code must retain the above copyright notice, this | ||||
| *    list of conditions and the following disclaimer. | ||||
| * | ||||
| * 2. Redistributions in binary form, except as embedded into a Nordic | ||||
| *    Semiconductor ASA integrated circuit in a product or a software update for | ||||
| *    such product, must reproduce the above copyright notice, this list of | ||||
| *    conditions and the following disclaimer in the documentation and/or other | ||||
| *    materials provided with the distribution. | ||||
| * | ||||
| * 3. Neither the name of Nordic Semiconductor ASA nor the names of its | ||||
| *    contributors may be used to endorse or promote products derived from this | ||||
| *    software without specific prior written permission. | ||||
| * | ||||
| * 4. This software, with or without modification, must only be used with a | ||||
| *    Nordic Semiconductor ASA integrated circuit. | ||||
| * | ||||
| * 5. Any software provided in binary form under this license must not be reverse | ||||
| *    engineered, decompiled, modified and/or disassembled. | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS | ||||
| * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
| * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE | ||||
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||||
| * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | ||||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| * | ||||
| * Modified by Jacob Eva (Liberated Embedded Systems) (c) 2025. | ||||
| * Changes licensed under the GPL. | ||||
| * This program is free software: you can redistribute it and/or modify it | ||||
| * under the terms of the GNU General Public License as published by the Free | ||||
| * Software Foundation, either version 3 of the License, or (at your option) | ||||
| * any later version. | ||||
| * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
| * more details. | ||||
| * You should have received a copy of the GNU General Public License along | ||||
| * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| 
 | ||||
| #pragma once | ||||
|   | ||||
| #ifndef _INC_SLIP_ENC | ||||
| #define _INC_SLIP_ENC | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #define	SLIP_END				0300 | ||||
| #define SLIP_HEADER_LEN         4 | ||||
| #define SLIP_GROW_FACTOR        2 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif  /* __cplusplus */ | ||||
| 
 | ||||
| void slip_header(uint8_t seq, bool dip, bool rp, uint8_t pkt_type, uint32_t pkt_len, uint8_t* header); | ||||
| 
 | ||||
| void encode_slip(uint8_t *pDestData, uint32_t *pDestSize, const uint8_t *pSrcData, uint32_t nSrcSize, bool frame); | ||||
| 
 | ||||
| int  decode_slip(uint8_t *pDestData, uint32_t *pDestSize, const uint8_t *pSrcData, uint32_t nSrcSize); | ||||
| 
 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| }   /* ... extern "C" */ | ||||
| #endif  /* __cplusplus */ | ||||
| 
 | ||||
| 
 | ||||
| #endif // _INC_SLIP_ENC
 | ||||
							
								
								
									
										29
									
								
								src/libs/util.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/libs/util.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| /* Copyright (c) 2025 - Jacob Eva (Liberated Embedded Systems)
 | ||||
|  * This program is free software: you can redistribute it and/or modify it | ||||
|  * under the terms of the GNU General Public License as published by the Free | ||||
|  * Software Foundation, either version 3 of the License, or (at your option) | ||||
|  * any later version. | ||||
|  * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
|  * more details. | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include "util.h" | ||||
| 
 | ||||
| int sleep_ms(int ms) | ||||
| { | ||||
|     #ifdef WIN32 | ||||
|         Sleep(ms); | ||||
|         return 0; | ||||
|     #elif _POSIX_C_SOURCE >= 199309L | ||||
|         struct timespec ts; | ||||
|         ts.tv_sec = ms / 1000; | ||||
|         ts.tv_nsec = (ms % 1000) * 1000000; | ||||
|         return nanosleep(&ts, NULL); | ||||
|     #else | ||||
|         return usleep(ms * 1000); | ||||
|     #endif | ||||
| } | ||||
							
								
								
									
										22
									
								
								src/libs/util.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/libs/util.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| /* Copyright (c) 2025 - Jacob Eva (Liberated Embedded Systems)
 | ||||
|  * This program is free software: you can redistribute it and/or modify it | ||||
|  * under the terms of the GNU General Public License as published by the Free | ||||
|  * Software Foundation, either version 3 of the License, or (at your option) | ||||
|  * any later version. | ||||
|  * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||||
|  * more details. | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __UTIL_H | ||||
| #define __UTIL_H | ||||
| 
 | ||||
| #include <unistd.h> | ||||
| #include <time.h> | ||||
| 
 | ||||
| int sleep_ms(int ms); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										786
									
								
								src/libs/zip.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										786
									
								
								src/libs/zip.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,786 @@ | ||||
| /*
 | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||
|  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||
|  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||||
|  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||||
|  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||||
|  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||||
|  * OTHER DEALINGS IN THE SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| #include "zip.h" | ||||
| #include "miniz.h" | ||||
| 
 | ||||
| #include <errno.h> | ||||
| #include <sys/stat.h> | ||||
| #include <time.h> | ||||
| 
 | ||||
| #if defined _WIN32 || defined __WIN32__ | ||||
| /* Win32, DOS */ | ||||
| #include <direct.h> | ||||
| 
 | ||||
| #define MKDIR(DIRNAME) _mkdir(DIRNAME) | ||||
| #define STRCLONE(STR) ((STR) ? _strdup(STR) : NULL) | ||||
| #define HAS_DEVICE(P)                                                          \ | ||||
|     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) && \ | ||||
|      (P)[1] == ':') | ||||
| #define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE(P) ? 2 : 0) | ||||
| #define ISSLASH(C) ((C) == '/' || (C) == '\\') | ||||
| 
 | ||||
| #else | ||||
| #define MKDIR(DIRNAME) mkdir(DIRNAME, 0755) | ||||
| #define STRCLONE(STR) ((STR) ? strdup(STR) : NULL) | ||||
| #endif | ||||
| 
 | ||||
| #ifndef FILESYSTEM_PREFIX_LEN | ||||
| #define FILESYSTEM_PREFIX_LEN(P) 0 | ||||
| #endif | ||||
| 
 | ||||
| #ifndef ISSLASH | ||||
| #define ISSLASH(C) ((C) == '/') | ||||
| #endif | ||||
| 
 | ||||
| #define CLEANUP(ptr)           \ | ||||
|     do {                       \ | ||||
|         if (ptr) {             \ | ||||
|             free((void *)ptr); \ | ||||
|             ptr = NULL;        \ | ||||
|         }                      \ | ||||
|     } while (0) | ||||
| 
 | ||||
| static char *basename(const char *name) { | ||||
|     char const *p; | ||||
|     char const *base = name += FILESYSTEM_PREFIX_LEN(name); | ||||
|     int all_slashes = 1; | ||||
| 
 | ||||
|     for (p = name; *p; p++) { | ||||
|         if (ISSLASH(*p)) | ||||
|             base = p + 1; | ||||
|         else | ||||
|             all_slashes = 0; | ||||
|     } | ||||
| 
 | ||||
|     /* If NAME is all slashes, arrange to return `/'. */ | ||||
|     if (*base == '\0' && ISSLASH(*name) && all_slashes) --base; | ||||
| 
 | ||||
|     return (char *)base; | ||||
| } | ||||
| 
 | ||||
| static int mkpath(const char *path) { | ||||
|     char const *p; | ||||
|     char npath[MAX_PATH + 1] = {0}; | ||||
|     int len = 0; | ||||
| 
 | ||||
|     for (p = path; *p && len < MAX_PATH; p++) { | ||||
|         if (ISSLASH(*p) && len > 0) { | ||||
|             if (MKDIR(npath) == -1) | ||||
|                 if (errno != EEXIST) return -1; | ||||
|         } | ||||
|         npath[len++] = *p; | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static char *strrpl(const char *str, size_t n, char oldchar, char newchar) { | ||||
|     char c; | ||||
|     size_t i; | ||||
|     char *rpl = (char *)calloc((1 + n), sizeof(char)); | ||||
|     char *begin = rpl; | ||||
|     if (!rpl) { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     for(i = 0; (i < n) && (c = *str++); ++i) { | ||||
|         if (c == oldchar) { | ||||
|             c = newchar; | ||||
|         } | ||||
|         *rpl++ = c; | ||||
|     } | ||||
| 
 | ||||
|     return begin; | ||||
| } | ||||
| 
 | ||||
| struct zip_entry_t { | ||||
|     int index; | ||||
|     const char *name; | ||||
|     mz_uint64 uncomp_size; | ||||
|     mz_uint64 comp_size; | ||||
|     mz_uint32 uncomp_crc32; | ||||
|     mz_uint64 offset; | ||||
|     mz_uint8 header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; | ||||
|     mz_uint64 header_offset; | ||||
|     mz_uint16 method; | ||||
|     mz_zip_writer_add_state state; | ||||
|     tdefl_compressor comp; | ||||
| }; | ||||
| 
 | ||||
| struct zip_t { | ||||
|     mz_zip_archive archive; | ||||
|     mz_uint level; | ||||
|     struct zip_entry_t entry; | ||||
| }; | ||||
| 
 | ||||
| struct zip_t *zip_open(const char *zipname, int level, char mode) { | ||||
|     struct zip_t *zip = NULL; | ||||
| 
 | ||||
|     if (!zipname || strlen(zipname) < 1) { | ||||
|         // zip_t archive name is empty or NULL
 | ||||
|         goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     if (level < 0) level = MZ_DEFAULT_LEVEL; | ||||
|     if ((level & 0xF) > MZ_UBER_COMPRESSION) { | ||||
|         // Wrong compression level
 | ||||
|         goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t)); | ||||
|     if (!zip) goto cleanup; | ||||
| 
 | ||||
|     zip->level = level; | ||||
|     switch (mode) { | ||||
|         case 'w': | ||||
|             // Create a new archive.
 | ||||
|             if (!mz_zip_writer_init_file(&(zip->archive), zipname, 0)) { | ||||
|                 // Cannot initialize zip_archive writer
 | ||||
|                 goto cleanup; | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|         case 'r': | ||||
|         case 'a': | ||||
|             if (!mz_zip_reader_init_file( | ||||
|                     &(zip->archive), zipname, | ||||
|                     level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) { | ||||
|                 // An archive file does not exist or cannot initialize
 | ||||
|                 // zip_archive reader
 | ||||
|                 goto cleanup; | ||||
|             } | ||||
|             if (mode == 'a' && | ||||
|                 !mz_zip_writer_init_from_reader(&(zip->archive), zipname)) { | ||||
|                 mz_zip_reader_end(&(zip->archive)); | ||||
|                 goto cleanup; | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|         default: | ||||
|             goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     return zip; | ||||
| 
 | ||||
| cleanup: | ||||
|     CLEANUP(zip); | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| void zip_close(struct zip_t *zip) { | ||||
|     if (zip) { | ||||
|         // Always finalize, even if adding failed for some reason, so we have a
 | ||||
|         // valid central directory.
 | ||||
|         mz_zip_writer_finalize_archive(&(zip->archive)); | ||||
| 
 | ||||
|         mz_zip_writer_end(&(zip->archive)); | ||||
|         mz_zip_reader_end(&(zip->archive)); | ||||
| 
 | ||||
|         CLEANUP(zip); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| int zip_entry_open(struct zip_t *zip, const char *entryname) { | ||||
|     size_t entrylen = 0; | ||||
|     mz_zip_archive *pzip = NULL; | ||||
|     mz_uint num_alignment_padding_bytes, level; | ||||
|     mz_zip_archive_file_stat stats; | ||||
| 
 | ||||
|     if (!zip || !entryname) { | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     entrylen = strlen(entryname); | ||||
|     if (entrylen < 1) { | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|       .ZIP File Format Specification Version: 6.3.3 | ||||
| 
 | ||||
|       4.4.17.1 The name of the file, with optional relative path. | ||||
|       The path stored MUST not contain a drive or | ||||
|       device letter, or a leading slash.  All slashes | ||||
|       MUST be forward slashes '/' as opposed to | ||||
|       backwards slashes '\' for compatibility with Amiga | ||||
|       and UNIX file systems etc.  If input came from standard | ||||
|       input, there is no file name field. | ||||
|     */ | ||||
|     zip->entry.name = strrpl(entryname, entrylen, '\\', '/'); | ||||
|     if (!zip->entry.name) { | ||||
|         // Cannot parse zip entry name
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     pzip = &(zip->archive); | ||||
|     if (pzip->m_zip_mode == MZ_ZIP_MODE_READING) { | ||||
|         zip->entry.index = mz_zip_reader_locate_file(pzip, zip->entry.name, NULL, 0); | ||||
|         if (zip->entry.index < 0) { | ||||
|             goto cleanup; | ||||
|         } | ||||
| 
 | ||||
|         if (!mz_zip_reader_file_stat(pzip, zip->entry.index, &stats)) { | ||||
|             goto cleanup; | ||||
|         } | ||||
| 
 | ||||
|         zip->entry.comp_size = stats.m_comp_size; | ||||
|         zip->entry.uncomp_size = stats.m_uncomp_size; | ||||
|         zip->entry.uncomp_crc32 = stats.m_crc32; | ||||
|         zip->entry.offset = stats.m_central_dir_ofs; | ||||
|         zip->entry.header_offset = stats.m_local_header_ofs; | ||||
|         zip->entry.method = stats.m_method; | ||||
| 
 | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     zip->entry.index = zip->archive.m_total_files; | ||||
|     zip->entry.comp_size = 0; | ||||
|     zip->entry.uncomp_size = 0; | ||||
|     zip->entry.uncomp_crc32 = MZ_CRC32_INIT; | ||||
|     zip->entry.offset = zip->archive.m_archive_size; | ||||
|     zip->entry.header_offset = zip->archive.m_archive_size; | ||||
|     memset(zip->entry.header, 0, | ||||
|            MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8)); | ||||
|     zip->entry.method = 0; | ||||
| 
 | ||||
|     num_alignment_padding_bytes = | ||||
|         mz_zip_writer_compute_padding_needed_for_file_alignment(pzip); | ||||
| 
 | ||||
|     if (!pzip->m_pState || (pzip->m_zip_mode != MZ_ZIP_MODE_WRITING)) { | ||||
|         // Wrong zip mode
 | ||||
|         goto cleanup; | ||||
|     } | ||||
|     if (zip->level & MZ_ZIP_FLAG_COMPRESSED_DATA) { | ||||
|         // Wrong zip compression level
 | ||||
|         goto cleanup; | ||||
|     } | ||||
|     // no zip64 support yet
 | ||||
|     if ((pzip->m_total_files == 0xFFFF) || | ||||
|         ((pzip->m_archive_size + num_alignment_padding_bytes + | ||||
|           MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + | ||||
|           entrylen) > 0xFFFFFFFF)) { | ||||
|         // No zip64 support yet
 | ||||
|         goto cleanup; | ||||
|     } | ||||
|     if (!mz_zip_writer_write_zeros( | ||||
|             pzip, zip->entry.offset, | ||||
|             num_alignment_padding_bytes + sizeof(zip->entry.header))) { | ||||
|         // Cannot memset zip entry header
 | ||||
|         goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     zip->entry.header_offset += num_alignment_padding_bytes; | ||||
|     if (pzip->m_file_offset_alignment) { | ||||
|         MZ_ASSERT((zip->entry.header_offset & | ||||
|                    (pzip->m_file_offset_alignment - 1)) == 0); | ||||
|     } | ||||
|     zip->entry.offset += | ||||
|         num_alignment_padding_bytes + sizeof(zip->entry.header); | ||||
| 
 | ||||
|     if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.offset, zip->entry.name, | ||||
|                        entrylen) != entrylen) { | ||||
|         // Cannot write data to zip entry
 | ||||
|         goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     zip->entry.offset += entrylen; | ||||
|     level = zip->level & 0xF; | ||||
|     if (level) { | ||||
|         zip->entry.state.m_pZip = pzip; | ||||
|         zip->entry.state.m_cur_archive_file_ofs = zip->entry.offset; | ||||
|         zip->entry.state.m_comp_size = 0; | ||||
| 
 | ||||
|         if (tdefl_init(&(zip->entry.comp), mz_zip_writer_add_put_buf_callback, | ||||
|                        &(zip->entry.state), | ||||
|                        tdefl_create_comp_flags_from_zip_params( | ||||
|                            level, -15, MZ_DEFAULT_STRATEGY)) != | ||||
|             TDEFL_STATUS_OKAY) { | ||||
|             // Cannot initialize the zip compressor
 | ||||
|             goto cleanup; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| 
 | ||||
|     cleanup: | ||||
|         CLEANUP(zip->entry.name); | ||||
|         return -1; | ||||
| } | ||||
| 
 | ||||
| int zip_entry_openbyindex(struct zip_t *zip, int index) { | ||||
|     mz_zip_archive *pZip = NULL; | ||||
|     mz_zip_archive_file_stat stats; | ||||
|     if (!zip) { | ||||
|         // zip_t handler is not initialized
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     pZip = &(zip->archive); | ||||
|     if (pZip->m_zip_mode != MZ_ZIP_MODE_READING) { | ||||
|         // open by index requires readonly mode
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     if (index < 0 || (mz_uint)index >= pZip->m_total_files) { | ||||
|         // index out of range
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, index)); | ||||
|     if (!pHeader) { | ||||
|         // cannot find header in central directory
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     mz_uint namelen = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); | ||||
|     const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; | ||||
| 
 | ||||
|     /*
 | ||||
|       .ZIP File Format Specification Version: 6.3.3 | ||||
| 
 | ||||
|       4.4.17.1 The name of the file, with optional relative path. | ||||
|       The path stored MUST not contain a drive or | ||||
|       device letter, or a leading slash.  All slashes | ||||
|       MUST be forward slashes '/' as opposed to | ||||
|       backwards slashes '\' for compatibility with Amiga | ||||
|       and UNIX file systems etc.  If input came from standard | ||||
|       input, there is no file name field. | ||||
|     */ | ||||
|     zip->entry.name = strrpl(pFilename, namelen, '\\', '/'); | ||||
|     if (!zip->entry.name) { | ||||
|         // local entry name is NULL
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     if (!mz_zip_reader_file_stat(pZip, index, &stats)) { | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     zip->entry.index = index; | ||||
|     zip->entry.comp_size = stats.m_comp_size; | ||||
|     zip->entry.uncomp_size = stats.m_uncomp_size; | ||||
|     zip->entry.uncomp_crc32 = stats.m_crc32; | ||||
|     zip->entry.offset = stats.m_central_dir_ofs; | ||||
|     zip->entry.header_offset = stats.m_local_header_ofs; | ||||
|     zip->entry.method = stats.m_method; | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int zip_entry_close(struct zip_t *zip) { | ||||
|     mz_zip_archive *pzip = NULL; | ||||
|     mz_uint level; | ||||
|     tdefl_status done; | ||||
|     mz_uint16 entrylen; | ||||
|     time_t t; | ||||
|     struct tm *tm; | ||||
|     mz_uint16 dos_time, dos_date; | ||||
|     int status = -1; | ||||
| 
 | ||||
|     if (!zip) { | ||||
|         // zip_t handler is not initialized
 | ||||
|         goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     pzip = &(zip->archive); | ||||
|     if (pzip->m_zip_mode == MZ_ZIP_MODE_READING) { | ||||
|         status = 0; | ||||
|         goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     level = zip->level & 0xF; | ||||
|     if (level) { | ||||
|         done = tdefl_compress_buffer(&(zip->entry.comp), "", 0, TDEFL_FINISH); | ||||
|         if (done != TDEFL_STATUS_DONE && done != TDEFL_STATUS_OKAY) { | ||||
|             // Cannot flush compressed buffer
 | ||||
|             goto cleanup; | ||||
|         } | ||||
|         zip->entry.comp_size = zip->entry.state.m_comp_size; | ||||
|         zip->entry.offset = zip->entry.state.m_cur_archive_file_ofs; | ||||
|         zip->entry.method = MZ_DEFLATED; | ||||
|     } | ||||
| 
 | ||||
|     entrylen = (mz_uint16)strlen(zip->entry.name); | ||||
|     t = time(NULL); | ||||
|     tm = localtime(&t); | ||||
|     dos_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + | ||||
|                            ((tm->tm_sec) >> 1)); | ||||
|     dos_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + | ||||
|                            ((tm->tm_mon + 1) << 5) + tm->tm_mday); | ||||
| 
 | ||||
|     // no zip64 support yet
 | ||||
|     if ((zip->entry.comp_size > 0xFFFFFFFF) || | ||||
|         (zip->entry.offset > 0xFFFFFFFF)) { | ||||
|         // No zip64 support, yet
 | ||||
|         goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     if (!mz_zip_writer_create_local_dir_header( | ||||
|             pzip, zip->entry.header, entrylen, 0, zip->entry.uncomp_size, | ||||
|             zip->entry.comp_size, zip->entry.uncomp_crc32, zip->entry.method, 0, | ||||
|             dos_time, dos_date)) { | ||||
|         // Cannot create zip entry header
 | ||||
|         goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.header_offset, | ||||
|                        zip->entry.header, sizeof(zip->entry.header)) != | ||||
|         sizeof(zip->entry.header)) { | ||||
|         // Cannot write zip entry header
 | ||||
|         goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     if (!mz_zip_writer_add_to_central_dir( | ||||
|             pzip, zip->entry.name, entrylen, NULL, 0, "", 0, | ||||
|             zip->entry.uncomp_size, zip->entry.comp_size, | ||||
|             zip->entry.uncomp_crc32, zip->entry.method, 0, dos_time, dos_date, | ||||
|             zip->entry.header_offset, 0)) { | ||||
|         // Cannot write to zip central dir
 | ||||
|         goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     pzip->m_total_files++; | ||||
|     pzip->m_archive_size = zip->entry.offset; | ||||
|     status = 0; | ||||
| 
 | ||||
| cleanup: | ||||
|     CLEANUP(zip->entry.name); | ||||
|     return status; | ||||
| } | ||||
| 
 | ||||
| const char *zip_entry_name(struct zip_t *zip) { | ||||
|     if (!zip) { | ||||
|         // zip_t handler is not initialized
 | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     return zip->entry.name; | ||||
| } | ||||
| 
 | ||||
| int zip_entry_index(struct zip_t *zip) { | ||||
|     if (!zip) { | ||||
|         // zip_t handler is not initialized
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     return zip->entry.index; | ||||
| } | ||||
| 
 | ||||
| int zip_entry_isdir(struct zip_t *zip) { | ||||
|     if (!zip) { | ||||
|         // zip_t handler is not initialized
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     if (zip->entry.index < 0) { | ||||
|         // zip entry is not opened
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     return (int)mz_zip_reader_is_file_a_directory(&zip->archive, (mz_uint)zip->entry.index); | ||||
| } | ||||
| 
 | ||||
| unsigned long long zip_entry_size(struct zip_t *zip) { | ||||
|     return zip->entry.uncomp_size; | ||||
| } | ||||
| 
 | ||||
| unsigned int zip_entry_crc32(struct zip_t *zip) { | ||||
|     return zip->entry.uncomp_crc32;     | ||||
| } | ||||
| 
 | ||||
| int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) { | ||||
|     mz_uint level; | ||||
|     mz_zip_archive *pzip = NULL; | ||||
|     tdefl_status status; | ||||
| 
 | ||||
|     if (!zip) { | ||||
|         // zip_t handler is not initialized
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     pzip = &(zip->archive); | ||||
|     if (buf && bufsize > 0) { | ||||
|         zip->entry.uncomp_size += bufsize; | ||||
|         zip->entry.uncomp_crc32 = (mz_uint32)mz_crc32( | ||||
|             zip->entry.uncomp_crc32, (const mz_uint8 *)buf, bufsize); | ||||
| 
 | ||||
|         level = zip->level & 0xF; | ||||
|         if (!level) { | ||||
|             if ((pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.offset, buf, | ||||
|                                 bufsize) != bufsize)) { | ||||
|                 // Cannot write buffer
 | ||||
|                 return -1; | ||||
|             } | ||||
|             zip->entry.offset += bufsize; | ||||
|             zip->entry.comp_size += bufsize; | ||||
|         } else { | ||||
|             status = tdefl_compress_buffer(&(zip->entry.comp), buf, bufsize, | ||||
|                                            TDEFL_NO_FLUSH); | ||||
|             if (status != TDEFL_STATUS_DONE && status != TDEFL_STATUS_OKAY) { | ||||
|                 // Cannot compress buffer
 | ||||
|                 return -1; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int zip_entry_fwrite(struct zip_t *zip, const char *filename) { | ||||
|     int status = 0; | ||||
|     size_t n = 0; | ||||
|     FILE *stream = NULL; | ||||
|     mz_uint8 buf[MZ_ZIP_MAX_IO_BUF_SIZE] = {0}; | ||||
| 
 | ||||
|     if (!zip) { | ||||
|         // zip_t handler is not initialized
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     stream = fopen(filename, "rb"); | ||||
|     if (!stream) { | ||||
|         // Cannot open filename
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     while ((n = fread(buf, sizeof(mz_uint8), MZ_ZIP_MAX_IO_BUF_SIZE, stream)) > | ||||
|            0) { | ||||
|         if (zip_entry_write(zip, buf, n) < 0) { | ||||
|             status = -1; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     fclose(stream); | ||||
| 
 | ||||
|     return status; | ||||
| } | ||||
| 
 | ||||
| int zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize) { | ||||
|     mz_zip_archive *pzip = NULL; | ||||
|     mz_uint idx; | ||||
| 
 | ||||
|     if (!zip) { | ||||
|         // zip_t handler is not initialized
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     pzip = &(zip->archive); | ||||
|     if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) { | ||||
|         // the entry is not found or we do not have read access
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     idx = (mz_uint)zip->entry.index; | ||||
|     if (mz_zip_reader_is_file_a_directory(pzip, idx)) { | ||||
|         // the entry is a directory
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     *buf = mz_zip_reader_extract_to_heap(pzip, idx, bufsize, 0); | ||||
|     return (*buf) ? 0 : -1; | ||||
| } | ||||
| 
 | ||||
| int zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) { | ||||
|     mz_zip_archive *pzip = NULL; | ||||
|     mz_uint idx; | ||||
| 
 | ||||
|     if (!zip) { | ||||
|         // zip_t handler is not initialized
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     pzip = &(zip->archive); | ||||
|     if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) { | ||||
|         // the entry is not found or we do not have read access
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     idx = (mz_uint)zip->entry.index; | ||||
|     if (!mz_zip_reader_extract_to_mem_no_alloc(pzip, idx, buf, bufsize, 0, NULL, 0)) { | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int zip_entry_fread(struct zip_t *zip, const char *filename) { | ||||
|     mz_zip_archive *pzip = NULL; | ||||
|     mz_uint idx; | ||||
| 
 | ||||
|     if (!zip) { | ||||
|         // zip_t handler is not initialized
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     pzip = &(zip->archive); | ||||
|     if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) { | ||||
|         // the entry is not found or we do not have read access
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     idx = (mz_uint)zip->entry.index; | ||||
|     if (mz_zip_reader_is_file_a_directory(pzip, idx)) { | ||||
|         // the entry is a directory
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     return (mz_zip_reader_extract_to_file(pzip, idx, filename, 0)) ? 0 : -1; | ||||
| } | ||||
| 
 | ||||
| int zip_entry_extract(struct zip_t *zip, | ||||
|                       size_t (*on_extract)(void *arg, unsigned long long offset, | ||||
|                                            const void *buf, size_t bufsize), | ||||
|                       void *arg) { | ||||
|     mz_zip_archive *pzip = NULL; | ||||
|     mz_uint idx; | ||||
| 
 | ||||
|     if (!zip) { | ||||
|         // zip_t handler is not initialized
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     pzip = &(zip->archive); | ||||
|     if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) { | ||||
|         // the entry is not found or we do not have read access
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     idx = (mz_uint)zip->entry.index; | ||||
|     return (mz_zip_reader_extract_to_callback(pzip, idx, on_extract, arg, 0)) ? 0 : -1; | ||||
| } | ||||
| 
 | ||||
| int zip_total_entries(struct zip_t *zip) { | ||||
|     if (!zip) { | ||||
|         // zip_t handler is not initialized
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     return zip->archive.m_total_files; | ||||
| } | ||||
| 
 | ||||
| int zip_create(const char *zipname, const char *filenames[], size_t len) { | ||||
|     int status = 0; | ||||
|     size_t i; | ||||
|     mz_zip_archive zip_archive; | ||||
| 
 | ||||
|     if (!zipname || strlen(zipname) < 1) { | ||||
|         // zip_t archive name is empty or NULL
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     // Create a new archive.
 | ||||
|     if (!memset(&(zip_archive), 0, sizeof(zip_archive))) { | ||||
|         // Cannot memset zip archive
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     if (!mz_zip_writer_init_file(&zip_archive, zipname, 0)) { | ||||
|         // Cannot initialize zip_archive writer
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     for (i = 0; i < len; ++i) { | ||||
|         const char *name = filenames[i]; | ||||
|         if (!name) { | ||||
|             status = -1; | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         if (!mz_zip_writer_add_file(&zip_archive, basename(name), name, "", 0, | ||||
|                                     ZIP_DEFAULT_COMPRESSION_LEVEL)) { | ||||
|             // Cannot add file to zip_archive
 | ||||
|             status = -1; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     mz_zip_writer_finalize_archive(&zip_archive); | ||||
|     mz_zip_writer_end(&zip_archive); | ||||
|     return status; | ||||
| } | ||||
| 
 | ||||
| int zip_extract(const char *zipname, const char *dir, | ||||
|                 int (*on_extract)(const char *filename, void *arg), void *arg) { | ||||
|     int status = -1; | ||||
|     mz_uint i, n; | ||||
|     char path[MAX_PATH + 1] = {0}; | ||||
|     mz_zip_archive zip_archive; | ||||
|     mz_zip_archive_file_stat info; | ||||
|     size_t dirlen = 0; | ||||
| 
 | ||||
|     if (!memset(&(zip_archive), 0, sizeof(zip_archive))) { | ||||
|         // Cannot memset zip archive
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     if (!zipname || !dir) { | ||||
|         // Cannot parse zip archive name
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     dirlen = strlen(dir); | ||||
|     if (dirlen + 1 > MAX_PATH) { | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     // Now try to open the archive.
 | ||||
|     if (!mz_zip_reader_init_file(&zip_archive, zipname, 0)) { | ||||
|         // Cannot initialize zip_archive reader
 | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     strcpy(path, dir); | ||||
|     if (!ISSLASH(path[dirlen - 1])) { | ||||
| #if defined _WIN32 || defined __WIN32__ | ||||
|         path[dirlen] = '\\'; | ||||
| #else | ||||
|         path[dirlen] = '/'; | ||||
| #endif | ||||
|         ++dirlen; | ||||
|     } | ||||
| 
 | ||||
|     // Get and print information about each file in the archive.
 | ||||
|     n = mz_zip_reader_get_num_files(&zip_archive); | ||||
|     for (i = 0; i < n; ++i) { | ||||
|         if (!mz_zip_reader_file_stat(&zip_archive, i, &info)) { | ||||
|             // Cannot get information about zip archive;
 | ||||
|             goto out; | ||||
|         } | ||||
|         strncpy(&path[dirlen], info.m_filename, MAX_PATH - dirlen); | ||||
|         if (mkpath(path) < 0) { | ||||
|             // Cannot make a path
 | ||||
|             goto out; | ||||
|         } | ||||
| 
 | ||||
|         if (!mz_zip_reader_is_file_a_directory(&zip_archive, i)) { | ||||
|             if (!mz_zip_reader_extract_to_file(&zip_archive, i, path, 0)) { | ||||
|                 // Cannot extract zip archive to file
 | ||||
|                 goto out; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (on_extract) { | ||||
|             if (on_extract(path, arg) < 0) { | ||||
|                 goto out; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     status = 0; | ||||
| 
 | ||||
| out: | ||||
|     // Close the archive, freeing any resources it was using
 | ||||
|     if (!mz_zip_reader_end(&zip_archive)) { | ||||
|         // Cannot end zip reader
 | ||||
|         status = -1; | ||||
|     } | ||||
| 
 | ||||
|     return status; | ||||
| } | ||||
							
								
								
									
										302
									
								
								src/libs/zip.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										302
									
								
								src/libs/zip.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,302 @@ | ||||
| /*
 | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||
|  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||
|  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||||
|  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||||
|  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||||
|  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||||
|  * OTHER DEALINGS IN THE SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| #ifndef ZIP_H | ||||
| #define ZIP_H | ||||
| 
 | ||||
| #include <string.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| #ifndef MAX_PATH | ||||
| #define MAX_PATH 32767 /* # chars in a path name including NULL */ | ||||
| #endif | ||||
| 
 | ||||
| #define ZIP_DEFAULT_COMPRESSION_LEVEL 6 | ||||
| 
 | ||||
| /*
 | ||||
|   This data structure is used throughout the library to represent zip archive | ||||
|   - forward declaration. | ||||
| */ | ||||
| struct zip_t; | ||||
| 
 | ||||
| /*
 | ||||
|   Opens zip archive with compression level using the given mode. | ||||
| 
 | ||||
|   Args: | ||||
|     zipname: zip archive file name. | ||||
|     level: compression level (0-9 are the standard zlib-style levels). | ||||
|     mode: file access mode. | ||||
|         'r': opens a file for reading/extracting (the file must exists). | ||||
|         'w': creates an empty file for writing. | ||||
|         'a': appends to an existing archive. | ||||
| 
 | ||||
|   Returns: | ||||
|     The zip archive handler or NULL on error | ||||
| */ | ||||
| extern struct zip_t *zip_open(const char *zipname, int level, char mode); | ||||
| 
 | ||||
| /*
 | ||||
|   Closes the zip archive, releases resources - always finalize. | ||||
| 
 | ||||
|   Args: | ||||
|     zip: zip archive handler. | ||||
| */ | ||||
| extern void zip_close(struct zip_t *zip); | ||||
| 
 | ||||
| /*
 | ||||
|   Opens an entry by name in the zip archive. | ||||
|   For zip archive opened in 'w' or 'a' mode the function will append | ||||
|   a new entry. In readonly mode the function tries to locate the entry | ||||
|   in global dictionary. | ||||
| 
 | ||||
|   Args: | ||||
|     zip: zip archive handler. | ||||
|     entryname: an entry name in local dictionary. | ||||
| 
 | ||||
|   Returns: | ||||
|     The return code - 0 on success, negative number (< 0) on error. | ||||
| */ | ||||
| extern int zip_entry_open(struct zip_t *zip, const char *entryname); | ||||
| 
 | ||||
| /*
 | ||||
|   Opens a new entry by index in the zip archive. | ||||
|   This function is only valid if zip archive was opened in 'r' (readonly) mode. | ||||
| 
 | ||||
|   Args: | ||||
|     zip: zip archive handler. | ||||
|     index: index in local dictionary. | ||||
| 
 | ||||
|   Returns: | ||||
|     The return code - 0 on success, negative number (< 0) on error. | ||||
| */ | ||||
| extern int zip_entry_openbyindex(struct zip_t *zip, int index); | ||||
| 
 | ||||
| /*
 | ||||
|   Closes a zip entry, flushes buffer and releases resources. | ||||
| 
 | ||||
|   Args: | ||||
|     zip: zip archive handler. | ||||
| 
 | ||||
|   Returns: | ||||
|     The return code - 0 on success, negative number (< 0) on error. | ||||
| */ | ||||
| extern int zip_entry_close(struct zip_t *zip); | ||||
| 
 | ||||
| /*
 | ||||
|   Returns a local name of the current zip entry. | ||||
|   The main difference between user's entry name and local entry name | ||||
|   is optional relative path. | ||||
|   Following .ZIP File Format Specification - the path stored MUST not contain | ||||
|   a drive or device letter, or a leading slash. | ||||
|   All slashes MUST be forward slashes '/' as opposed to backwards slashes '\' | ||||
|   for compatibility with Amiga and UNIX file systems etc. | ||||
| 
 | ||||
|   Args: | ||||
|     zip: zip archive handler. | ||||
| 
 | ||||
|   Returns: | ||||
|     The pointer to the current zip entry name, or NULL on error. | ||||
| */ | ||||
| extern const char *zip_entry_name(struct zip_t *zip); | ||||
| 
 | ||||
| /*
 | ||||
|   Returns an index of the current zip entry. | ||||
| 
 | ||||
|   Args: | ||||
|     zip: zip archive handler. | ||||
| 
 | ||||
|   Returns: | ||||
|     The index on success, negative number (< 0) on error. | ||||
| */ | ||||
| extern int zip_entry_index(struct zip_t *zip); | ||||
| 
 | ||||
| /*
 | ||||
|   Determines if the current zip entry is a directory entry. | ||||
| 
 | ||||
|   Args: | ||||
|     zip: zip archive handler. | ||||
| 
 | ||||
|   Returns: | ||||
|     The return code - 1 (true), 0 (false), negative number (< 0) on error. | ||||
| */ | ||||
| extern int zip_entry_isdir(struct zip_t *zip); | ||||
| 
 | ||||
| /*
 | ||||
|   Returns an uncompressed size of the current zip entry. | ||||
| 
 | ||||
|   Args: | ||||
|     zip: zip archive handler. | ||||
| 
 | ||||
|   Returns: | ||||
|     The uncompressed size in bytes. | ||||
| */ | ||||
| extern unsigned long long zip_entry_size(struct zip_t *zip); | ||||
| 
 | ||||
| /*
 | ||||
|   Returns CRC-32 checksum of the current zip entry. | ||||
| 
 | ||||
|   Args: | ||||
|     zip: zip archive handler. | ||||
| 
 | ||||
|   Returns: | ||||
|     The CRC-32 checksum. | ||||
| */ | ||||
| extern unsigned int zip_entry_crc32(struct zip_t *zip); | ||||
| 
 | ||||
| /*
 | ||||
|   Compresses an input buffer for the current zip entry. | ||||
| 
 | ||||
|   Args: | ||||
|     zip: zip archive handler. | ||||
|     buf: input buffer. | ||||
|     bufsize: input buffer size (in bytes). | ||||
| 
 | ||||
|   Returns: | ||||
|     The return code - 0 on success, negative number (< 0) on error. | ||||
| */ | ||||
| extern int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize); | ||||
| 
 | ||||
| /*
 | ||||
|   Compresses a file for the current zip entry. | ||||
| 
 | ||||
|   Args: | ||||
|     zip: zip archive handler. | ||||
|     filename: input file. | ||||
| 
 | ||||
|   Returns: | ||||
|     The return code - 0 on success, negative number (< 0) on error. | ||||
| */ | ||||
| extern int zip_entry_fwrite(struct zip_t *zip, const char *filename); | ||||
| 
 | ||||
| /*
 | ||||
|   Extracts the current zip entry into output buffer. | ||||
|   The function allocates sufficient memory for a output buffer. | ||||
| 
 | ||||
|   Args: | ||||
|     zip: zip archive handler. | ||||
|     buf: output buffer. | ||||
|     bufsize: output buffer size (in bytes). | ||||
| 
 | ||||
|   Note: | ||||
|     - remember to release memory allocated for a output buffer. | ||||
|     - for large entries, please take a look at zip_entry_extract function. | ||||
| 
 | ||||
|   Returns: | ||||
|     The return code - 0 on success, negative number (< 0) on error. | ||||
| */ | ||||
| extern int zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize); | ||||
| 
 | ||||
| /*
 | ||||
|   Extracts the current zip entry into a memory buffer using no memory allocation. | ||||
| 
 | ||||
|   Args: | ||||
|     zip: zip archive handler. | ||||
|     buf: preallocated output buffer. | ||||
|     bufsize: output buffer size (in bytes). | ||||
| 
 | ||||
|   Note: | ||||
|     - ensure supplied output buffer is large enough. | ||||
|     - zip_entry_size function (returns uncompressed size for the current entry) | ||||
|       can be handy to estimate how big buffer is needed. | ||||
|     - for large entries, please take a look at zip_entry_extract function. | ||||
| 
 | ||||
|   Returns: | ||||
|     The return code - 0 on success, negative number (< 0) on error (e.g. bufsize | ||||
|     is not large enough). | ||||
| */ | ||||
| extern int zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize); | ||||
| 
 | ||||
| /*
 | ||||
|   Extracts the current zip entry into output file. | ||||
| 
 | ||||
|   Args: | ||||
|     zip: zip archive handler. | ||||
|     filename: output file. | ||||
| 
 | ||||
|   Returns: | ||||
|     The return code - 0 on success, negative number (< 0) on error. | ||||
| */ | ||||
| extern int zip_entry_fread(struct zip_t *zip, const char *filename); | ||||
| 
 | ||||
| /*
 | ||||
|   Extracts the current zip entry using a callback function (on_extract). | ||||
| 
 | ||||
|   Args: | ||||
|     zip: zip archive handler. | ||||
|     on_extract: callback function. | ||||
|     arg: opaque pointer (optional argument, | ||||
|                          which you can pass to the on_extract callback) | ||||
| 
 | ||||
|    Returns: | ||||
|     The return code - 0 on success, negative number (< 0) on error. | ||||
|  */ | ||||
| extern int zip_entry_extract(struct zip_t *zip, | ||||
|                              size_t (*on_extract)(void *arg, | ||||
|                                                   unsigned long long offset, | ||||
|                                                   const void *data, | ||||
|                                                   size_t size), | ||||
|                              void *arg); | ||||
| 
 | ||||
| /*
 | ||||
|   Returns the number of all entries (files and directories) in the zip archive. | ||||
| 
 | ||||
|   Args: | ||||
|     zip: zip archive handler. | ||||
| 
 | ||||
|   Returns: | ||||
|     The return code - the number of entries on success, | ||||
|     negative number (< 0) on error. | ||||
| */ | ||||
| extern int zip_total_entries(struct zip_t *zip); | ||||
| 
 | ||||
| /*
 | ||||
|   Creates a new archive and puts files into a single zip archive. | ||||
| 
 | ||||
|   Args: | ||||
|     zipname: zip archive file. | ||||
|     filenames: input files. | ||||
|     len: number of input files. | ||||
| 
 | ||||
|   Returns: | ||||
|     The return code - 0 on success, negative number (< 0) on error. | ||||
| */ | ||||
| extern int zip_create(const char *zipname, const char *filenames[], size_t len); | ||||
| 
 | ||||
| /*
 | ||||
|   Extracts a zip archive file into directory. | ||||
| 
 | ||||
|   If on_extract_entry is not NULL, the callback will be called after | ||||
|   successfully extracted each zip entry. | ||||
|   Returning a negative value from the callback will cause abort and return an | ||||
|   error. The last argument (void *arg) is optional, which you can use to pass | ||||
|   data to the on_extract_entry callback. | ||||
| 
 | ||||
|   Args: | ||||
|     zipname: zip archive file. | ||||
|     dir: output directory. | ||||
|     on_extract_entry: on extract callback. | ||||
|     arg: opaque pointer. | ||||
| 
 | ||||
|   Returns: | ||||
|     The return code - 0 on success, negative number (< 0) on error. | ||||
| */ | ||||
| extern int zip_extract(const char *zipname, const char *dir, | ||||
|                        int (*on_extract_entry)(const char *filename, void *arg), | ||||
|                        void *arg); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										208
									
								
								tests/test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								tests/test.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,208 @@ | ||||
| #include <tap.h> | ||||
| #include "../src/librnode.h" | ||||
| #include "../src/libs/logging/log.h" | ||||
| #include "../src/libs/util.h" | ||||
| #include <time.h> | ||||
| #include <openssl/evp.h> | ||||
| #include <openssl/decoder.h> | ||||
| #include <openssl/rsa.h> | ||||
| #include <fcntl.h> | ||||
| 
 | ||||
| #include <string.h> // todo remove me | ||||
| #include <openssl/sha.h> // todo remove me | ||||
| 
 | ||||
| //char* port = "/dev/serial/by-id/usb-Silicon_Labs_CP2102_USB_to_UART_Bridge_Controller_0001-if00-port0";
 | ||||
| char* port = "/dev/ttyACM0"; | ||||
| //char* port = "/dev/serial/by-id/usb-Heltec_HT-n5262_1E35113239EFFE55-if00";
 | ||||
| char* zip = "/home/elimin8/Downloads/rnode_firmware_t3s3_sx1280_pa.zip"; | ||||
| char* key = "/home/elimin8/.config/rnodeconf/firmware/signing.key"; | ||||
| uint32_t baud = 115200; | ||||
| struct RNode rn = {0}; | ||||
| 
 | ||||
| EVP_PKEY* load_key(struct RNode* rn, char* path) { | ||||
|     EVP_PKEY *priv_key = EVP_PKEY_new(); | ||||
|     OSSL_DECODER_CTX *dctx; | ||||
|     const char *format = "DER";   /* NULL for any format */ | ||||
|     const char *structure = NULL; /* any structure */ | ||||
|     const char *keytype = "RSA";  /* NULL for any key */ | ||||
|     size_t len; | ||||
|     uint8_t key_buf[1024]; | ||||
|     const uint8_t *data = key_buf; | ||||
| 
 | ||||
|     FILE *file = fopen(path, "rb");  | ||||
|     if (file <= 0) { | ||||
|         return NULL; | ||||
|     } | ||||
|     fseek(file, 0L, SEEK_END); | ||||
|     len = ftell(file); | ||||
| 
 | ||||
|     fseek(file, 0L, SEEK_SET); | ||||
| 
 | ||||
|     fread(key_buf, sizeof(uint8_t), len, file); | ||||
| 
 | ||||
|     fclose(file); | ||||
| 
 | ||||
|     dctx = OSSL_DECODER_CTX_new_for_pkey(&priv_key, format, structure, | ||||
|             keytype, | ||||
|             OSSL_KEYMGMT_SELECT_KEYPAIR, | ||||
|             NULL, NULL); | ||||
|     if (dctx == NULL) { | ||||
|         /* error: no suitable potential decoders found */ | ||||
|         return NULL; | ||||
|     } | ||||
|     //if (pass != NULL)
 | ||||
|     //    OSSL_DECODER_CTX_set_passphrase(dctx, pass, strlen(pass));
 | ||||
| 
 | ||||
|     if (!OSSL_DECODER_from_data(dctx, &data, &len)) { | ||||
|         /* decoding failure */ | ||||
|         return NULL; | ||||
|     } | ||||
|     OSSL_DECODER_CTX_free(dctx); | ||||
| 
 | ||||
|     return priv_key; | ||||
| } | ||||
| 
 | ||||
| void esp32_flash(struct RNode* rn, char* zip) { | ||||
|     uint8_t serial[4] = {0}; | ||||
| 
 | ||||
|     ok(rnode_set_platform(rn, PLATFORM_ESP32) == 0, "RNode set platform"); | ||||
| 
 | ||||
|     time_t start = time(NULL); | ||||
|     EVP_PKEY *priv_key = load_key(rn, key); | ||||
|     ok(priv_key != NULL, "Load EEPROM signing key"); | ||||
|     rn->product = 0xf0; | ||||
|     rn->model = 0xac; | ||||
|     rn->hw_rev = 0x01; | ||||
|     rn->boot_app0_addr = 0xe000; | ||||
|     rn->bootloader_addr = 0x0; | ||||
|     rn->bin_addr = 0x10000; | ||||
|     rn->partitions_addr = 0x8000; | ||||
|     rn->console_image_addr = 0x210000; | ||||
|     ok(rnode_flash(rn, zip, false, serial, priv_key, true) == 0, "RNode update"); | ||||
|     time_t end = time(NULL); | ||||
|     printf("Time taken for flash: %ld seconds.\n", end - start); | ||||
| } | ||||
| 
 | ||||
| void nrf52_flash(struct RNode* rn, char* zip) { | ||||
|     uint8_t serial[4] = {0}; | ||||
| 
 | ||||
|     ok(rnode_set_platform(rn, PLATFORM_NRF52) == 0, "RNode set platform"); | ||||
| 
 | ||||
|     time_t start = time(NULL); | ||||
|     EVP_PKEY *priv_key = load_key(rn, key); | ||||
|     ok(priv_key != NULL, "Load EEPROM signing key"); | ||||
|     rn->product = 0x10; | ||||
|     rn->model = 0x12; | ||||
|     rn->hw_rev = 0x01; | ||||
|     ok(rnode_flash(rn, zip, false, serial, priv_key, true) == 0, "RNode update"); | ||||
|     time_t end = time(NULL); | ||||
|     printf("Time taken for flash: %ld seconds.\n", end - start); | ||||
| } | ||||
| 
 | ||||
| int main() { | ||||
|     //printf("--- RNode reset test ---\n\n");
 | ||||
| 
 | ||||
|     ok(rnode_init(&rn, port, baud, true, false) == 0, "RNode initialisation & detection"); | ||||
| 
 | ||||
|     //ok(rnode_reset(&rn) == 0, "RNode reset");
 | ||||
|     //sleep_ms(5000);
 | ||||
| 
 | ||||
|     //ok(rnode_cleanup(&rn) == 0, "RNode cleanup");
 | ||||
| 
 | ||||
|     //ok(rnode_init(&rn, port, baud, true, false) == 0, "RNode initialisation & detection");
 | ||||
| 
 | ||||
|     //printf("--- RNode display test --- \n\n");
 | ||||
|     //ok(rnode_set_disp_int(&rn, 255) == 0, "Set display intensity to 255");
 | ||||
|     //sleep_ms(500);
 | ||||
|     //ok(rnode_set_disp_int(&rn, 0) == 0, "Set display intensity to 0");
 | ||||
|     //sleep_ms(500);
 | ||||
|     //ok(rnode_set_disp_int(&rn, 127) == 0, "Set display intensity to 127");
 | ||||
|     //sleep_ms(100);
 | ||||
| 
 | ||||
|     //ok(rnode_set_disp_timeout(&rn, 1) == 0, "Set display timeout to 1 second");
 | ||||
|     //sleep_ms(5000);
 | ||||
|     //ok(rnode_set_disp_timeout(&rn, 1) == 0, "Disable display timeout");
 | ||||
|     //sleep_ms(500);
 | ||||
| 
 | ||||
|     //ok(rnode_set_disp_addr(&rn, 0x3B) == 0, "Set display address to 0x3B");
 | ||||
|     //sleep_ms(500);
 | ||||
|     //ok(rnode_set_disp_addr(&rn, 0x3C) == 0, "Set display address to 0x3C");
 | ||||
|     //sleep_ms(500);
 | ||||
| 
 | ||||
|     //ok(rnode_set_disp_rot(&rn, 0) == 0, "Set display rotation to 0");
 | ||||
|     //sleep_ms(2000);
 | ||||
|     //ok(rnode_cleanup(&rn) == 0, "RNode cleanup");
 | ||||
|     //ok(rnode_init(&rn, port, baud, true, false) == 0, "RNode initialisation & detection");
 | ||||
|     //ok(rnode_set_disp_rot(&rn, 1) == 0, "Set display rotation to 1");
 | ||||
|     //sleep_ms(2000);
 | ||||
|     //ok(rnode_cleanup(&rn) == 0, "RNode cleanup");
 | ||||
|     //ok(rnode_init(&rn, port, baud, true, false) == 0, "RNode initialisation & detection");
 | ||||
|     //ok(rnode_set_disp_rot(&rn, 2) == 0, "Set display rotation to 2");
 | ||||
|     //sleep_ms(2000);
 | ||||
|     //ok(rnode_cleanup(&rn) == 0, "RNode cleanup");
 | ||||
|     //ok(rnode_init(&rn, port, baud, true, false) == 0, "RNode initialisation & detection");
 | ||||
|     //ok(rnode_set_disp_rot(&rn, 3) == 0, "Set display rotation to 3");
 | ||||
|     //sleep_ms(2000);
 | ||||
|     //ok(rnode_cleanup(&rn) == 0, "RNode cleanup");
 | ||||
|     //ok(rnode_init(&rn, port, baud, true, false) == 0, "RNode initialisation & detection");
 | ||||
| 
 | ||||
|     //ok(rnode_start_disp_recon(&rn) == 0, "Start display reconditioning (5s)");
 | ||||
|     //sleep_ms(5000);
 | ||||
| 
 | ||||
|     //ok(rnode_reset(&rn) == 0, "RNode reset");
 | ||||
|     //sleep_ms(5000);
 | ||||
| 
 | ||||
|     //ok(rnode_cleanup(&rn) == 0, "RNode cleanup");
 | ||||
|     //ok(rnode_init(&rn, port, baud, true, false) == 0, "RNode initialisation & detection");
 | ||||
| 
 | ||||
|     //printf("--- RNode NP test (if present) --- \n\n");
 | ||||
| 
 | ||||
|     //ok(rnode_set_np_int(&rn, 0) == 0, "Set NP intensity to 0");
 | ||||
|     //sleep_ms(500);
 | ||||
| 
 | ||||
|     //ok(rnode_set_np_int(&rn, 255) == 0, "Set NP intensity to 255");
 | ||||
|     //sleep_ms(500);
 | ||||
|     //
 | ||||
|     //printf("--- RNode BT test --- \n\n");
 | ||||
| 
 | ||||
|     //ok(rnode_set_bt(&rn, BT_OFF) == 0, "Disable Bluetooth");
 | ||||
|     //sleep_ms(1000);
 | ||||
| 
 | ||||
|     //ok(rnode_set_bt(&rn, BT_ON) == 0, "Enable Bluetooth");
 | ||||
|     //sleep_ms(1000);
 | ||||
| 
 | ||||
|     //ok(rnode_set_bt(&rn, BT_PAIRING) == 0, "Enable Bluetooth pairing");
 | ||||
|     //sleep_ms(1000);
 | ||||
| 
 | ||||
|     //int pin = rnode_get_bt_pin(&rn, 30000);
 | ||||
| 
 | ||||
|     //ok(pin > 0, "Get Bluetooth code (30s timeout)");
 | ||||
| 
 | ||||
|     //printf("Pin: %u\n", pin);
 | ||||
| 
 | ||||
|     //ok(rnode_wipe_eeprom(&rn) == 0, "Wipe RNode EEPROM");
 | ||||
| 
 | ||||
|     //esp32_flash(&rn, zip);
 | ||||
|     //printf("--- RNode flash & provision test ---\n\n");
 | ||||
| 
 | ||||
| 
 | ||||
|     printf("--- RNode TNC mode test ---\n\n"); | ||||
| 
 | ||||
|     ok(rnode_get_interfaces(&rn) == 0, "Get interfaces"); | ||||
| 
 | ||||
|     ok(rnode_select_interface(&rn, 0) == 0, "Select interface 0"); | ||||
| 
 | ||||
|     ok(rnode_set_freq(&rn, 865700000) > 0, "Set frequency"); | ||||
| 
 | ||||
|     ok(rnode_set_sf(&rn, 7) == 0, "Set spreading factor"); | ||||
| 
 | ||||
|     ok(rnode_set_cr(&rn, 7) == 0, "Set coding rate"); | ||||
| 
 | ||||
|     ok(rnode_set_txp(&rn, 7) == 0, "Set TX power"); | ||||
| 
 | ||||
|     ok(rnode_set_tnc_mode(&rn) == 0, "Enable TNC mode"); | ||||
| 
 | ||||
|     ok(rnode_cleanup(&rn) == 0, "RNode cleanup"); | ||||
| 
 | ||||
|     done_testing(); | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user