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