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