Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d3d74f381
|
||
|
|
20639b77a6
|
||
|
|
b8909fca06
|
||
|
|
54b72a4bf1
|
||
|
|
afee9ab6a3
|
||
|
|
a1e9cf2a57
|
||
|
|
482a67c5d2
|
||
|
|
9703408307
|
||
|
|
b40825a75f
|
||
|
|
6bfa40ce9f
|
||
|
|
315da1fc82
|
||
|
|
0bce53403f
|
||
|
|
30d1762710
|
||
|
|
49c291dade
|
||
|
|
02b0ceb139
|
||
|
|
c0846f0bb7
|
||
|
|
396501564a
|
||
|
|
041e4f5b70
|
||
|
|
4ede660471
|
||
|
|
73e134d0b6
|
||
|
|
dc78c4da41
|
||
|
|
2bad5d69e6
|
||
|
|
e4ae8e23fc
|
||
|
|
2f4101a6e0
|
||
|
|
5eec46c041
|
||
|
|
9182c666ea
|
||
|
|
a66c453820
|
||
|
|
de75f2d91c
|
||
|
|
e667a2dd3a
|
||
|
|
9b1d084308
|
||
|
|
102d5f5a4c
|
||
|
|
1797f179b4
|
||
|
|
218d26fb7b
|
||
|
|
b9f82c8077
|
||
|
|
d1f8804a93
|
||
|
|
2e2dab9244
|
||
|
|
e046be30b2
|
||
|
|
f9200fcc7d
|
||
|
|
ffec192a27
|
||
|
|
9f40c6e4dd
|
||
|
|
b2066a9010
|
||
|
|
590d550a09
|
||
|
|
274f2be6e0
|
||
|
|
76d1cd3a24
|
||
|
|
3654bf2206
|
||
|
|
5687196bdd
|
||
|
|
da330b4b73
|
||
|
|
0b14e5dda4
|
||
|
|
887887b675
|
||
|
|
e96ecceec9
|
||
|
|
d8bdaf7203
|
||
|
|
3fdd51ba2e
|
||
|
|
5dd350ffe4
|
||
|
|
4b8d24ae0f
|
||
|
|
ed7a4c80a0
|
||
|
|
78897f84b3
|
||
|
|
8410c273ab
|
||
|
|
2812f962d9
|
||
|
|
7f4c06ae4b
|
||
|
|
5019bf225d
|
||
|
|
41ad18cc7c
|
||
|
|
101d2534f4
|
||
|
|
1f2d346e23
|
||
|
|
639031fc38
|
||
|
|
1a888366af
|
||
|
|
a60b736834
|
||
|
|
8dcdaf9236
|
+7
-29
@@ -90,6 +90,7 @@
|
|||||||
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
|
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "plat_config.h"
|
||||||
#include "plat_compat.h"
|
#include "plat_compat.h"
|
||||||
extern uint32_t SystemCoreClock;
|
extern uint32_t SystemCoreClock;
|
||||||
#endif
|
#endif
|
||||||
@@ -110,7 +111,7 @@ extern uint32_t SystemCoreClock;
|
|||||||
#define configCHECK_FOR_STACK_OVERFLOW 2
|
#define configCHECK_FOR_STACK_OVERFLOW 2
|
||||||
#define configENABLE_BACKWARD_COMPATIBILITY 0
|
#define configENABLE_BACKWARD_COMPATIBILITY 0
|
||||||
|
|
||||||
#define configUSE_TIMERS 1
|
#define configUSE_TIMERS 0
|
||||||
#define configTIMER_TASK_PRIORITY TSK_TIMERS_PRIO // above normal
|
#define configTIMER_TASK_PRIORITY TSK_TIMERS_PRIO // above normal
|
||||||
#define configTIMER_TASK_STACK_DEPTH TSK_STACK_TIMERS //128
|
#define configTIMER_TASK_STACK_DEPTH TSK_STACK_TIMERS //128
|
||||||
#define configTIMER_QUEUE_LENGTH 4
|
#define configTIMER_QUEUE_LENGTH 4
|
||||||
@@ -134,34 +135,11 @@ to exclude the API function. */
|
|||||||
|
|
||||||
///* Cortex-M specific definitions. */
|
///* Cortex-M specific definitions. */
|
||||||
|
|
||||||
#if defined(GEX_PLAT_F103_BLUEPILL) || defined(GEX_PLAT_F303_DISCOVERY) \
|
// These are defined in plat_compat.h:
|
||||||
|| defined(GEX_PLAT_F407_DISCOVERY)
|
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY PLAT_FREERTOS_LOWEST_INTERRUPT_PRIORITY
|
||||||
// This is for F103+
|
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY PLAT_FREERTOS_MAX_SYSCALL_INTERRUPT_PRIORITY
|
||||||
|
#define configPRIO_BITS PLAT_FREERTOS_PRIO_BITS
|
||||||
/* The lowest interrupt priority that can be used in a call to a "set priority"
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION PLAT_FREERTOS_USE_PORT_OPTIMISED_TASK_SELECTION
|
||||||
function. */
|
|
||||||
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
|
|
||||||
|
|
||||||
#define configPRIO_BITS 4
|
|
||||||
|
|
||||||
/* The highest interrupt priority that can be used by any interrupt service
|
|
||||||
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
|
|
||||||
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
|
|
||||||
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
|
|
||||||
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
|
|
||||||
|
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
|
||||||
#elif defined(GEX_PLAT_F072_DISCOVERY)
|
|
||||||
// This is for F072
|
|
||||||
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 3
|
|
||||||
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 1
|
|
||||||
|
|
||||||
#define configPRIO_BITS 2
|
|
||||||
|
|
||||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
|
||||||
#else
|
|
||||||
#error "BAD PLATFORM!!"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Interrupt priorities used by the kernel port layer itself. These are generic
|
/* Interrupt priorities used by the kernel port layer itself. These are generic
|
||||||
to all Cortex-M ports, and do not rely on any particular library functions. */
|
to all Cortex-M ports, and do not rely on any particular library functions. */
|
||||||
|
|||||||
+373
@@ -0,0 +1,373 @@
|
|||||||
|
Mozilla Public License Version 2.0
|
||||||
|
==================================
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
--------------
|
||||||
|
|
||||||
|
1.1. "Contributor"
|
||||||
|
means each individual or legal entity that creates, contributes to
|
||||||
|
the creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. "Contributor Version"
|
||||||
|
means the combination of the Contributions of others (if any) used
|
||||||
|
by a Contributor and that particular Contributor's Contribution.
|
||||||
|
|
||||||
|
1.3. "Contribution"
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. "Covered Software"
|
||||||
|
means Source Code Form to which the initial Contributor has attached
|
||||||
|
the notice in Exhibit A, the Executable Form of such Source Code
|
||||||
|
Form, and Modifications of such Source Code Form, in each case
|
||||||
|
including portions thereof.
|
||||||
|
|
||||||
|
1.5. "Incompatible With Secondary Licenses"
|
||||||
|
means
|
||||||
|
|
||||||
|
(a) that the initial Contributor has attached the notice described
|
||||||
|
in Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
(b) that the Covered Software was made available under the terms of
|
||||||
|
version 1.1 or earlier of the License, but not also under the
|
||||||
|
terms of a Secondary License.
|
||||||
|
|
||||||
|
1.6. "Executable Form"
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. "Larger Work"
|
||||||
|
means a work that combines Covered Software with other material, in
|
||||||
|
a separate file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. "License"
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. "Licensable"
|
||||||
|
means having the right to grant, to the maximum extent possible,
|
||||||
|
whether at the time of the initial grant or subsequently, any and
|
||||||
|
all of the rights conveyed by this License.
|
||||||
|
|
||||||
|
1.10. "Modifications"
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
(a) any file in Source Code Form that results from an addition to,
|
||||||
|
deletion from, or modification of the contents of Covered
|
||||||
|
Software; or
|
||||||
|
|
||||||
|
(b) any new file in Source Code Form that contains any Covered
|
||||||
|
Software.
|
||||||
|
|
||||||
|
1.11. "Patent Claims" of a Contributor
|
||||||
|
means any patent claim(s), including without limitation, method,
|
||||||
|
process, and apparatus claims, in any patent Licensable by such
|
||||||
|
Contributor that would be infringed, but for the grant of the
|
||||||
|
License, by the making, using, selling, offering for sale, having
|
||||||
|
made, import, or transfer of either its Contributions or its
|
||||||
|
Contributor Version.
|
||||||
|
|
||||||
|
1.12. "Secondary License"
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU
|
||||||
|
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||||
|
Public License, Version 3.0, or any later versions of those
|
||||||
|
licenses.
|
||||||
|
|
||||||
|
1.13. "Source Code Form"
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. "You" (or "Your")
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, "You" includes any entity that
|
||||||
|
controls, is controlled by, or is under common control with You. For
|
||||||
|
purposes of this definition, "control" means (a) the power, direct
|
||||||
|
or indirect, to cause the direction or management of such entity,
|
||||||
|
whether by contract or otherwise, or (b) ownership of more than
|
||||||
|
fifty percent (50%) of the outstanding shares or beneficial
|
||||||
|
ownership of such entity.
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
(a) under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or
|
||||||
|
as part of a Larger Work; and
|
||||||
|
|
||||||
|
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||||
|
for sale, have made, import, and otherwise transfer either its
|
||||||
|
Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution
|
||||||
|
become effective for each Contribution on the date the Contributor first
|
||||||
|
distributes such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under
|
||||||
|
this License. No additional rights or licenses will be implied from the
|
||||||
|
distribution or licensing of Covered Software under this License.
|
||||||
|
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||||
|
Contributor:
|
||||||
|
|
||||||
|
(a) for any code that a Contributor has removed from Covered Software;
|
||||||
|
or
|
||||||
|
|
||||||
|
(b) for infringements caused by: (i) Your and any other third party's
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||||
|
its Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks,
|
||||||
|
or logos of any Contributor (except as may be necessary to comply with
|
||||||
|
the notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this
|
||||||
|
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||||
|
permitted under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its
|
||||||
|
Contributions are its original creation(s) or it has sufficient rights
|
||||||
|
to grant the rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under
|
||||||
|
applicable copyright doctrines of fair use, fair dealing, or other
|
||||||
|
equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||||
|
in Section 2.1.
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under
|
||||||
|
the terms of this License. You must inform recipients that the Source
|
||||||
|
Code Form of the Covered Software is governed by the terms of this
|
||||||
|
License, and how they can obtain a copy of this License. You may not
|
||||||
|
attempt to alter or restrict the recipients' rights in the Source Code
|
||||||
|
Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
(a) such Covered Software must also be made available in Source Code
|
||||||
|
Form, as described in Section 3.1, and You must inform recipients of
|
||||||
|
the Executable Form how they can obtain a copy of such Source Code
|
||||||
|
Form by reasonable means in a timely manner, at a charge no more
|
||||||
|
than the cost of distribution to the recipient; and
|
||||||
|
|
||||||
|
(b) You may distribute such Executable Form under the terms of this
|
||||||
|
License, or sublicense it under different terms, provided that the
|
||||||
|
license for the Executable Form does not attempt to limit or alter
|
||||||
|
the recipients' rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for
|
||||||
|
the Covered Software. If the Larger Work is a combination of Covered
|
||||||
|
Software with a work governed by one or more Secondary Licenses, and the
|
||||||
|
Covered Software is not Incompatible With Secondary Licenses, this
|
||||||
|
License permits You to additionally distribute such Covered Software
|
||||||
|
under the terms of such Secondary License(s), so that the recipient of
|
||||||
|
the Larger Work may, at their option, further distribute the Covered
|
||||||
|
Software under the terms of either this License or such Secondary
|
||||||
|
License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices
|
||||||
|
(including copyright notices, patent notices, disclaimers of warranty,
|
||||||
|
or limitations of liability) contained within the Source Code Form of
|
||||||
|
the Covered Software, except that You may alter any license notices to
|
||||||
|
the extent required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on
|
||||||
|
behalf of any Contributor. You must make it absolutely clear that any
|
||||||
|
such warranty, support, indemnity, or liability obligation is offered by
|
||||||
|
You alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this
|
||||||
|
License with respect to some or all of the Covered Software due to
|
||||||
|
statute, judicial order, or regulation then You must: (a) comply with
|
||||||
|
the terms of this License to the maximum extent possible; and (b)
|
||||||
|
describe the limitations and the code they affect. Such description must
|
||||||
|
be placed in a text file included with all distributions of the Covered
|
||||||
|
Software under this License. Except to the extent prohibited by statute
|
||||||
|
or regulation, such description must be sufficiently detailed for a
|
||||||
|
recipient of ordinary skill to be able to understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
--------------
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically
|
||||||
|
if You fail to comply with any of its terms. However, if You become
|
||||||
|
compliant, then the rights granted under this License from a particular
|
||||||
|
Contributor are reinstated (a) provisionally, unless and until such
|
||||||
|
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||||
|
ongoing basis, if such Contributor fails to notify You of the
|
||||||
|
non-compliance by some reasonable means prior to 60 days after You have
|
||||||
|
come back into compliance. Moreover, Your grants from a particular
|
||||||
|
Contributor are reinstated on an ongoing basis if such Contributor
|
||||||
|
notifies You of the non-compliance by some reasonable means, this is the
|
||||||
|
first time You have received notice of non-compliance with this License
|
||||||
|
from such Contributor, and You become compliant prior to 30 days after
|
||||||
|
Your receipt of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions,
|
||||||
|
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||||
|
directly or indirectly infringes any patent, then the rights granted to
|
||||||
|
You by any and all Contributors for the Covered Software under Section
|
||||||
|
2.1 of this License shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||||
|
end user license agreements (excluding distributors and resellers) which
|
||||||
|
have been validly granted by You or Your distributors under this License
|
||||||
|
prior to termination shall survive termination.
|
||||||
|
|
||||||
|
************************************************************************
|
||||||
|
* *
|
||||||
|
* 6. Disclaimer of Warranty *
|
||||||
|
* ------------------------- *
|
||||||
|
* *
|
||||||
|
* Covered Software is provided under this License on an "as is" *
|
||||||
|
* basis, without warranty of any kind, either expressed, implied, or *
|
||||||
|
* statutory, including, without limitation, warranties that the *
|
||||||
|
* Covered Software is free of defects, merchantable, fit for a *
|
||||||
|
* particular purpose or non-infringing. The entire risk as to the *
|
||||||
|
* quality and performance of the Covered Software is with You. *
|
||||||
|
* Should any Covered Software prove defective in any respect, You *
|
||||||
|
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||||
|
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||||
|
* essential part of this License. No use of any Covered Software is *
|
||||||
|
* authorized under this License except under this disclaimer. *
|
||||||
|
* *
|
||||||
|
************************************************************************
|
||||||
|
|
||||||
|
************************************************************************
|
||||||
|
* *
|
||||||
|
* 7. Limitation of Liability *
|
||||||
|
* -------------------------- *
|
||||||
|
* *
|
||||||
|
* Under no circumstances and under no legal theory, whether tort *
|
||||||
|
* (including negligence), contract, or otherwise, shall any *
|
||||||
|
* Contributor, or anyone who distributes Covered Software as *
|
||||||
|
* permitted above, be liable to You for any direct, indirect, *
|
||||||
|
* special, incidental, or consequential damages of any character *
|
||||||
|
* including, without limitation, damages for lost profits, loss of *
|
||||||
|
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||||
|
* and all other commercial damages or losses, even if such party *
|
||||||
|
* shall have been informed of the possibility of such damages. This *
|
||||||
|
* limitation of liability shall not apply to liability for death or *
|
||||||
|
* personal injury resulting from such party's negligence to the *
|
||||||
|
* extent applicable law prohibits such limitation. Some *
|
||||||
|
* jurisdictions do not allow the exclusion or limitation of *
|
||||||
|
* incidental or consequential damages, so this exclusion and *
|
||||||
|
* limitation may not apply to You. *
|
||||||
|
* *
|
||||||
|
************************************************************************
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the
|
||||||
|
courts of a jurisdiction where the defendant maintains its principal
|
||||||
|
place of business and such litigation shall be governed by laws of that
|
||||||
|
jurisdiction, without reference to its conflict-of-law provisions.
|
||||||
|
Nothing in this Section shall prevent a party's ability to bring
|
||||||
|
cross-claims or counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
----------------
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject
|
||||||
|
matter hereof. If any provision of this License is held to be
|
||||||
|
unenforceable, such provision shall be reformed only to the extent
|
||||||
|
necessary to make it enforceable. Any law or regulation which provides
|
||||||
|
that the language of a contract shall be construed against the drafter
|
||||||
|
shall not be used to construe this License against a Contributor.
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version
|
||||||
|
of the License under which You originally received the Covered Software,
|
||||||
|
or under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a
|
||||||
|
modified version of this License if you rename the license and remove
|
||||||
|
any references to the name of the license steward (except to note that
|
||||||
|
such modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||||
|
Licenses
|
||||||
|
|
||||||
|
If You choose to distribute Source Code Form that is Incompatible With
|
||||||
|
Secondary Licenses under the terms of this version of the License, the
|
||||||
|
notice described in Exhibit B of this License must be attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular
|
||||||
|
file, then You may include the notice in a location (such as a LICENSE
|
||||||
|
file in a relevant directory) where a recipient would be likely to look
|
||||||
|
for such a notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||||
|
---------------------------------------------------------
|
||||||
|
|
||||||
|
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
defined by the Mozilla Public License, v. 2.0.
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
GEX core
|
||||||
|
========
|
||||||
|
|
||||||
|
This is the (mostly) independent core of the GEX platform. To port GEX to a new STM32 microcontroller,
|
||||||
|
add this as a submodule and implement platform specific configuration by following the example of another
|
||||||
|
existing port. Some examples are in the template folder.
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
- Original GEX source code is provided under the Mozilla Public License v2.0.
|
||||||
|
- The VFS driver is adapted from the DAPLink project and remains licensed under the Apache license v2.0.
|
||||||
|
- STM32 device drivers etc. provided by ST Microelectronics are licensed under the 3-clause BSD license.
|
||||||
+36
-18
@@ -6,8 +6,15 @@
|
|||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "task_main.h"
|
#include "task_main.h"
|
||||||
|
#include "comm/messages.h"
|
||||||
|
#include "comm/interfaces.h"
|
||||||
|
#include "comm/iface_uart.h"
|
||||||
|
#include "comm/iface_nordic.h"
|
||||||
|
#include "comm/iface_usb.h"
|
||||||
|
#include "framework/system_settings.h"
|
||||||
|
|
||||||
#include "USB/usbd_cdc_if.h"
|
#include "USB/usbd_cdc_if.h"
|
||||||
|
#include "USB/usb_device.h"
|
||||||
#include "TinyFrame.h"
|
#include "TinyFrame.h"
|
||||||
|
|
||||||
extern osSemaphoreId semVcomTxReadyHandle;
|
extern osSemaphoreId semVcomTxReadyHandle;
|
||||||
@@ -15,21 +22,20 @@ extern osMutexId mutTinyFrameTxHandle;
|
|||||||
|
|
||||||
void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
|
void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
|
||||||
{
|
{
|
||||||
(void) tf;
|
if (gActiveComport == COMPORT_USB) {
|
||||||
#define CHUNK 64 // same as TF_SENDBUF_LEN, so we should always have only one run of the loop
|
iface_usb_transmit(buff, len);
|
||||||
int32_t total = (int32_t) len;
|
}
|
||||||
while (total > 0) {
|
else if (gActiveComport == COMPORT_USART) {
|
||||||
const int32_t mxStatus = osSemaphoreWait(semVcomTxReadyHandle, 100);
|
iface_uart_transmit(buff, len);
|
||||||
if (mxStatus != osOK) {
|
}
|
||||||
TF_Error("Tx stalled");
|
#if SUPPORT_NRF
|
||||||
return;
|
else if (gActiveComport == COMPORT_NORDIC) {
|
||||||
}
|
iface_nordic_transmit(buff, len);
|
||||||
|
}
|
||||||
const uint16_t chunksize = (uint16_t) MIN(total, CHUNK);
|
#endif // SUPPORT_NRF
|
||||||
assert_param(USBD_OK == CDC_Transmit_FS((uint8_t *) buff, chunksize));
|
else {
|
||||||
|
// TODO other transports
|
||||||
buff += chunksize;
|
trap("not implemented.");
|
||||||
total -= chunksize;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,10 +43,20 @@ void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
|
|||||||
bool TF_ClaimTx(TinyFrame *tf)
|
bool TF_ClaimTx(TinyFrame *tf)
|
||||||
{
|
{
|
||||||
(void) tf;
|
(void) tf;
|
||||||
// assert_param(osThreadGetId() != tskMainHandle);
|
|
||||||
assert_param(!inIRQ());
|
assert_param(!inIRQ());
|
||||||
|
|
||||||
assert_param(osOK == osMutexWait(mutTinyFrameTxHandle, 5000));
|
assert_param(pdTRUE == xSemaphoreTake(mutTinyFrameTxHandle, 5000)); // trips the wd
|
||||||
|
|
||||||
|
// The last chunk from some previous frame may still be being transmitted,
|
||||||
|
// wait for it to finish (the semaphore is given in the CDC tx done handler)
|
||||||
|
if (pdTRUE != xSemaphoreTake(semVcomTxReadyHandle, 200)) {
|
||||||
|
TF_Error("Tx stalled in Claim");
|
||||||
|
|
||||||
|
// release the guarding mutex again
|
||||||
|
assert_param(pdTRUE == xSemaphoreGive(mutTinyFrameTxHandle));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,5 +64,7 @@ bool TF_ClaimTx(TinyFrame *tf)
|
|||||||
void TF_ReleaseTx(TinyFrame *tf)
|
void TF_ReleaseTx(TinyFrame *tf)
|
||||||
{
|
{
|
||||||
(void) tf;
|
(void) tf;
|
||||||
assert_param(osOK == osMutexRelease(mutTinyFrameTxHandle));
|
assert_param(pdTRUE == xSemaphoreGive(mutTinyFrameTxHandle));
|
||||||
|
|
||||||
|
// the last payload is sent asynchronously
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -870,7 +870,11 @@ static inline uint32_t _TF_FN TF_ComposeTail(uint8_t *outbuff, TF_CKSUM *cksum)
|
|||||||
*/
|
*/
|
||||||
static bool _TF_FN TF_SendFrame_Begin(TinyFrame *tf, TF_Msg *msg, TF_Listener listener, TF_TICKS timeout)
|
static bool _TF_FN TF_SendFrame_Begin(TinyFrame *tf, TF_Msg *msg, TF_Listener listener, TF_TICKS timeout)
|
||||||
{
|
{
|
||||||
TF_TRY(TF_ClaimTx(tf));
|
bool suc = TF_ClaimTx(tf);
|
||||||
|
if (!suc) {
|
||||||
|
TF_Error("TF lock not free");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
tf->tx_pos = (uint32_t) TF_ComposeHead(tf, tf->sendbuf, msg); // frame ID is incremented here if it's not a response
|
tf->tx_pos = (uint32_t) TF_ComposeHead(tf, tf->sendbuf, msg); // frame ID is incremented here if it's not a response
|
||||||
tf->tx_len = msg->len;
|
tf->tx_len = msg->len;
|
||||||
@@ -1031,10 +1035,10 @@ bool _TF_FN TF_Query_Multipart(TinyFrame *tf, TF_Msg *msg, TF_Listener listener,
|
|||||||
return TF_Query(tf, msg, listener, timeout);
|
return TF_Query(tf, msg, listener, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _TF_FN TF_Respond_Multipart(TinyFrame *tf, TF_Msg *msg)
|
bool _TF_FN TF_Respond_Multipart(TinyFrame *tf, TF_Msg *msg)
|
||||||
{
|
{
|
||||||
msg->data = NULL;
|
msg->data = NULL;
|
||||||
TF_Respond(tf, msg);
|
return TF_Respond(tf, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _TF_FN TF_Multipart_Payload(TinyFrame *tf, const uint8_t *buff, uint32_t length)
|
void _TF_FN TF_Multipart_Payload(TinyFrame *tf, const uint8_t *buff, uint32_t length)
|
||||||
|
|||||||
@@ -369,7 +369,7 @@ bool TF_Query_Multipart(TinyFrame *tf, TF_Msg *msg, TF_Listener listener, TF_TIC
|
|||||||
* TF_Respond() with multipart payload.
|
* TF_Respond() with multipart payload.
|
||||||
* msg.data is ignored and set to NULL
|
* msg.data is ignored and set to NULL
|
||||||
*/
|
*/
|
||||||
void TF_Respond_Multipart(TinyFrame *tf, TF_Msg *msg);
|
bool TF_Respond_Multipart(TinyFrame *tf, TF_Msg *msg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send the payload for a started multipart frame. This can be called multiple times
|
* Send the payload for a started multipart frame. This can be called multiple times
|
||||||
|
|||||||
@@ -17,3 +17,15 @@ and processed by the message queue thread. This makes it possible to query hardw
|
|||||||
also makes it possible to wait on a binary semaphore when sending data back to host. The
|
also makes it possible to wait on a binary semaphore when sending data back to host. The
|
||||||
semaphore is set from the CDC TxComplete callback and taken by the TinyFrame write
|
semaphore is set from the CDC TxComplete callback and taken by the TinyFrame write
|
||||||
function, serving as a form of flow control.
|
function, serving as a form of flow control.
|
||||||
|
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
COMM API:
|
||||||
|
|
||||||
|
GEX supports alternate command interfaces.
|
||||||
|
|
||||||
|
The active interface is set in the global variable gActiveComport
|
||||||
|
Due to special init procedures, the com_switch_transfer() function must be called to change it.
|
||||||
|
|
||||||
|
The TX function is defined in TF_Integration.c and any RX'd data is sent through rxQuePostMsg()
|
||||||
|
|
||||||
|
|||||||
@@ -1,328 +0,0 @@
|
|||||||
--- Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c (date 1511202099000)
|
|
||||||
+++ Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c (revision )
|
|
||||||
@@ -59,6 +59,7 @@
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Includes ------------------------------------------------------------------*/
|
|
||||||
+#include "usbd_msc.h" // for rejecting bad control messages
|
|
||||||
#include "usbd_cdc.h"
|
|
||||||
#include "usbd_desc.h"
|
|
||||||
#include "usbd_ctlreq.h"
|
|
||||||
@@ -103,34 +104,7 @@
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
-
|
|
||||||
-static uint8_t USBD_CDC_Init (USBD_HandleTypeDef *pdev,
|
|
||||||
- uint8_t cfgidx);
|
|
||||||
-
|
|
||||||
-static uint8_t USBD_CDC_DeInit (USBD_HandleTypeDef *pdev,
|
|
||||||
- uint8_t cfgidx);
|
|
||||||
-
|
|
||||||
-static uint8_t USBD_CDC_Setup (USBD_HandleTypeDef *pdev,
|
|
||||||
- USBD_SetupReqTypedef *req);
|
|
||||||
-
|
|
||||||
-static uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev,
|
|
||||||
- uint8_t epnum);
|
|
||||||
-
|
|
||||||
-static uint8_t USBD_CDC_DataOut (USBD_HandleTypeDef *pdev,
|
|
||||||
- uint8_t epnum);
|
|
||||||
-
|
|
||||||
-static uint8_t USBD_CDC_EP0_RxReady (USBD_HandleTypeDef *pdev);
|
|
||||||
-
|
|
||||||
-static uint8_t *USBD_CDC_GetFSCfgDesc (uint16_t *length);
|
|
||||||
-
|
|
||||||
-static uint8_t *USBD_CDC_GetHSCfgDesc (uint16_t *length);
|
|
||||||
-
|
|
||||||
-static uint8_t *USBD_CDC_GetOtherSpeedCfgDesc (uint16_t *length);
|
|
||||||
-
|
|
||||||
-static uint8_t *USBD_CDC_GetOtherSpeedCfgDesc (uint16_t *length);
|
|
||||||
-
|
|
||||||
-uint8_t *USBD_CDC_GetDeviceQualifierDescriptor (uint16_t *length);
|
|
||||||
-
|
|
||||||
+#ifndef CDC_COMPOSITE
|
|
||||||
/* USB Standard Device Descriptor */
|
|
||||||
__ALIGN_BEGIN static uint8_t USBD_CDC_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
|
|
||||||
{
|
|
||||||
@@ -156,7 +130,7 @@
|
|
||||||
|
|
||||||
|
|
||||||
/* CDC interface class callbacks structure */
|
|
||||||
-USBD_ClassTypeDef USBD_CDC =
|
|
||||||
+USBD_ClassTypeDef USBD_CDC =
|
|
||||||
{
|
|
||||||
USBD_CDC_Init,
|
|
||||||
USBD_CDC_DeInit,
|
|
||||||
@@ -172,6 +146,7 @@
|
|
||||||
USBD_CDC_GetFSCfgDesc,
|
|
||||||
USBD_CDC_GetOtherSpeedCfgDesc,
|
|
||||||
USBD_CDC_GetDeviceQualifierDescriptor,
|
|
||||||
+ NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
/* USB CDC device Configuration Descriptor */
|
|
||||||
@@ -456,6 +431,7 @@
|
|
||||||
0x00,
|
|
||||||
0x00 /* bInterval */
|
|
||||||
};
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
@@ -463,7 +439,7 @@
|
|
||||||
|
|
||||||
/** @defgroup USBD_CDC_Private_Functions
|
|
||||||
* @{
|
|
||||||
- */
|
|
||||||
+ */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_CDC_Init
|
|
||||||
@@ -472,7 +448,7 @@
|
|
||||||
* @param cfgidx: Configuration index
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
-static uint8_t USBD_CDC_Init (USBD_HandleTypeDef *pdev,
|
|
||||||
+uint8_t USBD_CDC_Init (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t cfgidx)
|
|
||||||
{
|
|
||||||
uint8_t ret = 0;
|
|
||||||
@@ -514,18 +490,18 @@
|
|
||||||
CDC_CMD_PACKET_SIZE);
|
|
||||||
|
|
||||||
|
|
||||||
- pdev->pClassData = USBD_malloc(sizeof (USBD_CDC_HandleTypeDef));
|
|
||||||
+ pdev->pClassData2 = USBD_malloc(sizeof (USBD_CDC_HandleTypeDef));
|
|
||||||
|
|
||||||
- if(pdev->pClassData == NULL)
|
|
||||||
+ if(pdev->pClassData2 == NULL)
|
|
||||||
{
|
|
||||||
ret = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
- hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
|
|
||||||
+ hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
|
|
||||||
|
|
||||||
/* Init physical Interface components */
|
|
||||||
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Init();
|
|
||||||
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData2)->Init();
|
|
||||||
|
|
||||||
/* Init Xfer states */
|
|
||||||
hcdc->TxState =0;
|
|
||||||
@@ -560,7 +536,7 @@
|
|
||||||
* @param cfgidx: Configuration index
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
-static uint8_t USBD_CDC_DeInit (USBD_HandleTypeDef *pdev,
|
|
||||||
+uint8_t USBD_CDC_DeInit (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t cfgidx)
|
|
||||||
{
|
|
||||||
uint8_t ret = 0;
|
|
||||||
@@ -579,11 +555,11 @@
|
|
||||||
|
|
||||||
|
|
||||||
/* DeInit physical Interface components */
|
|
||||||
- if(pdev->pClassData != NULL)
|
|
||||||
+ if(pdev->pClassData2 != NULL)
|
|
||||||
{
|
|
||||||
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->DeInit();
|
|
||||||
- USBD_free(pdev->pClassData);
|
|
||||||
- pdev->pClassData = NULL;
|
|
||||||
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData2)->DeInit();
|
|
||||||
+ USBD_free(pdev->pClassData2);
|
|
||||||
+ pdev->pClassData2 = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
@@ -596,20 +572,23 @@
|
|
||||||
* @param req: usb requests
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
-static uint8_t USBD_CDC_Setup (USBD_HandleTypeDef *pdev,
|
|
||||||
+uint8_t USBD_CDC_Setup (USBD_HandleTypeDef *pdev,
|
|
||||||
USBD_SetupReqTypedef *req)
|
|
||||||
{
|
|
||||||
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
|
|
||||||
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
|
|
||||||
static uint8_t ifalt = 0;
|
|
||||||
|
|
||||||
switch (req->bmRequest & USB_REQ_TYPE_MASK)
|
|
||||||
{
|
|
||||||
case USB_REQ_TYPE_CLASS :
|
|
||||||
+ if (req->bRequest == BOT_GET_MAX_LUN) break; // Not ours!
|
|
||||||
+ if (req->bRequest == BOT_RESET) break; // Not ours!
|
|
||||||
+
|
|
||||||
if (req->wLength)
|
|
||||||
{
|
|
||||||
if (req->bmRequest & 0x80)
|
|
||||||
{
|
|
||||||
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Control(req->bRequest,
|
|
||||||
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData2)->Control(req->bRequest,
|
|
||||||
(uint8_t *)hcdc->data,
|
|
||||||
req->wLength);
|
|
||||||
USBD_CtlSendData (pdev,
|
|
||||||
@@ -629,7 +608,7 @@
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Control(req->bRequest,
|
|
||||||
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData2)->Control(req->bRequest,
|
|
||||||
(uint8_t*)req,
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
@@ -661,14 +640,15 @@
|
|
||||||
* @param epnum: endpoint number
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
-static uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|
||||||
+uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|
||||||
{
|
|
||||||
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
|
|
||||||
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
|
|
||||||
|
|
||||||
- if(pdev->pClassData != NULL)
|
|
||||||
+ if(pdev->pClassData2 != NULL)
|
|
||||||
{
|
|
||||||
|
|
||||||
hcdc->TxState = 0;
|
|
||||||
+ USBD_CDC_TransmitDone(pdev);
|
|
||||||
|
|
||||||
return USBD_OK;
|
|
||||||
}
|
|
||||||
@@ -685,18 +665,18 @@
|
|
||||||
* @param epnum: endpoint number
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
-static uint8_t USBD_CDC_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|
||||||
+uint8_t USBD_CDC_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|
||||||
{
|
|
||||||
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
|
|
||||||
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
|
|
||||||
|
|
||||||
/* Get the received data length */
|
|
||||||
hcdc->RxLength = USBD_LL_GetRxDataSize (pdev, epnum);
|
|
||||||
|
|
||||||
/* USB data will be immediately processed, this allow next USB traffic being
|
|
||||||
NAKed till the end of the application Xfer */
|
|
||||||
- if(pdev->pClassData != NULL)
|
|
||||||
+ if(pdev->pClassData2 != NULL)
|
|
||||||
{
|
|
||||||
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Receive(hcdc->RxBuffer, &hcdc->RxLength);
|
|
||||||
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData2)->Receive(hcdc->RxBuffer, &hcdc->RxLength);
|
|
||||||
|
|
||||||
return USBD_OK;
|
|
||||||
}
|
|
||||||
@@ -715,13 +695,13 @@
|
|
||||||
* @param epnum: endpoint number
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
-static uint8_t USBD_CDC_EP0_RxReady (USBD_HandleTypeDef *pdev)
|
|
||||||
+uint8_t USBD_CDC_EP0_RxReady (USBD_HandleTypeDef *pdev)
|
|
||||||
{
|
|
||||||
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
|
|
||||||
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
|
|
||||||
|
|
||||||
- if((pdev->pUserData != NULL) && (hcdc->CmdOpCode != 0xFF))
|
|
||||||
+ if((pdev->pUserData2 != NULL) && (hcdc->CmdOpCode != 0xFF))
|
|
||||||
{
|
|
||||||
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Control(hcdc->CmdOpCode,
|
|
||||||
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData2)->Control(hcdc->CmdOpCode,
|
|
||||||
(uint8_t *)hcdc->data,
|
|
||||||
hcdc->CmdLength);
|
|
||||||
hcdc->CmdOpCode = 0xFF;
|
|
||||||
@@ -730,6 +710,7 @@
|
|
||||||
return USBD_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
+#ifndef CDC_COMPOSITE
|
|
||||||
/**
|
|
||||||
* @brief USBD_CDC_GetFSCfgDesc
|
|
||||||
* Return configuration descriptor
|
|
||||||
@@ -737,7 +718,7 @@
|
|
||||||
* @param length : pointer data length
|
|
||||||
* @retval pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
-static uint8_t *USBD_CDC_GetFSCfgDesc (uint16_t *length)
|
|
||||||
+uint8_t *USBD_CDC_GetFSCfgDesc (uint16_t *length)
|
|
||||||
{
|
|
||||||
*length = sizeof (USBD_CDC_CfgFSDesc);
|
|
||||||
return USBD_CDC_CfgFSDesc;
|
|
||||||
@@ -750,7 +731,7 @@
|
|
||||||
* @param length : pointer data length
|
|
||||||
* @retval pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
-static uint8_t *USBD_CDC_GetHSCfgDesc (uint16_t *length)
|
|
||||||
+uint8_t *USBD_CDC_GetHSCfgDesc (uint16_t *length)
|
|
||||||
{
|
|
||||||
*length = sizeof (USBD_CDC_CfgHSDesc);
|
|
||||||
return USBD_CDC_CfgHSDesc;
|
|
||||||
@@ -763,7 +744,7 @@
|
|
||||||
* @param length : pointer data length
|
|
||||||
* @retval pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
-static uint8_t *USBD_CDC_GetOtherSpeedCfgDesc (uint16_t *length)
|
|
||||||
+uint8_t *USBD_CDC_GetOtherSpeedCfgDesc (uint16_t *length)
|
|
||||||
{
|
|
||||||
*length = sizeof (USBD_CDC_OtherSpeedCfgDesc);
|
|
||||||
return USBD_CDC_OtherSpeedCfgDesc;
|
|
||||||
@@ -780,6 +761,7 @@
|
|
||||||
*length = sizeof (USBD_CDC_DeviceQualifierDesc);
|
|
||||||
return USBD_CDC_DeviceQualifierDesc;
|
|
||||||
}
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_CDC_RegisterInterface
|
|
||||||
@@ -794,7 +776,7 @@
|
|
||||||
|
|
||||||
if(fops != NULL)
|
|
||||||
{
|
|
||||||
- pdev->pUserData= fops;
|
|
||||||
+ pdev->pUserData2= fops;
|
|
||||||
ret = USBD_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -811,7 +793,7 @@
|
|
||||||
uint8_t *pbuff,
|
|
||||||
uint16_t length)
|
|
||||||
{
|
|
||||||
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
|
|
||||||
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
|
|
||||||
|
|
||||||
hcdc->TxBuffer = pbuff;
|
|
||||||
hcdc->TxLength = length;
|
|
||||||
@@ -829,7 +811,7 @@
|
|
||||||
uint8_t USBD_CDC_SetRxBuffer (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t *pbuff)
|
|
||||||
{
|
|
||||||
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
|
|
||||||
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
|
|
||||||
|
|
||||||
hcdc->RxBuffer = pbuff;
|
|
||||||
|
|
||||||
@@ -845,9 +827,9 @@
|
|
||||||
*/
|
|
||||||
uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev)
|
|
||||||
{
|
|
||||||
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
|
|
||||||
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
|
|
||||||
|
|
||||||
- if(pdev->pClassData != NULL)
|
|
||||||
+ if(pdev->pClassData2 != NULL)
|
|
||||||
{
|
|
||||||
if(hcdc->TxState == 0)
|
|
||||||
{
|
|
||||||
@@ -882,10 +864,10 @@
|
|
||||||
*/
|
|
||||||
uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev)
|
|
||||||
{
|
|
||||||
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
|
|
||||||
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
|
|
||||||
|
|
||||||
/* Suspend or Resume USB Out process */
|
|
||||||
- if(pdev->pClassData != NULL)
|
|
||||||
+ if(pdev->pClassData2 != NULL)
|
|
||||||
{
|
|
||||||
if(pdev->dev_speed == USBD_SPEED_HIGH )
|
|
||||||
{
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
--- Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc.h (date 1511202099000)
|
|
||||||
+++ Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc.h (revision )
|
|
||||||
@@ -58,9 +58,10 @@
|
|
||||||
#define BOT_RESET 0xFF
|
|
||||||
#define USB_MSC_CONFIG_DESC_SIZ 32
|
|
||||||
|
|
||||||
-
|
|
||||||
+#ifndef MSC_CUSTOM_EPS
|
|
||||||
#define MSC_EPIN_ADDR 0x81
|
|
||||||
-#define MSC_EPOUT_ADDR 0x01
|
|
||||||
+#define MSC_EPOUT_ADDR 0x01
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
@@ -107,7 +108,7 @@
|
|
||||||
USBD_MSC_BOT_HandleTypeDef;
|
|
||||||
|
|
||||||
/* Structure for MSC process */
|
|
||||||
-extern USBD_ClassTypeDef USBD_MSC;
|
|
||||||
+extern USBD_ClassTypeDef USBD_MSC;
|
|
||||||
#define USBD_MSC_CLASS &USBD_MSC
|
|
||||||
|
|
||||||
uint8_t USBD_MSC_RegisterStorage (USBD_HandleTypeDef *pdev,
|
|
||||||
@@ -118,8 +119,34 @@
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
- */
|
|
||||||
+ */
|
|
||||||
|
|
||||||
+// XXX "static" moved here for use in composite driver
|
|
||||||
+
|
|
||||||
+uint8_t USBD_MSC_Init (USBD_HandleTypeDef *pdev,
|
|
||||||
+ uint8_t cfgidx);
|
|
||||||
+
|
|
||||||
+uint8_t USBD_MSC_DeInit (USBD_HandleTypeDef *pdev,
|
|
||||||
+ uint8_t cfgidx);
|
|
||||||
+
|
|
||||||
+uint8_t USBD_MSC_Setup (USBD_HandleTypeDef *pdev,
|
|
||||||
+ USBD_SetupReqTypedef *req);
|
|
||||||
+
|
|
||||||
+uint8_t USBD_MSC_DataIn (USBD_HandleTypeDef *pdev,
|
|
||||||
+ uint8_t epnum);
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+uint8_t USBD_MSC_DataOut (USBD_HandleTypeDef *pdev,
|
|
||||||
+ uint8_t epnum);
|
|
||||||
+
|
|
||||||
+uint8_t *USBD_MSC_GetHSCfgDesc (uint16_t *length);
|
|
||||||
+
|
|
||||||
+uint8_t *USBD_MSC_GetFSCfgDesc (uint16_t *length);
|
|
||||||
+
|
|
||||||
+uint8_t *USBD_MSC_GetOtherSpeedCfgDesc (uint16_t *length);
|
|
||||||
+
|
|
||||||
+uint8_t *USBD_MSC_GetDeviceQualifierDescriptor (uint16_t *length);
|
|
||||||
+
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
--- Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc.c (date 1511202099000)
|
|
||||||
+++ Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc.c (revision )
|
|
||||||
@@ -116,7 +116,7 @@
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
-
|
|
||||||
+#ifndef MSC_COMPOSITE
|
|
||||||
USBD_ClassTypeDef USBD_MSC =
|
|
||||||
{
|
|
||||||
USBD_MSC_Init,
|
|
||||||
@@ -279,6 +279,7 @@
|
|
||||||
0x01,
|
|
||||||
0x00,
|
|
||||||
};
|
|
||||||
+#endif
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
@@ -530,6 +531,7 @@
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
+#ifndef MSC_COMPOSITE
|
|
||||||
/**
|
|
||||||
* @brief USBD_MSC_GetHSCfgDesc
|
|
||||||
* return configuration descriptor
|
|
||||||
@@ -576,6 +578,7 @@
|
|
||||||
*length = sizeof (USBD_MSC_DeviceQualifierDesc);
|
|
||||||
return USBD_MSC_DeviceQualifierDesc;
|
|
||||||
}
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_MSC_RegisterStorage
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
--- Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_scsi.c (date 1511202099000)
|
|
||||||
+++ Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_scsi.c (revision )
|
|
||||||
@@ -190,14 +190,27 @@
|
|
||||||
INVALID_CDB);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
-
|
|
||||||
- if(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
|
|
||||||
+
|
|
||||||
+ // XXX THIS SECTION IS MODIFIED FOR NOTIFY!
|
|
||||||
+ // https://www.microchip.com/forums/m401735.aspx
|
|
||||||
+ int8_t changeStatus = ((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun);
|
|
||||||
+ if(changeStatus != 0)
|
|
||||||
{
|
|
||||||
- SCSI_SenseCode(pdev,
|
|
||||||
- lun,
|
|
||||||
- NOT_READY,
|
|
||||||
- MEDIUM_NOT_PRESENT);
|
|
||||||
-
|
|
||||||
+ if (changeStatus == -1)
|
|
||||||
+ {
|
|
||||||
+ SCSI_SenseCode(pdev,
|
|
||||||
+ lun,
|
|
||||||
+ UNIT_ATTENTION,
|
|
||||||
+ MEDIUM_HAVE_CHANGED);
|
|
||||||
+ }
|
|
||||||
+ else
|
|
||||||
+ {
|
|
||||||
+ SCSI_SenseCode(pdev,
|
|
||||||
+ lun,
|
|
||||||
+ NOT_READY,
|
|
||||||
+ MEDIUM_NOT_PRESENT);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
hmsc->bot_state = USBD_BOT_NO_DATA;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
@@ -25,8 +25,8 @@ __ALIGN_BEGIN uint8_t USBD_MSC_CDC_CfgFSDesc[USBD_MSC_CDC_CONFIG_DESC_SIZ] __AL
|
|||||||
3, /* bNumInterfaces - 1 MSC + 2 composite CDC ACM */
|
3, /* bNumInterfaces - 1 MSC + 2 composite CDC ACM */
|
||||||
0x01, /* bConfigurationValue: */
|
0x01, /* bConfigurationValue: */
|
||||||
0, /* iConfiguration: - string descriptor */
|
0, /* iConfiguration: - string descriptor */
|
||||||
0xC0, /* bmAttributes: - self powered */
|
0x80, /* bmAttributes: - bus powered */
|
||||||
150, /* MaxPower 300 mA */
|
250, /* MaxPower 500 mA */
|
||||||
|
|
||||||
/******************** Mass Storage interface ********************/
|
/******************** Mass Storage interface ********************/
|
||||||
/*9*/ 0x09, /* bLength: Interface Descriptor size */
|
/*9*/ 0x09, /* bLength: Interface Descriptor size */
|
||||||
@@ -63,7 +63,7 @@ __ALIGN_BEGIN uint8_t USBD_MSC_CDC_CfgFSDesc[USBD_MSC_CDC_CONFIG_DESC_SIZ] __AL
|
|||||||
0x02, /* bInterfaceCount */
|
0x02, /* bInterfaceCount */
|
||||||
0x02, /* bFunctionClass */ // #36
|
0x02, /* bFunctionClass */ // #36
|
||||||
0x02, /* bFunctionSubClass (ACM) */
|
0x02, /* bFunctionSubClass (ACM) */
|
||||||
0x01, /* bFunctionProtocol (AT-COMMANDS) */
|
0x01, /* bFunctionProtocol (AT-COMMANDS - we don't implement this but it's a good default) */
|
||||||
0x05, /* iFunction: string descriptor */
|
0x05, /* iFunction: string descriptor */
|
||||||
|
|
||||||
/********************** ACM interface **********************/
|
/********************** ACM interface **********************/
|
||||||
@@ -131,7 +131,7 @@ __ALIGN_BEGIN uint8_t USBD_MSC_CDC_CfgFSDesc[USBD_MSC_CDC_CONFIG_DESC_SIZ] __AL
|
|||||||
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
||||||
CDC_OUT_EP, /* bEndpointAddress */
|
CDC_OUT_EP, /* bEndpointAddress */
|
||||||
0x02, /* bmAttributes: Bulk */
|
0x02, /* bmAttributes: Bulk */
|
||||||
LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: TODO 8? */
|
LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize */
|
||||||
HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
|
HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
|
||||||
0x00, /* bInterval: ignore for Bulk transfer */
|
0x00, /* bInterval: ignore for Bulk transfer */
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@ __ALIGN_BEGIN uint8_t USBD_MSC_CDC_CfgFSDesc[USBD_MSC_CDC_CONFIG_DESC_SIZ] __AL
|
|||||||
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
||||||
CDC_IN_EP, /* bEndpointAddress */
|
CDC_IN_EP, /* bEndpointAddress */
|
||||||
0x02, /* bmAttributes: Bulk */
|
0x02, /* bmAttributes: Bulk */
|
||||||
LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: TODO 16? */
|
LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize */
|
||||||
HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
|
HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
|
||||||
0x00 /* bInterval: ignore for Bulk transfer */
|
0x00 /* bInterval: ignore for Bulk transfer */
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -265,8 +265,8 @@ typedef struct _USBD_HandleTypeDef
|
|||||||
#define SWAPBYTE(addr) (((uint16_t)(*((uint8_t *)(addr)))) + \
|
#define SWAPBYTE(addr) (((uint16_t)(*((uint8_t *)(addr)))) + \
|
||||||
(((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8))
|
(((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8))
|
||||||
|
|
||||||
#define LOBYTE(x) ((uint8_t)(x & 0x00FF))
|
#define LOBYTE(x) ((uint8_t)((x) & 0x00FF))
|
||||||
#define HIBYTE(x) ((uint8_t)((x & 0xFF00) >>8))
|
#define HIBYTE(x) ((uint8_t)(((x) & 0xFF00) >>8))
|
||||||
|
|
||||||
#ifndef MIN
|
#ifndef MIN
|
||||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
--- Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h (date 1511202099000)
|
|
||||||
+++ Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h (revision )
|
|
||||||
@@ -99,6 +99,7 @@
|
|
||||||
#define USB_DESC_TYPE_ENDPOINT 5
|
|
||||||
#define USB_DESC_TYPE_DEVICE_QUALIFIER 6
|
|
||||||
#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 7
|
|
||||||
+#define USB_DESC_TYPE_IFACE_ASSOCIATION 11
|
|
||||||
#define USB_DESC_TYPE_BOS 0x0F
|
|
||||||
|
|
||||||
#define USB_CONFIG_REMOTE_WAKEUP 2
|
|
||||||
@@ -147,7 +148,7 @@
|
|
||||||
|
|
||||||
typedef struct usb_setup_req
|
|
||||||
{
|
|
||||||
-
|
|
||||||
+
|
|
||||||
uint8_t bmRequest;
|
|
||||||
uint8_t bRequest;
|
|
||||||
uint16_t wValue;
|
|
||||||
@@ -230,7 +231,7 @@
|
|
||||||
uint32_t dev_config_status;
|
|
||||||
USBD_SpeedTypeDef dev_speed;
|
|
||||||
USBD_EndpointTypeDef ep_in[15];
|
|
||||||
- USBD_EndpointTypeDef ep_out[15];
|
|
||||||
+ USBD_EndpointTypeDef ep_out[15];
|
|
||||||
uint32_t ep0_state;
|
|
||||||
uint32_t ep0_data_len;
|
|
||||||
uint8_t dev_state;
|
|
||||||
@@ -242,10 +243,14 @@
|
|
||||||
|
|
||||||
USBD_SetupReqTypedef request;
|
|
||||||
USBD_DescriptorsTypeDef *pDesc;
|
|
||||||
- USBD_ClassTypeDef *pClass;
|
|
||||||
- void *pClassData;
|
|
||||||
- void *pUserData;
|
|
||||||
- void *pData;
|
|
||||||
+ USBD_ClassTypeDef *pClass; // the composite class
|
|
||||||
+ void *pClassData;
|
|
||||||
+ void *pUserData;
|
|
||||||
+ void *pClassData2; // used for secondary class
|
|
||||||
+ void *pUserData2; // used for secondary class
|
|
||||||
+ void *pClassData3; // used for tertiary class
|
|
||||||
+ void *pUserData3; // used for tertiary class
|
|
||||||
+ void *pData; // this is a pointer to the low level registers struct
|
|
||||||
} USBD_HandleTypeDef;
|
|
||||||
|
|
||||||
/**
|
|
||||||
@@ -262,8 +267,14 @@
|
|
||||||
|
|
||||||
#define LOBYTE(x) ((uint8_t)(x & 0x00FF))
|
|
||||||
#define HIBYTE(x) ((uint8_t)((x & 0xFF00) >>8))
|
|
||||||
+
|
|
||||||
+#ifndef MIN
|
|
||||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+#ifndef MAX
|
|
||||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if defined ( __GNUC__ )
|
|
||||||
@@ -66,6 +66,7 @@ PCD_HandleTypeDef hpcd_USB_FS;
|
|||||||
/* init function */
|
/* init function */
|
||||||
void MX_USB_DEVICE_Init(void)
|
void MX_USB_DEVICE_Init(void)
|
||||||
{
|
{
|
||||||
|
dbg("USB device init ...");
|
||||||
/* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */
|
/* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */
|
||||||
|
|
||||||
/* USER CODE END USB_DEVICE_Init_PreTreatment */
|
/* USER CODE END USB_DEVICE_Init_PreTreatment */
|
||||||
|
|||||||
+1
-1
@@ -314,7 +314,7 @@ void USBD_CDC_TransmitDone(USBD_HandleTypeDef *pdev)
|
|||||||
assert_param(inIRQ());
|
assert_param(inIRQ());
|
||||||
|
|
||||||
portBASE_TYPE taskWoken = pdFALSE;
|
portBASE_TYPE taskWoken = pdFALSE;
|
||||||
assert_param(xSemaphoreGiveFromISR(semVcomTxReadyHandle, &taskWoken) == pdTRUE);
|
assert_param(pdTRUE == xSemaphoreGiveFromISR(semVcomTxReadyHandle, &taskWoken));
|
||||||
portYIELD_FROM_ISR(taskWoken);
|
portYIELD_FROM_ISR(taskWoken);
|
||||||
}
|
}
|
||||||
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */
|
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */
|
||||||
|
|||||||
+7
-6
@@ -84,13 +84,14 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle)
|
|||||||
__HAL_RCC_USB_CLK_ENABLE();
|
__HAL_RCC_USB_CLK_ENABLE();
|
||||||
|
|
||||||
/* Peripheral interrupt init */
|
/* Peripheral interrupt init */
|
||||||
#if defined(GEX_PLAT_F103_BLUEPILL)
|
// TODO convert this to feature flags if possible - avoid tying to particular platforms
|
||||||
|
#if GEX_PLAT_F103
|
||||||
HAL_NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, 5, 0);
|
HAL_NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, 5, 0);
|
||||||
HAL_NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
|
HAL_NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
|
||||||
#elif defined(GEX_PLAT_F072_DISCOVERY)
|
#elif GEX_PLAT_F072
|
||||||
HAL_NVIC_SetPriority(USB_IRQn, 3, 0);
|
HAL_NVIC_SetPriority(USB_IRQn, 3, 0);
|
||||||
HAL_NVIC_EnableIRQ(USB_IRQn);
|
HAL_NVIC_EnableIRQ(USB_IRQn);
|
||||||
#elif defined(GEX_PLAT_F303_DISCOVERY)
|
#elif GEX_PLAT_F303
|
||||||
// Pins need to be configured here
|
// Pins need to be configured here
|
||||||
|
|
||||||
/**USB GPIO Configuration
|
/**USB GPIO Configuration
|
||||||
@@ -149,11 +150,11 @@ void HAL_PCD_MspDeInit(PCD_HandleTypeDef* pcdHandle)
|
|||||||
__HAL_RCC_USB_CLK_DISABLE();
|
__HAL_RCC_USB_CLK_DISABLE();
|
||||||
|
|
||||||
/* Peripheral interrupt Deinit*/
|
/* Peripheral interrupt Deinit*/
|
||||||
#if defined(GEX_PLAT_F103_BLUEPILL)
|
#if GEX_PLAT_F103
|
||||||
HAL_NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
|
HAL_NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
|
||||||
#elif defined(GEX_PLAT_F072_DISCOVERY)
|
#elif GEX_PLAT_F072
|
||||||
HAL_NVIC_DisableIRQ(USB_IRQn);
|
HAL_NVIC_DisableIRQ(USB_IRQn);
|
||||||
#elif defined(GEX_PLAT_F303_DISCOVERY)
|
#elif GEX_PLAT_F303
|
||||||
HAL_NVIC_DisableIRQ(USB_LP_CAN_RX0_IRQn);
|
HAL_NVIC_DisableIRQ(USB_LP_CAN_RX0_IRQn);
|
||||||
#else
|
#else
|
||||||
#error "BAD PLATFORM"
|
#error "BAD PLATFORM"
|
||||||
|
|||||||
+3
-3
@@ -72,11 +72,11 @@
|
|||||||
/** @defgroup USBD_DESC_Private_Defines
|
/** @defgroup USBD_DESC_Private_Defines
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
#define USBD_VID 1155 // TODO choose a VID:PID (eg. via pid.codes - 0x1209)
|
#define USBD_VID 0x1209
|
||||||
#define USBD_PID_FS 22314
|
#define USBD_PID_FS 0x4c60
|
||||||
#define USBD_LANGID_NUM 1033
|
#define USBD_LANGID_NUM 1033
|
||||||
#define USBD_MANUFACTURER_STRING "MightyPork"
|
#define USBD_MANUFACTURER_STRING "MightyPork"
|
||||||
#define USBD_PRODUCT_STRING_FS "GEX"
|
#define USBD_PRODUCT_STRING_FS "GEX USB module"
|
||||||
#define USBD_VERSION_NUM 0x0001 // 0xMMmp
|
#define USBD_VERSION_NUM 0x0001 // 0xMMmp
|
||||||
//#define USBD_SERIALNUMBER_STRING_FS "00000000001A"
|
//#define USBD_SERIALNUMBER_STRING_FS "00000000001A"
|
||||||
//#define USBD_CONFIGURATION_STRING_FS "MSC Config"
|
//#define USBD_CONFIGURATION_STRING_FS "MSC Config"
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ USBD_StorageTypeDef USBD_Storage_Interface_fops_FS =
|
|||||||
int8_t STORAGE_Init_FS (uint8_t lun)
|
int8_t STORAGE_Init_FS (uint8_t lun)
|
||||||
{
|
{
|
||||||
/* USER CODE BEGIN 2 */
|
/* USER CODE BEGIN 2 */
|
||||||
dbg("Plug In");
|
dbg("MSC init request");
|
||||||
vfs_mngr_fs_enable(1);
|
vfs_mngr_fs_enable(1);
|
||||||
return (USBD_OK);
|
return (USBD_OK);
|
||||||
/* USER CODE END 2 */
|
/* USER CODE END 2 */
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
// Created by MightyPork on 2018/01/27.
|
// Created by MightyPork on 2018/01/27.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef GEX_F072_EVENT_REPORTS_H
|
#ifndef GEX_CORE_EVENT_REPORTS_H
|
||||||
#define GEX_F072_EVENT_REPORTS_H
|
#define GEX_CORE_EVENT_REPORTS_H
|
||||||
|
|
||||||
#ifndef GEX_MESSAGES_H
|
#ifndef GEX_MESSAGES_H
|
||||||
#error "Include messages.h instead!"
|
#error "Include messages.h instead!"
|
||||||
@@ -31,4 +31,4 @@ void EventReport_Data(const uint8_t *buff, uint16_t len);
|
|||||||
void EventReport_PB(PayloadBuilder *pb);
|
void EventReport_PB(PayloadBuilder *pb);
|
||||||
void EventReport_End(void);
|
void EventReport_End(void);
|
||||||
|
|
||||||
#endif //GEX_F072_EVENT_REPORTS_H
|
#endif //GEX_CORE_EVENT_REPORTS_H
|
||||||
|
|||||||
@@ -0,0 +1,192 @@
|
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/04/06.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#if SUPPORT_NRF
|
||||||
|
|
||||||
|
#include "iface_nordic.h"
|
||||||
|
#include "nrf_pins.h"
|
||||||
|
#include "resources.h"
|
||||||
|
#include "hw_utils.h"
|
||||||
|
#include "nrf.h"
|
||||||
|
#include "unit_base.h"
|
||||||
|
#include "system_settings.h"
|
||||||
|
#include "utils/hexdump.h"
|
||||||
|
|
||||||
|
|
||||||
|
extern osSemaphoreId semVcomTxReadyHandle;
|
||||||
|
|
||||||
|
#define RX_PIPE_NUM 0
|
||||||
|
|
||||||
|
void iface_nordic_claim_resources(void)
|
||||||
|
{
|
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, NRF_R_SPI));
|
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, NRF_R_CE));
|
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, NRF_R_NSS));
|
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, NRF_R_IRQ));
|
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, NRF_R_MISO));
|
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, NRF_R_MOSI));
|
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, NRF_R_SCK));
|
||||||
|
|
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, R_EXTI0+NRF_EXTI_LINENUM));
|
||||||
|
}
|
||||||
|
|
||||||
|
void iface_nordic_free_resources(void)
|
||||||
|
{
|
||||||
|
rsc_free(&UNIT_SYSTEM, NRF_R_SPI);
|
||||||
|
rsc_free(&UNIT_SYSTEM, NRF_R_CE);
|
||||||
|
rsc_free(&UNIT_SYSTEM, NRF_R_NSS);
|
||||||
|
rsc_free(&UNIT_SYSTEM, NRF_R_IRQ);
|
||||||
|
rsc_free(&UNIT_SYSTEM, NRF_R_MISO);
|
||||||
|
rsc_free(&UNIT_SYSTEM, NRF_R_MOSI);
|
||||||
|
rsc_free(&UNIT_SYSTEM, NRF_R_SCK);
|
||||||
|
|
||||||
|
rsc_free(&UNIT_SYSTEM, R_EXTI0+NRF_EXTI_LINENUM);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t rx_buffer[32];
|
||||||
|
|
||||||
|
static void NrfIrqHandler(void *arg)
|
||||||
|
{
|
||||||
|
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINES[NRF_EXTI_LINENUM]);
|
||||||
|
dbg_nrf("[EXTI] ---");
|
||||||
|
|
||||||
|
while (NRF_IsRxPacket()) {
|
||||||
|
uint8_t pipenum;
|
||||||
|
uint8_t count = NRF_ReceivePacket(rx_buffer, &pipenum);
|
||||||
|
if (count > 0) {
|
||||||
|
dbg_nrf("NRF RX %d bytes", (int) count);
|
||||||
|
rxQuePostMsg(rx_buffer, count);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dbg("IRQ but no Rx");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg_nrf("--- end [EXTI]");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool iface_nordic_init(void)
|
||||||
|
{
|
||||||
|
dbg("Setting up Nordic...");
|
||||||
|
|
||||||
|
hw_periph_clock_enable(NRF_SPI);
|
||||||
|
|
||||||
|
// SPI pins
|
||||||
|
assert_param(E_SUCCESS == hw_configure_gpiorsc_af(NRF_R_SCK, NRF_SCK_AF));
|
||||||
|
assert_param(E_SUCCESS == hw_configure_gpiorsc_af(NRF_R_MOSI, NRF_MOSI_AF));
|
||||||
|
assert_param(E_SUCCESS == hw_configure_gpiorsc_af(NRF_R_MISO, NRF_MISO_AF));
|
||||||
|
|
||||||
|
// Manual pins
|
||||||
|
LL_GPIO_SetPinMode(NRF_NSS_GPIO_Port, NRF_NSS_Pin, LL_GPIO_MODE_OUTPUT);
|
||||||
|
LL_GPIO_SetPinMode(NRF_CE_GPIO_Port, NRF_CE_Pin, LL_GPIO_MODE_OUTPUT);
|
||||||
|
LL_GPIO_SetPinMode(NRF_RST_GPIO_Port, NRF_RST_Pin, LL_GPIO_MODE_OUTPUT);
|
||||||
|
LL_GPIO_SetPinMode(NRF_IRQ_GPIO_Port, NRF_IRQ_Pin, LL_GPIO_MODE_INPUT);
|
||||||
|
|
||||||
|
// set up SPI
|
||||||
|
LL_SPI_Disable(NRF_SPI);
|
||||||
|
{
|
||||||
|
LL_SPI_SetBaudRatePrescaler(NRF_SPI, LL_SPI_BAUDRATEPRESCALER_DIV32);
|
||||||
|
//LL_SPI_BAUDRATEPRESCALER_DIV8
|
||||||
|
|
||||||
|
LL_SPI_SetClockPolarity(NRF_SPI, LL_SPI_POLARITY_LOW);
|
||||||
|
LL_SPI_SetClockPhase(NRF_SPI, LL_SPI_PHASE_1EDGE);
|
||||||
|
LL_SPI_SetTransferDirection(NRF_SPI, LL_SPI_FULL_DUPLEX);
|
||||||
|
LL_SPI_SetTransferBitOrder(NRF_SPI, LL_SPI_MSB_FIRST);
|
||||||
|
|
||||||
|
LL_SPI_SetNSSMode(NRF_SPI, LL_SPI_NSS_SOFT);
|
||||||
|
LL_SPI_SetDataWidth(NRF_SPI, LL_SPI_DATAWIDTH_8BIT);
|
||||||
|
LL_SPI_SetRxFIFOThreshold(NRF_SPI, LL_SPI_RX_FIFO_TH_QUARTER); // trigger RXNE on 1 byte
|
||||||
|
|
||||||
|
LL_SPI_SetMode(NRF_SPI, LL_SPI_MODE_MASTER);
|
||||||
|
}
|
||||||
|
LL_SPI_Enable(NRF_SPI);
|
||||||
|
|
||||||
|
// reset the radio / enable its power supply
|
||||||
|
NRF_Reset(1);
|
||||||
|
LL_mDelay(5);
|
||||||
|
NRF_Reset(0);
|
||||||
|
|
||||||
|
dbg("configure nrf module");
|
||||||
|
|
||||||
|
// Now configure the radio
|
||||||
|
if (!NRF_Init(NRF_SPEED_2M)) {// TODO configurable speed - also maybe better to use slower
|
||||||
|
dbg("--- NRF not present!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NRF_SetChannel(SystemSettings.nrf_channel);
|
||||||
|
NRF_SetBaseAddress(SystemSettings.nrf_network);
|
||||||
|
NRF_SetRxAddress(RX_PIPE_NUM, SystemSettings.nrf_address);
|
||||||
|
NRF_EnablePipe(RX_PIPE_NUM);
|
||||||
|
NRF_ModeRX();
|
||||||
|
|
||||||
|
dbg("enable exti");
|
||||||
|
// EXTI
|
||||||
|
LL_EXTI_EnableIT_0_31(LL_EXTI_LINES[NRF_EXTI_LINENUM]);
|
||||||
|
LL_EXTI_EnableFallingTrig_0_31(LL_EXTI_LINES[NRF_EXTI_LINENUM]);
|
||||||
|
LL_SYSCFG_SetEXTISource(NRF_SYSCFG_EXTI_PORT, LL_SYSCFG_EXTI_LINES[NRF_EXTI_LINENUM]);
|
||||||
|
irqd_attach(EXTIS[NRF_EXTI_LINENUM], NrfIrqHandler, NULL);
|
||||||
|
// TODO increase priority in NVIC?
|
||||||
|
|
||||||
|
dbg("nrf setup done");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iface_nordic_deinit(void)
|
||||||
|
{
|
||||||
|
LL_EXTI_DisableIT_0_31(LL_EXTI_LINES[NRF_EXTI_LINENUM]);
|
||||||
|
LL_EXTI_DisableFallingTrig_0_31(LL_EXTI_LINES[NRF_EXTI_LINENUM]);
|
||||||
|
irqd_detach(EXTIS[NRF_EXTI_LINENUM], NrfIrqHandler);
|
||||||
|
hw_periph_clock_disable(NRF_SPI);
|
||||||
|
|
||||||
|
hw_deinit_pin_rsc(NRF_R_SCK);
|
||||||
|
hw_deinit_pin_rsc(NRF_R_MOSI);
|
||||||
|
hw_deinit_pin_rsc(NRF_R_MISO);
|
||||||
|
hw_deinit_pin_rsc(NRF_R_NSS);
|
||||||
|
hw_deinit_pin_rsc(NRF_R_CE);
|
||||||
|
hw_deinit_pin_rsc(NRF_R_IRQ);
|
||||||
|
hw_deinit_pin_rsc(NRF_R_RST);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
#define MAX_RETRY 5
|
||||||
|
|
||||||
|
void iface_nordic_transmit(const uint8_t *buff, uint32_t len)
|
||||||
|
{
|
||||||
|
bool suc = false;
|
||||||
|
while (len > 0) {
|
||||||
|
uint8_t chunk = (uint8_t) MIN(32, len);
|
||||||
|
|
||||||
|
uint16_t delay = 1;
|
||||||
|
//hexDump("Tx chunk", buff, chunk);
|
||||||
|
for (int i = 0; i < MAX_RETRY; i++) {
|
||||||
|
suc = NRF_SendPacket(RX_PIPE_NUM, buff, chunk); // use the pipe to retrieve the address
|
||||||
|
if (!suc) {
|
||||||
|
vTaskDelay(delay);
|
||||||
|
delay *= 2; // longer delay next time
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!suc) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buff += chunk;
|
||||||
|
len -= chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (suc) {
|
||||||
|
dbg_nrf("+ NRF Tx OK!");
|
||||||
|
} else {
|
||||||
|
dbg("- NRF sending failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// give when it's done
|
||||||
|
xSemaphoreGive(semVcomTxReadyHandle); // similar to how it's done in USB - this is called in the Tx Done handler
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SUPPORT_NRF
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/04/06.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GEX_CORE_IFACE_NORDIC_H
|
||||||
|
#define GEX_CORE_IFACE_NORDIC_H
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#if SUPPORT_NRF
|
||||||
|
|
||||||
|
void iface_nordic_claim_resources(void);
|
||||||
|
|
||||||
|
void iface_nordic_free_resources(void);
|
||||||
|
|
||||||
|
void iface_nordic_deinit(void);
|
||||||
|
|
||||||
|
bool iface_nordic_init(void);
|
||||||
|
|
||||||
|
void iface_nordic_transmit(const uint8_t *buff, uint32_t len);
|
||||||
|
|
||||||
|
#endif // SUPPORT_NRF
|
||||||
|
|
||||||
|
#endif //GEX_CORE_IFACE_NORDIC_H
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/04/06.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#include "iface_uart.h"
|
||||||
|
#include "resources.h"
|
||||||
|
#include "hw_utils.h"
|
||||||
|
#include "irq_dispatcher.h"
|
||||||
|
#include "task_msg.h"
|
||||||
|
#include "system_settings.h"
|
||||||
|
|
||||||
|
extern osSemaphoreId semVcomTxReadyHandle;
|
||||||
|
|
||||||
|
static uint32_t usart_rxi = 0;
|
||||||
|
static uint8_t usart_rx_buffer[MSG_QUE_SLOT_SIZE];
|
||||||
|
static uint32_t last_rx_time = 0;
|
||||||
|
|
||||||
|
void iface_uart_claim_resources(void)
|
||||||
|
{
|
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, R_USART2));
|
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, R_PA2));
|
||||||
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, R_PA3));
|
||||||
|
}
|
||||||
|
|
||||||
|
void iface_uart_free_resources(void)
|
||||||
|
{
|
||||||
|
rsc_free(&UNIT_SYSTEM, R_USART2);
|
||||||
|
rsc_free(&UNIT_SYSTEM, R_PA2);
|
||||||
|
rsc_free(&UNIT_SYSTEM, R_PA3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Handler for the USART transport */
|
||||||
|
static void com_UsartIrqHandler(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
if (LL_USART_IsActiveFlag_RXNE(USART2)) {
|
||||||
|
vPortEnterCritical();
|
||||||
|
{
|
||||||
|
usart_rx_buffer[usart_rxi++] = LL_USART_ReceiveData8(USART2);
|
||||||
|
if (usart_rxi == MSG_QUE_SLOT_SIZE) {
|
||||||
|
rxQuePostMsg(usart_rx_buffer, MSG_QUE_SLOT_SIZE); // avoid it happening in the irq
|
||||||
|
usart_rxi = 0;
|
||||||
|
}
|
||||||
|
last_rx_time = HAL_GetTick();
|
||||||
|
}
|
||||||
|
vPortExitCritical();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** this is called from the hal tick irq */
|
||||||
|
void com_iface_flush_buffer(void)
|
||||||
|
{
|
||||||
|
if (usart_rxi > 0 && (HAL_GetTick()-last_rx_time)>=2) {
|
||||||
|
vPortEnterCritical();
|
||||||
|
{
|
||||||
|
rxQuePostMsg(usart_rx_buffer, usart_rxi);
|
||||||
|
usart_rxi = 0;
|
||||||
|
}
|
||||||
|
vPortExitCritical();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool iface_uart_init(void)
|
||||||
|
{
|
||||||
|
dbg("Setting up UART transfer");
|
||||||
|
assert_param(E_SUCCESS == hw_configure_gpiorsc_af(R_PA2, LL_GPIO_AF_1));
|
||||||
|
assert_param(E_SUCCESS == hw_configure_gpiorsc_af(R_PA3, LL_GPIO_AF_1));
|
||||||
|
|
||||||
|
__HAL_RCC_USART2_CLK_ENABLE();
|
||||||
|
__HAL_RCC_USART2_FORCE_RESET();
|
||||||
|
__HAL_RCC_USART2_RELEASE_RESET();
|
||||||
|
|
||||||
|
LL_USART_Disable(USART2);
|
||||||
|
|
||||||
|
LL_USART_SetBaudRate(USART2, PLAT_APB1_HZ, LL_USART_OVERSAMPLING_16, SystemSettings.comm_uart_baud);
|
||||||
|
dbg("baud = %d", (int)SystemSettings.comm_uart_baud);
|
||||||
|
|
||||||
|
irqd_attach(USART2, com_UsartIrqHandler, NULL);
|
||||||
|
LL_USART_EnableIT_RXNE(USART2);
|
||||||
|
LL_USART_SetTransferDirection(USART2, LL_USART_DIRECTION_TX_RX);
|
||||||
|
|
||||||
|
LL_USART_Enable(USART2);
|
||||||
|
|
||||||
|
return true; // always OK (TODO check voltage on Rx if it's 3V3 when idle?)
|
||||||
|
}
|
||||||
|
|
||||||
|
void iface_uart_deinit(void)
|
||||||
|
{
|
||||||
|
// this doesn't normally happen
|
||||||
|
hw_deinit_pin_rsc(R_PA2);
|
||||||
|
hw_deinit_pin_rsc(R_PA3);
|
||||||
|
__HAL_RCC_USART2_CLK_DISABLE();
|
||||||
|
irqd_detach(USART2, com_UsartIrqHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void iface_uart_transmit(const uint8_t *buff, uint32_t len)
|
||||||
|
{
|
||||||
|
// TODO rewrite this to use DMA, then wait for the DMA
|
||||||
|
for(uint32_t i=0;i<len;i++) {
|
||||||
|
while(!LL_USART_IsActiveFlag_TXE(USART2));
|
||||||
|
LL_USART_TransmitData8(USART2, buff[i]);
|
||||||
|
}
|
||||||
|
xSemaphoreGive(semVcomTxReadyHandle); // act as if we just finished it and this is perhaps the DMA irq
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/04/06.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GEX_CORE_IFACE_UART_H
|
||||||
|
#define GEX_CORE_IFACE_UART_H
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
void com_iface_flush_buffer(void);
|
||||||
|
|
||||||
|
void iface_uart_deinit(void);
|
||||||
|
bool iface_uart_init(void);
|
||||||
|
|
||||||
|
void iface_uart_free_resources(void);
|
||||||
|
void iface_uart_claim_resources(void);
|
||||||
|
|
||||||
|
void iface_uart_transmit(const uint8_t *buff, uint32_t len);
|
||||||
|
|
||||||
|
#endif //GEX_CORE_IFACE_UART_H
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/04/06.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "iface_usb.h"
|
||||||
|
#include "TinyFrame.h"
|
||||||
|
#include "system_settings.h"
|
||||||
|
#include "USB/usb_device.h"
|
||||||
|
|
||||||
|
extern osSemaphoreId semVcomTxReadyHandle;
|
||||||
|
extern osMutexId mutTinyFrameTxHandle;
|
||||||
|
|
||||||
|
bool iface_usb_ready(void)
|
||||||
|
{
|
||||||
|
return 0 != (USB->DADDR & USB_DADDR_ADD);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* USB transmit implementation
|
||||||
|
*
|
||||||
|
* @param buff - buffer to send (can be longer than the buffers)
|
||||||
|
* @param len - buffer size
|
||||||
|
*/
|
||||||
|
void iface_usb_transmit(const uint8_t *buff, uint32_t len)
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
const uint32_t real_size = len;
|
||||||
|
|
||||||
|
// Padding to a multiple of 64 bytes - this is supposed to maximize the bulk transfer speed
|
||||||
|
if ((len&0x3F) && !SystemSettings.visible_vcom) { // this corrupts VCOM on Linux for some reason
|
||||||
|
uint32_t pad = (64 - (len&0x3F));
|
||||||
|
memset((void *) (buff + len), 0, pad);
|
||||||
|
len += pad; // padding to a multiple of 64 (size of the endpoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We bypass the USBD driver library's overhead by using the HAL function directly
|
||||||
|
assert_param(HAL_OK == HAL_PCD_EP_Transmit(hUsbDeviceFS.pData, CDC_IN_EP, (uint8_t *) buff, len));
|
||||||
|
|
||||||
|
// The buffer is the TF transmit buffer, we can't leave it to work asynchronously because
|
||||||
|
// the next call could modify it before it's been transmitted (in the case of a chunked / multi-part frame)
|
||||||
|
|
||||||
|
// If this is not the last chunk (assuming all but the last use full 512 bytes of the TF buffer), wait now for completion
|
||||||
|
if (real_size == TF_SENDBUF_LEN) {
|
||||||
|
// TODO this seems wrong - investigate
|
||||||
|
if (pdTRUE != xSemaphoreTake(semVcomTxReadyHandle, 100)) {
|
||||||
|
TF_Error("Tx stalled in WriteImpl");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
(void) tf;
|
||||||
|
#define CHUNK 64 // size of the USB packet
|
||||||
|
int32_t total = (int32_t) len;
|
||||||
|
while (total > 0) {
|
||||||
|
const int32_t mxStatus = osSemaphoreWait(semVcomTxReadyHandle, 100);
|
||||||
|
if (mxStatus != osOK) {
|
||||||
|
TF_Error("Tx stalled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint16_t chunksize = (uint16_t) MIN(total, CHUNK);
|
||||||
|
|
||||||
|
// this is an attempt to speed it up a little by removing a couple levels of indirection
|
||||||
|
assert_param(HAL_OK == HAL_PCD_EP_Transmit(hUsbDeviceFS.pData, CDC_IN_EP, (uint8_t *) buff, chunksize));
|
||||||
|
|
||||||
|
// USBD_LL_Transmit(&hUsbDeviceFS, CDC_IN_EP, (uint8_t *) buff, chunksize);
|
||||||
|
// assert_param(USBD_OK == CDC_Transmit_FS((uint8_t *) buff, chunksize));
|
||||||
|
|
||||||
|
buff += chunksize;
|
||||||
|
total -= chunksize;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/04/06.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GEX_CORE_IFACE_USB_H
|
||||||
|
#define GEX_CORE_IFACE_USB_H
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
bool iface_usb_ready(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* USB transmit implementation
|
||||||
|
*
|
||||||
|
* @param buff - buffer to send (can be longer than the buffers)
|
||||||
|
* @param len - buffer size
|
||||||
|
*/
|
||||||
|
void iface_usb_transmit(const uint8_t *buff, uint32_t len);
|
||||||
|
|
||||||
|
#endif //GEX_CORE_IFACE_USB_H
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/03/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#include "usbd_core.h"
|
||||||
|
#include "USB/usb_device.h"
|
||||||
|
#include "interfaces.h"
|
||||||
|
#include "framework/system_settings.h"
|
||||||
|
#include "framework/unit.h"
|
||||||
|
#include "framework/resources.h"
|
||||||
|
#include "platform/hw_utils.h"
|
||||||
|
#include "framework/unit_base.h"
|
||||||
|
#include "nrf_pins.h"
|
||||||
|
#include "iface_uart.h"
|
||||||
|
#include "iface_usb.h"
|
||||||
|
#include "iface_nordic.h"
|
||||||
|
|
||||||
|
// those correspond to the ENUM values
|
||||||
|
const char * COMPORT_NAMES[] = {
|
||||||
|
"NONE",
|
||||||
|
"USB",
|
||||||
|
"UART",
|
||||||
|
"NRF",
|
||||||
|
"LORA",
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ComportSelection gActiveComport = COMPORT_USB; // start with USB so the handlers work correctly initially
|
||||||
|
|
||||||
|
static uint32_t last_switch_time = 0; // started with USB
|
||||||
|
static bool xfer_verify_done = false;
|
||||||
|
|
||||||
|
static bool configure_interface(enum ComportSelection iface);
|
||||||
|
|
||||||
|
/** Switch com transfer if the current one doesnt seem to work */
|
||||||
|
void com_switch_transfer_if_needed(void)
|
||||||
|
{
|
||||||
|
if (xfer_verify_done) return;
|
||||||
|
|
||||||
|
const uint32_t now = HAL_GetTick();
|
||||||
|
const uint32_t elapsed = now - last_switch_time;
|
||||||
|
|
||||||
|
if (gActiveComport == COMPORT_USB) {
|
||||||
|
if (elapsed > 1000) {
|
||||||
|
// USB may or may not work, depending on whether the module is plugged in
|
||||||
|
// or running from a battery/external supply remotely.
|
||||||
|
|
||||||
|
// Check if USB is enumerated
|
||||||
|
|
||||||
|
if (!iface_usb_ready()) {
|
||||||
|
dbg("Not enumerated, assuming USB is dead");
|
||||||
|
|
||||||
|
// Fallback to radio or bare USART
|
||||||
|
do {
|
||||||
|
if (SystemSettings.use_comm_nordic) {
|
||||||
|
if (configure_interface(COMPORT_NORDIC)) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (SystemSettings.use_comm_lora) {
|
||||||
|
if (configure_interface(COMPORT_LORA)) break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (SystemSettings.use_comm_uart) {
|
||||||
|
// after nordic/lora
|
||||||
|
if (configure_interface(COMPORT_USART)) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg("No alternate com interface configured.");
|
||||||
|
gActiveComport = COMPORT_NONE;
|
||||||
|
} while (0);
|
||||||
|
} else {
|
||||||
|
dbg("USB got address - OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
xfer_verify_done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Claim resources that may be needed for alternate transfers */
|
||||||
|
void com_claim_resources_for_alt_transfers(void)
|
||||||
|
{
|
||||||
|
if (SystemSettings.use_comm_uart) {
|
||||||
|
iface_uart_claim_resources();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SUPPORT_NRF
|
||||||
|
if (SystemSettings.use_comm_nordic) {
|
||||||
|
iface_nordic_claim_resources();
|
||||||
|
}
|
||||||
|
#endif // SUPPORT_NRF
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Release resources allocated for alternate transfers */
|
||||||
|
void com_release_resources_for_alt_transfers(void)
|
||||||
|
{
|
||||||
|
if (SystemSettings.use_comm_uart) {
|
||||||
|
iface_uart_free_resources();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SUPPORT_NRF
|
||||||
|
if (SystemSettings.use_comm_nordic) {
|
||||||
|
iface_nordic_free_resources();
|
||||||
|
}
|
||||||
|
#endif // SUPPORT_NRF
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool configure_interface(enum ComportSelection iface)
|
||||||
|
{
|
||||||
|
// Teardown
|
||||||
|
if (gActiveComport == COMPORT_USB) {
|
||||||
|
// simplest USB disabling (XXX needs porting)
|
||||||
|
HAL_PCD_DeInit(&hpcd_USB_FS);
|
||||||
|
__HAL_RCC_USB_CLK_DISABLE();
|
||||||
|
}
|
||||||
|
else if (gActiveComport == COMPORT_USART) {
|
||||||
|
iface_uart_deinit();
|
||||||
|
}
|
||||||
|
#if SUPPORT_NRF
|
||||||
|
else if (gActiveComport == COMPORT_NORDIC) {
|
||||||
|
iface_nordic_deinit();
|
||||||
|
}
|
||||||
|
#endif // SUPPORT_NRF
|
||||||
|
|
||||||
|
|
||||||
|
gActiveComport = iface;
|
||||||
|
|
||||||
|
// Init
|
||||||
|
if (iface == COMPORT_USB) {
|
||||||
|
trap("illegal"); // this never happens
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (iface == COMPORT_USART) {
|
||||||
|
return iface_uart_init();
|
||||||
|
}
|
||||||
|
#if SUPPORT_NRF
|
||||||
|
else if (iface == COMPORT_NORDIC) {
|
||||||
|
return iface_nordic_init();
|
||||||
|
}
|
||||||
|
#endif // SUPPORT_NRF
|
||||||
|
#if 0
|
||||||
|
else if (iface == COMPORT_LORA) {
|
||||||
|
// Try to configure nordic
|
||||||
|
dbg("Setting up LoRa transfer");
|
||||||
|
// TODO set up and check LoRa transport
|
||||||
|
dbg("LoRa not impl!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else {
|
||||||
|
trap("Bad iface %d", iface);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/03/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GEX_CORE_COM_INTERFACES_H
|
||||||
|
#define GEX_CORE_COM_INTERFACES_H
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
enum ComportSelection {
|
||||||
|
COMPORT_NONE = 0,
|
||||||
|
COMPORT_USB = 1,
|
||||||
|
COMPORT_USART = 2,
|
||||||
|
COMPORT_NORDIC = 3,
|
||||||
|
COMPORT_LORA = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const char * COMPORT_NAMES[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The currently active communication port
|
||||||
|
*/
|
||||||
|
extern enum ComportSelection gActiveComport;
|
||||||
|
|
||||||
|
/** Switch com transfer if the current one doesnt seem to work */
|
||||||
|
void com_switch_transfer_if_needed(void);
|
||||||
|
|
||||||
|
/** Claim resources that may be needed for alternate transfers */
|
||||||
|
void com_claim_resources_for_alt_transfers(void);
|
||||||
|
|
||||||
|
/** Release resources allocated for alternate transfers */
|
||||||
|
void com_release_resources_for_alt_transfers(void);
|
||||||
|
|
||||||
|
/** Flush the rx buffer */
|
||||||
|
void com_iface_flush_buffer(void);
|
||||||
|
|
||||||
|
#endif //GEX_CORE_COM_INTERFACES_H
|
||||||
+43
-17
@@ -10,6 +10,8 @@
|
|||||||
#include "comm/messages.h"
|
#include "comm/messages.h"
|
||||||
#include "framework/system_settings.h"
|
#include "framework/system_settings.h"
|
||||||
#include "utils/malloc_safe.h"
|
#include "utils/malloc_safe.h"
|
||||||
|
#include "platform/status_led.h"
|
||||||
|
#include "interfaces.h"
|
||||||
|
|
||||||
static TinyFrame tf_;
|
static TinyFrame tf_;
|
||||||
TinyFrame *comm = &tf_;
|
TinyFrame *comm = &tf_;
|
||||||
@@ -21,8 +23,9 @@ TinyFrame *comm = &tf_;
|
|||||||
*/
|
*/
|
||||||
static TF_Result lst_ping(TinyFrame *tf, TF_Msg *msg)
|
static TF_Result lst_ping(TinyFrame *tf, TF_Msg *msg)
|
||||||
{
|
{
|
||||||
|
dbg("Ping!");
|
||||||
com_respond_snprintf(msg->frame_id, MSG_SUCCESS,
|
com_respond_snprintf(msg->frame_id, MSG_SUCCESS,
|
||||||
"GEX v%s on %s", GEX_VERSION, GEX_PLATFORM);
|
"GEX v%s on %s (%s)", GEX_VERSION, GEX_PLATFORM, COMPORT_NAMES[gActiveComport]);
|
||||||
return TF_STAY;
|
return TF_STAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,41 +60,64 @@ static TF_Result lst_list_units(TinyFrame *tf, TF_Msg *msg)
|
|||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
/** Callback for bulk read of the settings file */
|
/** Callback for bulk read of a settings file */
|
||||||
static void settings_bulkread_cb(BulkRead *bulk, uint32_t chunk, uint8_t *buffer)
|
static void ini_bulkread_cb(BulkRead *bulk, uint32_t chunk, uint8_t *buffer)
|
||||||
{
|
{
|
||||||
// clean-up request
|
// clean-up request
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
free_ck(bulk);
|
free_ck(bulk);
|
||||||
iw_end();
|
iw_end();
|
||||||
dbg("INI read complete.");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bulk->offset == 0) iw_begin();
|
if (bulk->offset == 0) iw_begin();
|
||||||
|
|
||||||
IniWriter iw = iw_init((char *)buffer, bulk->offset, chunk);
|
IniWriter iw = iw_init((char *)buffer, bulk->offset, chunk);
|
||||||
iw.tag = 1;
|
iw.tag = 1; // indicates this is read via the API (affects some comments)
|
||||||
settings_build_units_ini(&iw);
|
|
||||||
|
uint8_t filenum = (uint8_t) (int) bulk->userdata;
|
||||||
|
|
||||||
|
if (filenum == 0) {
|
||||||
|
settings_build_units_ini(&iw);
|
||||||
|
}
|
||||||
|
else if (filenum == 1) {
|
||||||
|
settings_build_system_ini(&iw);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener: Export INI file via TF
|
* Listener: Export a file via TF
|
||||||
*/
|
*/
|
||||||
static TF_Result lst_ini_export(TinyFrame *tf, TF_Msg *msg)
|
static TF_Result lst_ini_export(TinyFrame *tf, TF_Msg *msg)
|
||||||
{
|
{
|
||||||
dbg("Bulk read INI file");
|
// dbg("Bulk read INI file");
|
||||||
|
|
||||||
BulkRead *bulk = malloc_ck(sizeof(BulkRead));
|
BulkRead *bulk = malloc_ck(sizeof(BulkRead));
|
||||||
assert_param(bulk != NULL);
|
assert_param(bulk != NULL);
|
||||||
|
|
||||||
|
uint8_t filenum = 0;
|
||||||
|
|
||||||
|
// if any payload, the first byte defines the file to read
|
||||||
|
// 0 - units
|
||||||
|
// 1 - system
|
||||||
|
// (this is optional for backwards compatibility)
|
||||||
|
if (msg->len > 0) {
|
||||||
|
filenum = msg->data[0];
|
||||||
|
}
|
||||||
|
|
||||||
bulk->frame_id = msg->frame_id;
|
bulk->frame_id = msg->frame_id;
|
||||||
bulk->len = iw_measure_total(settings_build_units_ini, 1);
|
bulk->read = ini_bulkread_cb;
|
||||||
bulk->read = settings_bulkread_cb;
|
bulk->userdata = (void *) (int)filenum;
|
||||||
bulk->userdata = NULL;
|
|
||||||
|
if (filenum == 0) {
|
||||||
|
bulk->len = iw_measure_total(settings_build_units_ini, 1);
|
||||||
|
}
|
||||||
|
else if (filenum == 1) {
|
||||||
|
bulk->len = iw_measure_total(settings_build_system_ini, 1);
|
||||||
|
}
|
||||||
|
|
||||||
bulkread_start(tf, bulk);
|
bulkread_start(tf, bulk);
|
||||||
|
Indicator_Effect(STATUS_DISK_BUSY_SHORT);
|
||||||
return TF_STAY;
|
return TF_STAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +138,7 @@ static void settings_bulkwrite_cb(BulkWrite *bulk, const uint8_t *chunk, uint32_
|
|||||||
|
|
||||||
if (bulk->offset > 0) {
|
if (bulk->offset > 0) {
|
||||||
settings_load_ini_end();
|
settings_load_ini_end();
|
||||||
dbg("INI write complete");
|
// dbg("INI write complete");
|
||||||
} else {
|
} else {
|
||||||
dbg("INI write failed");
|
dbg("INI write failed");
|
||||||
}
|
}
|
||||||
@@ -129,7 +155,7 @@ static void settings_bulkwrite_cb(BulkWrite *bulk, const uint8_t *chunk, uint32_
|
|||||||
*/
|
*/
|
||||||
static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg)
|
static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg)
|
||||||
{
|
{
|
||||||
dbg("Bulk write INI file");
|
// dbg("Bulk write INI file");
|
||||||
|
|
||||||
BulkWrite *bulk = malloc_ck(sizeof(BulkWrite));
|
BulkWrite *bulk = malloc_ck(sizeof(BulkWrite));
|
||||||
assert_param(bulk);
|
assert_param(bulk);
|
||||||
@@ -140,7 +166,7 @@ static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg)
|
|||||||
PayloadParser pp = pp_start(msg->data, msg->len, NULL);
|
PayloadParser pp = pp_start(msg->data, msg->len, NULL);
|
||||||
uint32_t len = pp_u32(&pp);
|
uint32_t len = pp_u32(&pp);
|
||||||
if (!pp.ok) {
|
if (!pp.ok) {
|
||||||
com_respond_error(msg->frame_id, E_PROTOCOL_BREACH);
|
com_respond_error(msg->frame_id, E_MALFORMED_COMMAND);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,9 +175,8 @@ static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg)
|
|||||||
|
|
||||||
settings_load_ini_begin();
|
settings_load_ini_begin();
|
||||||
ini_parse_begin(iniparser_cb, NULL);
|
ini_parse_begin(iniparser_cb, NULL);
|
||||||
|
|
||||||
bulkwrite_start(tf, bulk);
|
bulkwrite_start(tf, bulk);
|
||||||
|
Indicator_Effect(STATUS_DISK_BUSY);
|
||||||
done:
|
done:
|
||||||
return TF_STAY;
|
return TF_STAY;
|
||||||
}
|
}
|
||||||
@@ -161,6 +186,7 @@ done:
|
|||||||
/** Listener: Save settings to Flash */
|
/** Listener: Save settings to Flash */
|
||||||
static TF_Result lst_persist_cfg(TinyFrame *tf, TF_Msg *msg)
|
static TF_Result lst_persist_cfg(TinyFrame *tf, TF_Msg *msg)
|
||||||
{
|
{
|
||||||
|
Indicator_Effect(STATUS_DISK_REMOVED);
|
||||||
settings_save();
|
settings_save();
|
||||||
return TF_STAY;
|
return TF_STAY;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -4,8 +4,8 @@
|
|||||||
// Bulk read (providing data for bulk read by the PC)
|
// Bulk read (providing data for bulk read by the PC)
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef GEX_F072_MSG_BULKREAD_H
|
#ifndef GEX_CORE_MSG_BULKREAD_H
|
||||||
#define GEX_F072_MSG_BULKREAD_H
|
#define GEX_CORE_MSG_BULKREAD_H
|
||||||
|
|
||||||
#ifndef GEX_MESSAGES_H
|
#ifndef GEX_MESSAGES_H
|
||||||
#error "Include messages.h instead!"
|
#error "Include messages.h instead!"
|
||||||
@@ -45,4 +45,4 @@ struct bulk_read {
|
|||||||
void bulkread_start(TinyFrame *tf, BulkRead *bulk);
|
void bulkread_start(TinyFrame *tf, BulkRead *bulk);
|
||||||
|
|
||||||
|
|
||||||
#endif //GEX_F072_MSG_BULKREAD_H
|
#endif //GEX_CORE_MSG_BULKREAD_H
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
// Bulk write (receiving bulk write from the PC)
|
// Bulk write (receiving bulk write from the PC)
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef GEX_F072_MSG_BULKWRITE_H
|
#ifndef GEX_CORE_MSG_BULKWRITE_H
|
||||||
#define GEX_F072_MSG_BULKWRITE_H
|
#define GEX_CORE_MSG_BULKWRITE_H
|
||||||
|
|
||||||
#ifndef GEX_MESSAGES_H
|
#ifndef GEX_MESSAGES_H
|
||||||
#error "Include messages.h instead!"
|
#error "Include messages.h instead!"
|
||||||
@@ -44,4 +44,4 @@ struct bulk_write {
|
|||||||
void bulkwrite_start(TinyFrame *tf, BulkWrite *bulk);
|
void bulkwrite_start(TinyFrame *tf, BulkWrite *bulk);
|
||||||
|
|
||||||
|
|
||||||
#endif //GEX_F072_MSG_BULKWRITE_H
|
#endif //GEX_CORE_MSG_BULKWRITE_H
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
// Routines for sending TinyFrame responses.
|
// Routines for sending TinyFrame responses.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef GEX_F072_MSG_RESPONSES_H
|
#ifndef GEX_CORE_MSG_RESPONSES_H
|
||||||
#define GEX_F072_MSG_RESPONSES_H
|
#define GEX_CORE_MSG_RESPONSES_H
|
||||||
|
|
||||||
#ifndef GEX_MESSAGES_H
|
#ifndef GEX_MESSAGES_H
|
||||||
#error "Include messages.h instead!"
|
#error "Include messages.h instead!"
|
||||||
@@ -109,4 +109,4 @@ void com_respond_u16(TF_ID frame_id, uint16_t d);
|
|||||||
*/
|
*/
|
||||||
void com_respond_u32(TF_ID frame_id, uint32_t d);
|
void com_respond_u32(TF_ID frame_id, uint32_t d);
|
||||||
|
|
||||||
#endif //GEX_F072_MSG_RESPONSES_H
|
#endif //GEX_CORE_MSG_RESPONSES_H
|
||||||
|
|||||||
+551
@@ -0,0 +1,551 @@
|
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/04/02.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#if SUPPORT_NRF
|
||||||
|
|
||||||
|
#include "nrf.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a register
|
||||||
|
*
|
||||||
|
* @param reg - register number (max 83)
|
||||||
|
* @return register value
|
||||||
|
*/
|
||||||
|
static uint8_t NRF_ReadRegister(uint8_t reg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a register
|
||||||
|
*
|
||||||
|
* @param reg - register number (max 83)
|
||||||
|
* @param value - register value
|
||||||
|
* @return status register value
|
||||||
|
*/
|
||||||
|
static uint8_t NRF_WriteRegister(uint8_t reg, uint8_t value);
|
||||||
|
|
||||||
|
// Internal use
|
||||||
|
static uint8_t NRF_WriteBuffer(uint8_t reg, const uint8_t *pBuf, uint8_t bytes);
|
||||||
|
|
||||||
|
static uint8_t NRF_ReadBuffer(uint8_t reg, uint8_t *pBuf, uint8_t bytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set TX address for next frame
|
||||||
|
*
|
||||||
|
* @param SendTo - addr
|
||||||
|
*/
|
||||||
|
static void NRF_SetTxAddress(uint8_t ToAddr);
|
||||||
|
|
||||||
|
//----------------------------------------------------------
|
||||||
|
|
||||||
|
/** Tight asm loop */
|
||||||
|
#define __asm_loop(cycles) \
|
||||||
|
do { \
|
||||||
|
register uint32_t _count asm ("r4") = cycles; \
|
||||||
|
asm volatile( \
|
||||||
|
".syntax unified\n" \
|
||||||
|
".thumb\n" \
|
||||||
|
"0:" \
|
||||||
|
"subs %0, #1\n" \
|
||||||
|
"bne 0b\n" \
|
||||||
|
: "+r" (_count)); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
// 12 for 72 MHz
|
||||||
|
#define _delay_us(n) __asm_loop((n)*8)
|
||||||
|
|
||||||
|
static inline void CE(bool level) {
|
||||||
|
__asm_loop(1);
|
||||||
|
if (level) LL_GPIO_SetOutputPin(NRF_CE_GPIO_Port, NRF_CE_Pin);
|
||||||
|
else LL_GPIO_ResetOutputPin(NRF_CE_GPIO_Port, NRF_CE_Pin);
|
||||||
|
__asm_loop(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void NSS(bool level) {
|
||||||
|
__asm_loop(1);
|
||||||
|
if (level) LL_GPIO_SetOutputPin(NRF_NSS_GPIO_Port, NRF_NSS_Pin);
|
||||||
|
else LL_GPIO_ResetOutputPin(NRF_NSS_GPIO_Port, NRF_NSS_Pin);
|
||||||
|
__asm_loop(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t spi(uint8_t tx) {
|
||||||
|
while (! LL_SPI_IsActiveFlag_TXE(NRF_SPI));
|
||||||
|
LL_SPI_TransmitData8(NRF_SPI, tx);
|
||||||
|
while (! LL_SPI_IsActiveFlag_RXNE(NRF_SPI));
|
||||||
|
return LL_SPI_ReceiveData8(NRF_SPI);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NRF_Reset(bool enable_reset)
|
||||||
|
{
|
||||||
|
if (enable_reset) {
|
||||||
|
// go HIGH - this closes the PMOS
|
||||||
|
LL_GPIO_SetOutputPin(NRF_RST_GPIO_Port, NRF_RST_Pin);
|
||||||
|
} else {
|
||||||
|
// LOW - open PMOS, enable power
|
||||||
|
LL_GPIO_ResetOutputPin(NRF_RST_GPIO_Port, NRF_RST_Pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------
|
||||||
|
|
||||||
|
/*
|
||||||
|
* from: http://barefootelectronics.com/NRF24L01.aspx
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CMD_READ_REG 0x00 // Read command to register
|
||||||
|
#define CMD_WRITE_REG 0x20 // Write command to register
|
||||||
|
#define CMD_RD_RX_PLD 0x61 // Read RX payload register address
|
||||||
|
#define CMD_WR_TX_PLD 0xA0 // Write TX payload register address
|
||||||
|
#define CMD_FLUSH_TX 0xE1 // Flush TX register command
|
||||||
|
#define CMD_FLUSH_RX 0xE2 // Flush RX register command
|
||||||
|
#define CMD_REUSE_TX_PL 0xE3 // Reuse TX payload register command
|
||||||
|
#define CMD_RD_RX_PL_WIDTH 0x60 // Read RX Payload Width
|
||||||
|
#define CMD_WR_ACK_PLD 0xA8 // Write ACK payload for Pipe (Add pipe number 0-6)
|
||||||
|
#define CMD_WR_TX_PLD_NK 0xB0 // Write ACK payload for not ack
|
||||||
|
#define CMD_NOP 0xFF // No Operation, might be used to read status register
|
||||||
|
|
||||||
|
// SPI(nRF24L01) registers(addresses)
|
||||||
|
#define RG_CONFIG 0x00 // 'Config' register address
|
||||||
|
#define RG_EN_AA 0x01 // 'Enable Auto Acknowledgment' register address
|
||||||
|
#define RG_EN_RXADDR 0x02 // 'Enabled RX addresses' register address
|
||||||
|
#define RG_SETUP_AW 0x03 // 'Setup address width' register address
|
||||||
|
#define RG_SETUP_RETR 0x04 // 'Setup Auto. Retrans' register address
|
||||||
|
#define RG_RF_CH 0x05 // 'RF channel' register address
|
||||||
|
#define RG_RF_SETUP 0x06 // 'RF setup' register address
|
||||||
|
#define RG_STATUS 0x07 // 'Status' register address
|
||||||
|
#define RG_OBSERVE_TX 0x08 // 'Observe TX' register address
|
||||||
|
#define RG_CD 0x09 // 'Carrier Detect' register address
|
||||||
|
#define RG_RX_ADDR_P0 0x0A // 'RX address pipe0' register address
|
||||||
|
#define RG_RX_ADDR_P1 0x0B // 'RX address pipe1' register address
|
||||||
|
#define RG_RX_ADDR_P2 0x0C // 'RX address pipe2' register address
|
||||||
|
#define RG_RX_ADDR_P3 0x0D // 'RX address pipe3' register address
|
||||||
|
#define RG_RX_ADDR_P4 0x0E // 'RX address pipe4' register address
|
||||||
|
#define RG_RX_ADDR_P5 0x0F // 'RX address pipe5' register address
|
||||||
|
#define RG_TX_ADDR 0x10 // 'TX address' register address
|
||||||
|
#define RG_RX_PW_P0 0x11 // 'RX payload width, pipe0' register address
|
||||||
|
#define RG_RX_PW_P1 0x12 // 'RX payload width, pipe1' register address
|
||||||
|
#define RG_RX_PW_P2 0x13 // 'RX payload width, pipe2' register address
|
||||||
|
#define RG_RX_PW_P3 0x14 // 'RX payload width, pipe3' register address
|
||||||
|
#define RG_RX_PW_P4 0x15 // 'RX payload width, pipe4' register address
|
||||||
|
#define RG_RX_PW_P5 0x16 // 'RX payload width, pipe5' register address
|
||||||
|
#define RG_FIFO_STATUS 0x17 // 'FIFO Status Register' register address
|
||||||
|
#define RG_DYNPD 0x1C // 'Enable dynamic payload length
|
||||||
|
#define RG_FEATURE 0x1D // 'Feature register
|
||||||
|
|
||||||
|
#define RD_STATUS_TX_FULL 0x01 // tx queue full
|
||||||
|
#define RD_STATUS_RX_PNO 0x0E // pipe number of the received payload
|
||||||
|
#define RD_STATUS_MAX_RT 0x10 // max retransmissions
|
||||||
|
#define RD_STATUS_TX_DS 0x20 // data sent
|
||||||
|
#define RD_STATUS_RX_DR 0x40 // data ready
|
||||||
|
|
||||||
|
#define RD_CONFIG_PRIM_RX 0x01 // is primary receiver
|
||||||
|
#define RD_CONFIG_PWR_UP 0x02 // power up
|
||||||
|
#define RD_CONFIG_CRCO 0x04 // 2-byte CRC
|
||||||
|
#define RD_CONFIG_EN_CRC 0x08 // enable CRC
|
||||||
|
#define RD_CONFIG_DISABLE_IRQ_MAX_RT 0x10
|
||||||
|
#define RD_CONFIG_DISABLE_IRQ_TX_DS 0x20
|
||||||
|
#define RD_CONFIG_DISABLE_IRQ_RX_DR 0x40
|
||||||
|
|
||||||
|
#define RD_FIFO_STATUS_RX_EMPTY 0x01
|
||||||
|
#define RD_FIFO_STATUS_RX_FULL 0x02
|
||||||
|
#define RD_FIFO_STATUS_TX_EMPTY 0x10
|
||||||
|
#define RD_FIFO_STATUS_TX_FULL 0x20
|
||||||
|
#define RD_FIFO_STATUS_TX_REUSE 0x40
|
||||||
|
|
||||||
|
// Config register bits (excluding the bottom two that are changed dynamically)
|
||||||
|
// enable only Rx IRQ
|
||||||
|
#define ModeBits (RD_CONFIG_DISABLE_IRQ_MAX_RT | \
|
||||||
|
RD_CONFIG_DISABLE_IRQ_TX_DS | \
|
||||||
|
RD_CONFIG_EN_CRC | \
|
||||||
|
RD_CONFIG_CRCO)
|
||||||
|
|
||||||
|
static inline uint8_t CS(uint8_t hl)
|
||||||
|
{
|
||||||
|
if (hl == 1) {
|
||||||
|
NSS(0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
NSS(1);
|
||||||
|
}
|
||||||
|
return hl;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHIPSELECT for (uint8_t cs = CS(1); cs==1; cs = CS(0))
|
||||||
|
|
||||||
|
// Base NRF address - byte 4 may be modified before writing to a pipe register,
|
||||||
|
// the first 4 bytes are shared in the network. Master is always code 0.
|
||||||
|
static uint8_t nrf_base_address[5];
|
||||||
|
|
||||||
|
static uint8_t nrf_pipe_addr[6];
|
||||||
|
static bool nrf_pipe_enabled[6];
|
||||||
|
|
||||||
|
static uint8_t NRF_WriteRegister(uint8_t reg, uint8_t value)
|
||||||
|
{
|
||||||
|
uint8_t status = 0;
|
||||||
|
CHIPSELECT {
|
||||||
|
status = spi(CMD_WRITE_REG | reg);
|
||||||
|
spi(value);
|
||||||
|
}
|
||||||
|
dbg_nrf("Wr[0x%02x] := 0x%02x", (int)reg, (int) value);
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t reg_val = 0;
|
||||||
|
CHIPSELECT {
|
||||||
|
spi(CMD_READ_REG | reg);
|
||||||
|
reg_val = spi(0);
|
||||||
|
}
|
||||||
|
dbg_nrf(" verify 0x%02x", (int)reg_val);
|
||||||
|
if (reg_val != value)
|
||||||
|
dbg_nrf(" !!!");
|
||||||
|
else
|
||||||
|
dbg_nrf(" OK");
|
||||||
|
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t NRF_ReadRegister(uint8_t reg)
|
||||||
|
{
|
||||||
|
uint8_t reg_val = 0;
|
||||||
|
CHIPSELECT {
|
||||||
|
spi(CMD_READ_REG | reg);
|
||||||
|
reg_val = spi(0);
|
||||||
|
}
|
||||||
|
dbg_nrf("Rd[0x%02x] = 0x%02x", (int)reg, (int) reg_val);
|
||||||
|
return reg_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t NRF_ReadStatus(void)
|
||||||
|
{
|
||||||
|
uint8_t reg_val = 0;
|
||||||
|
CHIPSELECT {
|
||||||
|
reg_val = spi(CMD_NOP);
|
||||||
|
}
|
||||||
|
return reg_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t NRF_WriteBuffer(uint8_t reg, const uint8_t *pBuf, uint8_t bytes)
|
||||||
|
{
|
||||||
|
uint8_t status = 0, i = 0;
|
||||||
|
CHIPSELECT {
|
||||||
|
status = spi(CMD_WRITE_REG | reg);
|
||||||
|
for (i = 0; i < bytes; i++) {
|
||||||
|
spi(*pBuf++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t NRF_ReadBuffer(uint8_t reg, uint8_t *pBuf, uint8_t bytes)
|
||||||
|
{
|
||||||
|
uint8_t status = 0, i;
|
||||||
|
CHIPSELECT {
|
||||||
|
status = spi(CMD_READ_REG | reg);
|
||||||
|
for (i = 0; i < bytes; i++) {
|
||||||
|
pBuf[i] = spi(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NRF_SetBaseAddress(const uint8_t *Bytes4)
|
||||||
|
{
|
||||||
|
memcpy(nrf_base_address, Bytes4, 4);
|
||||||
|
nrf_base_address[4] = 0;
|
||||||
|
|
||||||
|
// write it to the two full-width address registers
|
||||||
|
NRF_WriteBuffer(RG_RX_ADDR_P0, nrf_base_address, 5);
|
||||||
|
nrf_base_address[4] = 1;// to be different
|
||||||
|
NRF_WriteBuffer(RG_RX_ADDR_P1, nrf_base_address, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NRF_SetRxAddress(uint8_t pipenum, uint8_t AddrByte)
|
||||||
|
{
|
||||||
|
if (pipenum > 5) {
|
||||||
|
dbg_nrf("!! bad pipe %d", pipenum);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nrf_base_address[4] = AddrByte;
|
||||||
|
|
||||||
|
nrf_pipe_addr[pipenum] = AddrByte;
|
||||||
|
|
||||||
|
dbg_nrf("Set Rx addr (pipe %d) = 0x%02x", (int)pipenum, AddrByte);
|
||||||
|
if (pipenum == 0) {
|
||||||
|
dbg_nrf("W ADDR_PA0: %02X-%02X-%02X-%02X-%02X", nrf_base_address[0], nrf_base_address[1], nrf_base_address[2], nrf_base_address[3], nrf_base_address[4]);
|
||||||
|
NRF_WriteBuffer(RG_RX_ADDR_P0, nrf_base_address, 5);
|
||||||
|
}
|
||||||
|
else if (pipenum == 1) {
|
||||||
|
dbg_nrf("W ADDR_PA1: %02X-%02X-%02X-%02X-%02X", nrf_base_address[0], nrf_base_address[1], nrf_base_address[2], nrf_base_address[3], nrf_base_address[4]);
|
||||||
|
NRF_WriteBuffer(RG_RX_ADDR_P1, nrf_base_address, 5);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
NRF_WriteRegister(RG_RX_ADDR_P2 + (pipenum - 2), AddrByte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NRF_AddPipe(uint8_t AddrByte, uint8_t *PipeNum)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < 6; i++) {
|
||||||
|
if(!nrf_pipe_enabled[i]) {
|
||||||
|
NRF_SetRxAddress(i, AddrByte);
|
||||||
|
*PipeNum = i;
|
||||||
|
NRF_EnablePipe(i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t NRF_PipeNum2Addr(uint8_t pipe_num)
|
||||||
|
{
|
||||||
|
if (pipe_num > 5) return 0; // fail
|
||||||
|
return nrf_pipe_addr[pipe_num];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t NRF_Addr2PipeNum(uint8_t addr)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
if (nrf_pipe_addr[i] == addr) return (uint8_t) i;
|
||||||
|
}
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NRF_EnablePipe(uint8_t pipenum)
|
||||||
|
{
|
||||||
|
dbg_nrf("Enable pipe num %d", (int)pipenum);
|
||||||
|
uint8_t enabled = NRF_ReadRegister(RG_EN_RXADDR);
|
||||||
|
enabled |= 1 << pipenum;
|
||||||
|
NRF_WriteRegister(RG_EN_RXADDR, enabled);
|
||||||
|
|
||||||
|
nrf_pipe_enabled[pipenum] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NRF_DisablePipe(uint8_t pipenum)
|
||||||
|
{
|
||||||
|
uint8_t enabled = NRF_ReadRegister(RG_EN_RXADDR);
|
||||||
|
enabled &= ~(1 << pipenum);
|
||||||
|
NRF_WriteRegister(RG_EN_RXADDR, enabled);
|
||||||
|
|
||||||
|
nrf_pipe_enabled[pipenum] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NRF_SetTxAddress(uint8_t SendTo)
|
||||||
|
{
|
||||||
|
nrf_base_address[4] = SendTo;
|
||||||
|
|
||||||
|
dbg_nrf("W Tx_ADDR + Rx0: %02X-%02X-%02X-%02X-%02X",
|
||||||
|
nrf_base_address[0], nrf_base_address[1], nrf_base_address[2], nrf_base_address[3], nrf_base_address[4]);
|
||||||
|
|
||||||
|
NRF_WriteBuffer(RG_TX_ADDR, nrf_base_address, 5);
|
||||||
|
NRF_WriteBuffer(RG_RX_ADDR_P0, nrf_base_address, 5); // the ACK will come to pipe 0
|
||||||
|
}
|
||||||
|
|
||||||
|
void NRF_PowerDown(void)
|
||||||
|
{
|
||||||
|
dbg_nrf("PDn");
|
||||||
|
CE(0);
|
||||||
|
NRF_WriteRegister(RG_CONFIG, ModeBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NRF_ModeTX(void)
|
||||||
|
{
|
||||||
|
dbg_nrf("Tx Mode");
|
||||||
|
|
||||||
|
CE(0);
|
||||||
|
uint8_t m = NRF_ReadRegister(RG_CONFIG);
|
||||||
|
NRF_WriteRegister(RG_CONFIG, ModeBits | RD_CONFIG_PWR_UP);
|
||||||
|
if ((m & RD_CONFIG_PWR_UP) == 0) {
|
||||||
|
// switching on
|
||||||
|
LL_mDelay(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NRF_ModeRX(void)
|
||||||
|
{
|
||||||
|
dbg_nrf("Rx Mode");
|
||||||
|
NRF_WriteRegister(RG_CONFIG, ModeBits | RD_CONFIG_PWR_UP | RD_CONFIG_PRIM_RX);
|
||||||
|
NRF_SetRxAddress(0, nrf_pipe_addr[0]); // set the P0 address - it was changed during Rx for ACK reception
|
||||||
|
CE(1);
|
||||||
|
|
||||||
|
//if ((m&2)==0) LL_mDelay()(5); You don't need to wait. Just nothing will come for 5ms or more
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t NRF_IsModePowerDown(void)
|
||||||
|
{
|
||||||
|
uint8_t ret = 0;
|
||||||
|
if ((NRF_ReadRegister(RG_CONFIG) & RD_CONFIG_PWR_UP) == 0) ret = 1;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t NRF_IsModeTX(void)
|
||||||
|
{
|
||||||
|
uint8_t m = NRF_ReadRegister(RG_CONFIG);
|
||||||
|
if ((m & RD_CONFIG_PWR_UP) == 0) return 0; // OFF
|
||||||
|
if ((m & RD_CONFIG_PRIM_RX) == 0) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t NRF_IsModeRx(void)
|
||||||
|
{
|
||||||
|
uint8_t m = NRF_ReadRegister(RG_CONFIG);
|
||||||
|
if ((m & RD_CONFIG_PWR_UP) == 0) return 0; // OFF
|
||||||
|
if ((m & RD_CONFIG_PRIM_RX) == 0) return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NRF_SetChannel(uint8_t Ch)
|
||||||
|
{
|
||||||
|
NRF_WriteRegister(RG_RF_CH, Ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t NRF_ReceivePacket(uint8_t *Packet, uint8_t *PipeNum)
|
||||||
|
{
|
||||||
|
uint8_t pw = 0, status;
|
||||||
|
// if (!NRF_IsRxPacket()) {
|
||||||
|
// dbg("rx queue empty");
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const uint8_t orig_conf = NRF_ReadRegister(RG_CONFIG);
|
||||||
|
// CE(0); // quit Rx mode - go idle
|
||||||
|
|
||||||
|
CHIPSELECT {
|
||||||
|
status = spi(CMD_RD_RX_PL_WIDTH);
|
||||||
|
pw = spi(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pw == 0) {
|
||||||
|
dbg("empty pld");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pw > 32) {
|
||||||
|
CHIPSELECT {
|
||||||
|
spi(CMD_FLUSH_RX);
|
||||||
|
}
|
||||||
|
pw = 0;
|
||||||
|
dbg("over 32");
|
||||||
|
} else {
|
||||||
|
// Read the reception pipe number
|
||||||
|
*PipeNum = ((status & RD_STATUS_RX_PNO) >> 1);
|
||||||
|
CHIPSELECT {
|
||||||
|
spi(CMD_RD_RX_PLD);
|
||||||
|
for (uint8_t i = 0; i < pw; i++) Packet[i] = spi(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NRF_WriteRegister(RG_STATUS, RD_STATUS_RX_DR); // Clear the RX_DR interrupt
|
||||||
|
|
||||||
|
// if ((orig_conf & RD_CONFIG_PWR_UP) == 0) {
|
||||||
|
// dbg_nrf("going back PwrDn");
|
||||||
|
// NRF_PowerDown();
|
||||||
|
// }
|
||||||
|
// else if ((orig_conf & RD_CONFIG_PRIM_RX) == RD_CONFIG_PRIM_RX) {
|
||||||
|
// dbg_nrf("going back PwrUp+Rx");
|
||||||
|
// NRF_ModeRX();
|
||||||
|
// }
|
||||||
|
// CE(1); // back to rx
|
||||||
|
return pw;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NRF_IsRxPacket(void)
|
||||||
|
{
|
||||||
|
return 0 == (NRF_ReadRegister(RG_FIFO_STATUS) & RD_FIFO_STATUS_RX_EMPTY);
|
||||||
|
// uint8_t ret = NRF_ReadRegister(RG_STATUS) & RD_STATUS_RX_DR;
|
||||||
|
// return 0 != ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NRF_SendPacket(uint8_t PipeNum, const uint8_t *Packet, uint8_t Length)
|
||||||
|
{
|
||||||
|
if (!nrf_pipe_enabled[PipeNum]) {
|
||||||
|
dbg_nrf("!! Pipe %d not enabled", PipeNum);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg_nrf("Will tx to addr %02x", nrf_pipe_addr[PipeNum]);
|
||||||
|
|
||||||
|
const uint8_t orig_conf = NRF_ReadRegister(RG_CONFIG);
|
||||||
|
CE(0);
|
||||||
|
NRF_ModeTX(); // Make sure in TX mode
|
||||||
|
NRF_SetTxAddress(nrf_pipe_addr[PipeNum]); // this sets the Tx addr and also pipe 0 addr for ACK
|
||||||
|
|
||||||
|
CHIPSELECT {
|
||||||
|
spi(CMD_FLUSH_TX);
|
||||||
|
};
|
||||||
|
|
||||||
|
CHIPSELECT {
|
||||||
|
spi(CMD_WR_TX_PLD);
|
||||||
|
for (uint8_t i = 0; i < Length; i++) spi(Packet[i]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// CE pulse
|
||||||
|
CE(1);
|
||||||
|
_delay_us(20); // At least 10 us
|
||||||
|
CE(0);
|
||||||
|
|
||||||
|
uint8_t st = 0;
|
||||||
|
while ((st & (RD_STATUS_MAX_RT|RD_STATUS_TX_DS)) == 0) {
|
||||||
|
st = NRF_ReadStatus(); // Packet acked or timed out
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg_nrf("Send status: 0x%02x - MAX_RT %d, SENT %d", (int)st,
|
||||||
|
(st&RD_STATUS_MAX_RT) != 0, (st&RD_STATUS_TX_DS) != 0);
|
||||||
|
|
||||||
|
NRF_WriteRegister(RG_STATUS, st & (RD_STATUS_MAX_RT|RD_STATUS_TX_DS)); // Clear the bit
|
||||||
|
|
||||||
|
if ((orig_conf & RD_CONFIG_PWR_UP) == 0) {
|
||||||
|
dbg_nrf("going back PwrDn");
|
||||||
|
NRF_PowerDown();
|
||||||
|
}
|
||||||
|
else if ((orig_conf & RD_CONFIG_PRIM_RX) == RD_CONFIG_PRIM_RX) {
|
||||||
|
dbg_nrf("going back PwrUp+Rx");
|
||||||
|
NRF_ModeRX();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0 != (st & RD_STATUS_TX_DS); // success
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NRF_Init(uint8_t pSpeed)
|
||||||
|
{
|
||||||
|
// Set the required output pins
|
||||||
|
NSS(1);
|
||||||
|
CE(0);
|
||||||
|
|
||||||
|
LL_mDelay(200);
|
||||||
|
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
nrf_pipe_addr[i] = 0;
|
||||||
|
nrf_pipe_enabled[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is a test if there's anything present
|
||||||
|
uint8_t awreg = NRF_ReadRegister(RG_SETUP_AW);
|
||||||
|
if (awreg == 0 || awreg > 3) return false;
|
||||||
|
|
||||||
|
// clear flags etc
|
||||||
|
NRF_PowerDown();
|
||||||
|
CHIPSELECT { spi(CMD_FLUSH_RX); }
|
||||||
|
CHIPSELECT { spi(CMD_FLUSH_TX); }
|
||||||
|
NRF_WriteRegister(RG_STATUS, 0x70);
|
||||||
|
|
||||||
|
NRF_WriteRegister(RG_CONFIG, ModeBits);
|
||||||
|
NRF_WriteRegister(RG_SETUP_AW, 0b11); // 5 byte addresses
|
||||||
|
|
||||||
|
NRF_WriteRegister(RG_EN_RXADDR, 0x01); // disable all, enable pipe 0 - this is required for shockburst, despite not being specified in the DS
|
||||||
|
|
||||||
|
NRF_WriteRegister(RG_SETUP_RETR, 0x18); // 8 retries
|
||||||
|
NRF_WriteRegister(RG_RF_CH, 2); // channel 2 NO HIGHER THAN 83 in USA!
|
||||||
|
|
||||||
|
NRF_WriteRegister(RG_RF_SETUP, pSpeed);
|
||||||
|
|
||||||
|
NRF_WriteRegister(RG_DYNPD, 0b111111); // Dynamic packet length
|
||||||
|
NRF_WriteRegister(RG_FEATURE, 0b100); // Enable dynamic payload, and no payload in the ack.
|
||||||
|
|
||||||
|
// for (int i = 0; i < 6; i++) {
|
||||||
|
// NRF_WriteRegister(RG_RX_PW_P0+i, 32); // Receive 32 byte packets - XXX this is probably not needed with dynamic length
|
||||||
|
// }
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
+163
@@ -0,0 +1,163 @@
|
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/04/02.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GEX_NRF_NRF_H
|
||||||
|
#define GEX_NRF_NRF_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nordic.h
|
||||||
|
*
|
||||||
|
* Created:12/16/2013 3:36:04 PM
|
||||||
|
* Author: Tom
|
||||||
|
*
|
||||||
|
* NRF24L01+ Library II
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#if SUPPORT_NRF
|
||||||
|
|
||||||
|
#include "resources.h"
|
||||||
|
#include "nrf_pins.h"
|
||||||
|
|
||||||
|
#define dbg_nrf(...) do{}while(0)
|
||||||
|
//#define dbg_nrf dbg
|
||||||
|
|
||||||
|
// Initialize SPI and the Nordic
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the NRF module
|
||||||
|
*
|
||||||
|
* @param pSpeed
|
||||||
|
* @return success (0 if device not detected)
|
||||||
|
*/
|
||||||
|
bool NRF_Init(uint8_t pSpeed);
|
||||||
|
|
||||||
|
#define NRF_SPEED_500k 0b00100110
|
||||||
|
#define NRF_SPEED_2M 0b00001110
|
||||||
|
#define NRF_SPEED_1M 0b00000110
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the reset pin (this is a PMOS controlling its power)
|
||||||
|
*
|
||||||
|
* @param enable_reset 1 to go into reset, 0 to enter operational state (will need some time to become ready)
|
||||||
|
*/
|
||||||
|
void NRF_Reset(bool enable_reset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set reception address
|
||||||
|
* @param pipenum - pipe to set
|
||||||
|
* @param AddrByte - byte 0
|
||||||
|
*/
|
||||||
|
void NRF_SetRxAddress(uint8_t pipenum, uint8_t AddrByte);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set communication channel
|
||||||
|
*/
|
||||||
|
void NRF_SetChannel(uint8_t Ch) ; // 0 through 83 only!
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Power down the transceiver
|
||||||
|
*/
|
||||||
|
void NRF_PowerDown(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selecr RX mode
|
||||||
|
*/
|
||||||
|
void NRF_ModeRX(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select TX mode
|
||||||
|
*/
|
||||||
|
void NRF_ModeTX(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return NRF is power down
|
||||||
|
*/
|
||||||
|
uint8_t NRF_IsModePowerDown(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return NRF in TX mode
|
||||||
|
*/
|
||||||
|
uint8_t NRF_IsModeTX(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return NRF in RX mode
|
||||||
|
*/
|
||||||
|
uint8_t NRF_IsModeRx(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a pipe to the next free slot
|
||||||
|
*
|
||||||
|
* @param AddrByte - address byte of the peer
|
||||||
|
* @param[out] PipeNum - pipe number is written here
|
||||||
|
* @return success
|
||||||
|
*/
|
||||||
|
bool NRF_AddPipe(uint8_t AddrByte, uint8_t *PipeNum);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert pipe number to address byte
|
||||||
|
*
|
||||||
|
* @param pipe_num - pipe number
|
||||||
|
* @return address byte
|
||||||
|
*/
|
||||||
|
uint8_t NRF_PipeNum2Addr(uint8_t pipe_num);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert address to a pipe number
|
||||||
|
*
|
||||||
|
* @param addr
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
uint8_t NRF_Addr2PipeNum(uint8_t addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a packet (takes care of mode switching etc)
|
||||||
|
*
|
||||||
|
* @param PipeNum - pipe number
|
||||||
|
* @param Packet - packet bytes
|
||||||
|
* @param Length - packet length
|
||||||
|
* @return success (ACK'd)
|
||||||
|
*/
|
||||||
|
bool NRF_SendPacket(uint8_t PipeNum, const uint8_t *Packet, uint8_t Length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive a packet
|
||||||
|
*
|
||||||
|
* @param[out] Packet - the receiuved packet - buffer that is written
|
||||||
|
* @param[out] PipeNum - pipe number that was received from
|
||||||
|
* @return packet size, 0 on failure
|
||||||
|
*/
|
||||||
|
uint8_t NRF_ReceivePacket(uint8_t *Packet, uint8_t *PipeNum);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set base address
|
||||||
|
* @param Bytes4
|
||||||
|
*/
|
||||||
|
void NRF_SetBaseAddress(const uint8_t *Bytes4);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if there's a packet to be read
|
||||||
|
*
|
||||||
|
* @return 1 if any to read
|
||||||
|
*/
|
||||||
|
bool NRF_IsRxPacket(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable a pipe
|
||||||
|
*
|
||||||
|
* @param pipenum - pipe number 0-5
|
||||||
|
*/
|
||||||
|
void NRF_EnablePipe(uint8_t pipenum);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable a pipe
|
||||||
|
*
|
||||||
|
* @param pipenum - pipe number 0-5
|
||||||
|
*/
|
||||||
|
void NRF_DisablePipe(uint8_t pipenum);
|
||||||
|
|
||||||
|
#endif // SUPPORT_NRF
|
||||||
|
|
||||||
|
#endif //GEX_NRF_NRF_H
|
||||||
+4
-2
@@ -13,8 +13,10 @@
|
|||||||
|
|
||||||
void SysTick_Handler(void)
|
void SysTick_Handler(void)
|
||||||
{
|
{
|
||||||
GEX_MsTick();
|
// OS first, avoids jitter
|
||||||
osSystickHandler();
|
osSystickHandler();
|
||||||
|
// GEX periodic updates
|
||||||
|
GEX_MsTick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -34,7 +36,7 @@ void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName)
|
|||||||
|
|
||||||
// && (__CORTEX_M >= 3)
|
// && (__CORTEX_M >= 3)
|
||||||
#if VERBOSE_HARDFAULT
|
#if VERBOSE_HARDFAULT
|
||||||
void __attribute__((used)) HardFault_DumpRegisters( uint32_t *origStack, uint32_t lr_value)
|
void __attribute__((used)) HardFault_DumpRegisters(const uint32_t *origStack, uint32_t lr_value)
|
||||||
{
|
{
|
||||||
/* These are volatile to try and prevent the compiler/linker optimising them
|
/* These are volatile to try and prevent the compiler/linker optimising them
|
||||||
away as the variables never actually get used. If the debugger won't show the
|
away as the variables never actually get used. If the debugger won't show the
|
||||||
|
|||||||
+44
-28
@@ -6,6 +6,7 @@
|
|||||||
#include "unit.h"
|
#include "unit.h"
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
#include "hw_utils.h"
|
#include "hw_utils.h"
|
||||||
|
#include "cfg_utils.h"
|
||||||
#include "unit_registry.h"
|
#include "unit_registry.h"
|
||||||
|
|
||||||
static bool rsc_initialized = false;
|
static bool rsc_initialized = false;
|
||||||
@@ -21,10 +22,8 @@ const char *const rsc_names[] = {
|
|||||||
#undef X
|
#undef X
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check that EXTI have higher values than GPIOs in the enum
|
COMPILER_ASSERT(R_PF15 < R_EXTI0);
|
||||||
// (determines the logic in the name generation code below)
|
COMPILER_ASSERT(R_PA0 == 0);
|
||||||
COMPILER_ASSERT(R_EXTI0 > R_PA0);
|
|
||||||
|
|
||||||
|
|
||||||
const char * rsc_get_name(Resource rsc)
|
const char * rsc_get_name(Resource rsc)
|
||||||
{
|
{
|
||||||
@@ -34,23 +33,45 @@ const char * rsc_get_name(Resource rsc)
|
|||||||
// we assume the returned value is not stored anywhere
|
// we assume the returned value is not stored anywhere
|
||||||
// and is directly used in a sprintf call, hence a static buffer is OK to use
|
// and is directly used in a sprintf call, hence a static buffer is OK to use
|
||||||
|
|
||||||
if (rsc >= R_EXTI0) {
|
// R_PA0 is 0
|
||||||
|
if (rsc <= R_PF15) {
|
||||||
|
// we assume the returned value is not stored anywhere
|
||||||
|
// and is directly used in a sprintf call.
|
||||||
|
uint8_t index = rsc;
|
||||||
|
SNPRINTF(gpionamebuf, 8, "P%c%d", 'A'+(index/16), index%16);
|
||||||
|
return gpionamebuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rsc >= R_EXTI0 && rsc <= R_EXTI15) {
|
||||||
uint8_t index = rsc - R_EXTI0;
|
uint8_t index = rsc - R_EXTI0;
|
||||||
SNPRINTF(gpionamebuf, 8, "EXTI%d", index);
|
SNPRINTF(gpionamebuf, 8, "EXTI%d", index);
|
||||||
return gpionamebuf;
|
return gpionamebuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rsc >= R_PA0) {
|
return rsc_names[rsc - R_EXTI15 - 1];
|
||||||
// we assume the returned value is not stored anywhere
|
|
||||||
// and is directly used in a sprintf call.
|
|
||||||
uint8_t index = rsc - R_PA0;
|
|
||||||
SNPRINTF(gpionamebuf, 8, "P%c%d", 'A'+(index/16), index%16);
|
|
||||||
return gpionamebuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rsc_names[rsc];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Convert a pin to resource handle */
|
||||||
|
Resource rsc_portpin2rsc(char port_name, uint8_t pin_number, bool *suc)
|
||||||
|
{
|
||||||
|
assert_param(suc != NULL);
|
||||||
|
|
||||||
|
if(port_name < 'A' || port_name >= ('A'+PORTS_COUNT)) {
|
||||||
|
dbg("Bad port: %c", port_name); // TODO proper report
|
||||||
|
*suc = false;
|
||||||
|
return R_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pin_number > 15) {
|
||||||
|
dbg("Bad pin: %d", pin_number); // TODO proper report
|
||||||
|
*suc = false;
|
||||||
|
return R_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t num = (uint8_t) (port_name - 'A');
|
||||||
|
|
||||||
|
return R_PA0 + num*16 + pin_number;
|
||||||
|
}
|
||||||
|
|
||||||
const char * rsc_get_owner_name(Resource rsc)
|
const char * rsc_get_owner_name(Resource rsc)
|
||||||
{
|
{
|
||||||
@@ -64,11 +85,12 @@ const char * rsc_get_owner_name(Resource rsc)
|
|||||||
|
|
||||||
void rsc_init_registry(void)
|
void rsc_init_registry(void)
|
||||||
{
|
{
|
||||||
for(uint32_t i = 0; i < RSCMAP_LEN; i++) {
|
memset(UNIT_PLATFORM.resources, 0xFF, RSCMAP_LEN);
|
||||||
UNIT_PLATFORM.resources[i] = global_rscmap[i] = 0xFF;
|
memset(global_rscmap, 0xFF, RSCMAP_LEN);
|
||||||
}
|
|
||||||
|
|
||||||
rsc_initialized = true;
|
rsc_initialized = true;
|
||||||
|
|
||||||
|
rsc_dbg("Total %d hw resources, bitmap has %d bytes.", RESOURCE_COUNT, RSCMAP_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -121,17 +143,11 @@ error_t rsc_claim_range(Unit *unit, Resource rsc0, Resource rsc1)
|
|||||||
return E_SUCCESS;
|
return E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
error_t rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins)
|
error_t rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins)
|
||||||
{
|
{
|
||||||
bool suc = true;
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++) {
|
for (int i = 0; i < 16; i++) {
|
||||||
if (pins & (1 << i)) {
|
if (pins & (1 << i)) {
|
||||||
Resource rsc = hw_pin2resource(port_name, (uint8_t) i, &suc);
|
TRY(rsc_claim_pin(unit, port_name, (uint8_t)i));
|
||||||
if (!suc) return E_BAD_CONFIG;
|
|
||||||
|
|
||||||
TRY(rsc_claim(unit, rsc));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return E_SUCCESS;
|
return E_SUCCESS;
|
||||||
@@ -141,7 +157,7 @@ error_t rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins)
|
|||||||
error_t rsc_claim_pin(Unit *unit, char port_name, uint8_t pin)
|
error_t rsc_claim_pin(Unit *unit, char port_name, uint8_t pin)
|
||||||
{
|
{
|
||||||
bool suc = true;
|
bool suc = true;
|
||||||
Resource rsc = hw_pin2resource(port_name, pin, &suc);
|
Resource rsc = rsc_portpin2rsc(port_name, pin, &suc);
|
||||||
if (!suc) return E_BAD_CONFIG;
|
if (!suc) return E_BAD_CONFIG;
|
||||||
TRY(rsc_claim(unit, rsc));
|
TRY(rsc_claim(unit, rsc));
|
||||||
return E_SUCCESS;
|
return E_SUCCESS;
|
||||||
@@ -222,7 +238,7 @@ void rsc_print_all_available(IniWriter *iw)
|
|||||||
|
|
||||||
uint32_t count0 = (iw->count + iw->skip);
|
uint32_t count0 = (iw->count + iw->skip);
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (uint32_t rsc = 0; rsc < R_PA0; rsc++) {
|
for (uint32_t rsc = R_EXTI15+1; rsc < R_NONE; rsc++) {
|
||||||
if (RSC_IS_HELD(scratchmap, (Resource)rsc)) continue;
|
if (RSC_IS_HELD(scratchmap, (Resource)rsc)) continue;
|
||||||
if (!first) iw_string(iw, ", ");
|
if (!first) iw_string(iw, ", ");
|
||||||
|
|
||||||
@@ -242,7 +258,7 @@ void rsc_print_all_available(IniWriter *iw)
|
|||||||
if (i%16 == 0) {
|
if (i%16 == 0) {
|
||||||
// here we print the previous port
|
// here we print the previous port
|
||||||
if (bitmap != 0) {
|
if (bitmap != 0) {
|
||||||
iw_string(iw, pinmask2str(bitmap, iwbuffer));
|
iw_string(iw, cfg_pinmask_encode(bitmap, iwbuffer, 0));
|
||||||
bitmap = 0;
|
bitmap = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +273,7 @@ void rsc_print_all_available(IniWriter *iw)
|
|||||||
}
|
}
|
||||||
// the last one
|
// the last one
|
||||||
if (bitmap != 0) {
|
if (bitmap != 0) {
|
||||||
iw_string(iw, pinmask2str(bitmap, iwbuffer));
|
iw_string(iw, cfg_pinmask_encode(bitmap, iwbuffer, 0));
|
||||||
}
|
}
|
||||||
iw_newline(iw);
|
iw_newline(iw);
|
||||||
iw_newline(iw);
|
iw_newline(iw);
|
||||||
|
|||||||
@@ -94,6 +94,16 @@ void rsc_free(Unit *unit, Resource rsc);
|
|||||||
*/
|
*/
|
||||||
void rsc_free_range(Unit *unit, Resource rsc0, Resource rsc1);
|
void rsc_free_range(Unit *unit, Resource rsc0, Resource rsc1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert pin name and number to a resource enum
|
||||||
|
*
|
||||||
|
* @param port_name - char 'A'..'Z'
|
||||||
|
* @param pin_number - number 0..15
|
||||||
|
* @param suc - set to false on failure, left unchanged on success
|
||||||
|
* @return the resource, or R_NONE
|
||||||
|
*/
|
||||||
|
Resource rsc_portpin2rsc(char port_name, uint8_t pin_number, bool *suc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get name of a resource by the Resource enum.
|
* Get name of a resource by the Resource enum.
|
||||||
* Uses a static buffer, DO NOT store the returned pointer.
|
* Uses a static buffer, DO NOT store the returned pointer.
|
||||||
|
|||||||
+10
-6
@@ -4,15 +4,16 @@
|
|||||||
// Enum of all defined resources
|
// Enum of all defined resources
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef GEX_F072_RSC_ENUM_H
|
#ifndef GEX_CORE_RSC_ENUM_H
|
||||||
#define GEX_F072_RSC_ENUM_H
|
#define GEX_CORE_RSC_ENUM_H
|
||||||
|
|
||||||
// X macro: Resource name,
|
// X macro: Resource name,
|
||||||
#define XX_RESOURCES \
|
#define XX_RESOURCES \
|
||||||
X(SPI1) X(SPI2) X(SPI3) \
|
X(SPI1) X(SPI2) X(SPI3) \
|
||||||
X(I2C1) X(I2C2) X(I2C3) \
|
X(I2C1) X(I2C2) X(I2C3) \
|
||||||
X(ADC1) X(ADC2) X(ADC3) X(ADC4) \
|
X(ADC1) X(ADC2) X(ADC3) X(ADC4) \
|
||||||
X(DAC1) X(DAC2) \
|
X(DAC1) \
|
||||||
|
X(TSC) \
|
||||||
X(USART1) X(USART2) X(USART3) X(USART4) X(USART5) X(USART6) \
|
X(USART1) X(USART2) X(USART3) X(USART4) X(USART5) X(USART6) \
|
||||||
X(TIM1) X(TIM2) X(TIM3) X(TIM4) X(TIM5) \
|
X(TIM1) X(TIM2) X(TIM3) X(TIM4) X(TIM5) \
|
||||||
X(TIM6) X(TIM7) X(TIM8) X(TIM9) X(TIM10) X(TIM11) X(TIM12) X(TIM13) X(TIM14) \
|
X(TIM6) X(TIM7) X(TIM8) X(TIM9) X(TIM10) X(TIM11) X(TIM12) X(TIM13) X(TIM14) \
|
||||||
@@ -24,7 +25,6 @@
|
|||||||
// X(I2S1) X(I2S2) X(I2S3)
|
// X(I2S1) X(I2S2) X(I2S3)
|
||||||
// X(OPAMP1) X(OPAMP2) X(OPAMP3) X(OPAMP4)
|
// X(OPAMP1) X(OPAMP2) X(OPAMP3) X(OPAMP4)
|
||||||
// X(CAN1) X(CAN2)
|
// X(CAN1) X(CAN2)
|
||||||
// X(TSC)
|
|
||||||
// X(DCMI)
|
// X(DCMI)
|
||||||
// X(ETH)
|
// X(ETH)
|
||||||
// X(FSMC)
|
// X(FSMC)
|
||||||
@@ -59,9 +59,13 @@ typedef enum hw_resource Resource;
|
|||||||
/** Enum of all resources */
|
/** Enum of all resources */
|
||||||
enum hw_resource {
|
enum hw_resource {
|
||||||
#define X(res_name) R_##res_name,
|
#define X(res_name) R_##res_name,
|
||||||
XX_RESOURCES
|
// GPIO are at the beginning, because some units use the constants in their config to represent
|
||||||
|
// selected pins and those must not change with adding more stuff to the main list
|
||||||
XX_RESOURCES_GPIO
|
XX_RESOURCES_GPIO
|
||||||
|
// EXTIs (same like GPIOs) have dynamically generated labels to save rom space. Must be contiguous.
|
||||||
XX_RESOURCES_EXTI
|
XX_RESOURCES_EXTI
|
||||||
|
// All the rest ...
|
||||||
|
XX_RESOURCES
|
||||||
#undef X
|
#undef X
|
||||||
R_NONE,
|
R_NONE,
|
||||||
RESOURCE_COUNT = R_NONE,
|
RESOURCE_COUNT = R_NONE,
|
||||||
@@ -128,4 +132,4 @@ static inline void rscmap_free(ResourceMap *rscmap, Resource rsc)
|
|||||||
#define RSC_CLAIM(rscmap, rsc) rscmap_claim(&rscmap, (rsc))
|
#define RSC_CLAIM(rscmap, rsc) rscmap_claim(&rscmap, (rsc))
|
||||||
#define RSC_FREE(rscmap, rsc) rscmap_free(&rscmap, (rsc))
|
#define RSC_FREE(rscmap, rsc) rscmap_free(&rscmap, (rsc))
|
||||||
|
|
||||||
#endif //GEX_F072_RSC_ENUM_H
|
#endif //GEX_CORE_RSC_ENUM_H
|
||||||
|
|||||||
+10
-3
@@ -2,7 +2,7 @@
|
|||||||
// Created by MightyPork on 2017/11/26.
|
// Created by MightyPork on 2017/11/26.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "utils/avrlibc.h"
|
#include <comm/interfaces.h>
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "utils/hexdump.h"
|
#include "utils/hexdump.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
@@ -10,6 +10,8 @@
|
|||||||
#include "system_settings.h"
|
#include "system_settings.h"
|
||||||
#include "utils/str_utils.h"
|
#include "utils/str_utils.h"
|
||||||
#include "unit_base.h"
|
#include "unit_base.h"
|
||||||
|
#include "platform/debug_uart.h"
|
||||||
|
#include "utils/avrlibc.h"
|
||||||
|
|
||||||
// pre-declarations
|
// pre-declarations
|
||||||
static void savebuf_flush(PayloadBuilder *pb, bool final);
|
static void savebuf_flush(PayloadBuilder *pb, bool final);
|
||||||
@@ -108,7 +110,7 @@ void settings_save(void)
|
|||||||
erase.Banks = FLASH_BANK_1; // TODO ?????
|
erase.Banks = FLASH_BANK_1; // TODO ?????
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(GEX_PLAT_F407_DISCOVERY)
|
#if GEX_PLAT_F407
|
||||||
// specialty for F4 with too much flash
|
// specialty for F4 with too much flash
|
||||||
erase.NbSectors = 1;
|
erase.NbSectors = 1;
|
||||||
erase.Sector = SETTINGS_FLASH_SECTOR;
|
erase.Sector = SETTINGS_FLASH_SECTOR;
|
||||||
@@ -120,6 +122,7 @@ void settings_save(void)
|
|||||||
erase.PageAddress = SETTINGS_FLASH_ADDR;
|
erase.PageAddress = SETTINGS_FLASH_ADDR;
|
||||||
erase.TypeErase = FLASH_TYPEERASE_PAGES;
|
erase.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint32_t pgerror = 0;
|
uint32_t pgerror = 0;
|
||||||
hst = HAL_FLASHEx_Erase(&erase, &pgerror);
|
hst = HAL_FLASHEx_Erase(&erase, &pgerror);
|
||||||
assert_param(pgerror == 0xFFFFFFFFU);
|
assert_param(pgerror == 0xFFFFFFFFU);
|
||||||
@@ -300,7 +303,6 @@ void settings_load_ini_begin(void)
|
|||||||
SystemSettings.loading_inifile = 0;
|
SystemSettings.loading_inifile = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void settings_load_ini_key(const char *restrict section, const char *restrict key, const char *restrict value)
|
void settings_load_ini_key(const char *restrict section, const char *restrict key, const char *restrict value)
|
||||||
{
|
{
|
||||||
// dbg("[%s] %s = %s", section, key, value);
|
// dbg("[%s] %s = %s", section, key, value);
|
||||||
@@ -312,6 +314,7 @@ void settings_load_ini_key(const char *restrict section, const char *restrict ke
|
|||||||
if (streq(section, "SYSTEM")) {
|
if (streq(section, "SYSTEM")) {
|
||||||
if (SystemSettings.loading_inifile == 0) {
|
if (SystemSettings.loading_inifile == 0) {
|
||||||
SystemSettings.loading_inifile = 'S';
|
SystemSettings.loading_inifile = 'S';
|
||||||
|
systemsettings_begin_load();
|
||||||
systemsettings_loadDefaults();
|
systemsettings_loadDefaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,4 +359,8 @@ void settings_load_ini_end(void)
|
|||||||
bool suc = ureg_finalize_all_init();
|
bool suc = ureg_finalize_all_init();
|
||||||
if (!suc) dbg("Some units failed to init!!");
|
if (!suc) dbg("Some units failed to init!!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SystemSettings.loading_inifile == 'S') {
|
||||||
|
systemsettings_finalize_load();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+226
-8
@@ -6,6 +6,16 @@
|
|||||||
#include "system_settings.h"
|
#include "system_settings.h"
|
||||||
#include "utils/str_utils.h"
|
#include "utils/str_utils.h"
|
||||||
#include "platform/lock_jumper.h"
|
#include "platform/lock_jumper.h"
|
||||||
|
#include "cfg_utils.h"
|
||||||
|
#include "resources.h"
|
||||||
|
#include "unit_base.h"
|
||||||
|
#include "platform/debug_uart.h"
|
||||||
|
#include "comm/interfaces.h"
|
||||||
|
|
||||||
|
static void systemsettings_mco_teardown(void);
|
||||||
|
static void systemsettings_mco_init(void);
|
||||||
|
/** Init/deinit debug uart */
|
||||||
|
static void systemsettings_debug_uart_init_deinit(void);
|
||||||
|
|
||||||
struct system_settings SystemSettings;
|
struct system_settings SystemSettings;
|
||||||
|
|
||||||
@@ -14,6 +24,24 @@ void systemsettings_loadDefaults(void)
|
|||||||
{
|
{
|
||||||
SystemSettings.visible_vcom = true;
|
SystemSettings.visible_vcom = true;
|
||||||
SystemSettings.ini_comments = true;
|
SystemSettings.ini_comments = true;
|
||||||
|
SystemSettings.enable_mco = false;
|
||||||
|
SystemSettings.mco_prediv = 7;
|
||||||
|
|
||||||
|
SystemSettings.use_comm_uart = false; // TODO configure those based on compile flags for a particular platform
|
||||||
|
SystemSettings.use_comm_lora = false;
|
||||||
|
SystemSettings.use_comm_nordic = false;
|
||||||
|
SystemSettings.comm_uart_baud = 115200; // TODO
|
||||||
|
|
||||||
|
// just a demo, user must change this
|
||||||
|
SystemSettings.nrf_network[0] = 0x12;
|
||||||
|
SystemSettings.nrf_network[2] = 0x09;
|
||||||
|
SystemSettings.nrf_network[3] = 0x4c;
|
||||||
|
SystemSettings.nrf_network[4] = 0x61;
|
||||||
|
|
||||||
|
SystemSettings.nrf_address = 1;
|
||||||
|
SystemSettings.nrf_channel = 76;
|
||||||
|
|
||||||
|
SystemSettings.enable_debug_uart = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Load defaults and init flags */
|
/** Load defaults and init flags */
|
||||||
@@ -30,18 +58,35 @@ void systemsettings_init(void)
|
|||||||
void systemsettings_save(PayloadBuilder *pb)
|
void systemsettings_save(PayloadBuilder *pb)
|
||||||
{
|
{
|
||||||
pb_char(pb, 'S');
|
pb_char(pb, 'S');
|
||||||
pb_u8(pb, 0); // settings format version
|
pb_u8(pb, 3); // settings format version
|
||||||
|
|
||||||
{ // system settings
|
{ // system settings
|
||||||
pb_bool(pb, SystemSettings.visible_vcom);
|
pb_bool(pb, SystemSettings.visible_vcom);
|
||||||
pb_bool(pb, SystemSettings.ini_comments);
|
pb_bool(pb, SystemSettings.ini_comments);
|
||||||
|
// 1
|
||||||
|
pb_bool(pb, SystemSettings.enable_mco);
|
||||||
|
pb_u8(pb, SystemSettings.mco_prediv);
|
||||||
|
// 2
|
||||||
|
pb_bool(pb, SystemSettings.use_comm_uart);
|
||||||
|
pb_bool(pb, SystemSettings.use_comm_nordic);
|
||||||
|
pb_bool(pb, SystemSettings.use_comm_lora);
|
||||||
|
pb_u32(pb, SystemSettings.comm_uart_baud);
|
||||||
|
pb_bool(pb, SystemSettings.enable_debug_uart);
|
||||||
|
// 3
|
||||||
|
pb_u8(pb, SystemSettings.nrf_channel);
|
||||||
|
pb_u8(pb, SystemSettings.nrf_address);
|
||||||
|
pb_buf(pb, SystemSettings.nrf_network, 4);
|
||||||
} // end system settings
|
} // end system settings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// from binary
|
// from binary
|
||||||
bool systemsettings_load(PayloadParser *pp)
|
bool systemsettings_load(PayloadParser *pp)
|
||||||
{
|
{
|
||||||
if (pp_char(pp) != 'S') return false;
|
if (pp_char(pp) != 'S') return false;
|
||||||
|
|
||||||
|
systemsettings_begin_load();
|
||||||
|
|
||||||
uint8_t version = pp_u8(pp);
|
uint8_t version = pp_u8(pp);
|
||||||
|
|
||||||
{ // system settings
|
{ // system settings
|
||||||
@@ -49,13 +94,80 @@ bool systemsettings_load(PayloadParser *pp)
|
|||||||
SystemSettings.ini_comments = pp_bool(pp);
|
SystemSettings.ini_comments = pp_bool(pp);
|
||||||
|
|
||||||
// conditional fields based on version
|
// conditional fields based on version
|
||||||
(void) version;
|
if (version >= 1) {
|
||||||
|
SystemSettings.enable_mco = pp_bool(pp);
|
||||||
|
SystemSettings.mco_prediv = pp_u8(pp);
|
||||||
|
}
|
||||||
|
if (version >= 2) {
|
||||||
|
SystemSettings.use_comm_uart = pp_bool(pp);
|
||||||
|
SystemSettings.use_comm_nordic = pp_bool(pp);
|
||||||
|
SystemSettings.use_comm_lora = pp_bool(pp);
|
||||||
|
SystemSettings.comm_uart_baud = pp_u32(pp);
|
||||||
|
SystemSettings.enable_debug_uart = pp_bool(pp);
|
||||||
|
}
|
||||||
|
if (version >= 3) {
|
||||||
|
SystemSettings.nrf_channel = pp_u8(pp);
|
||||||
|
SystemSettings.nrf_address = pp_u8(pp);
|
||||||
|
pp_buf(pp, SystemSettings.nrf_network, 4);
|
||||||
|
}
|
||||||
} // end system settings
|
} // end system settings
|
||||||
|
|
||||||
|
systemsettings_finalize_load();
|
||||||
|
|
||||||
return pp->ok;
|
return pp->ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void systemsettings_mco_teardown(void)
|
||||||
|
{
|
||||||
|
if (SystemSettings.enable_mco) {
|
||||||
|
rsc_free(&UNIT_SYSTEM, R_PA8);
|
||||||
|
LL_RCC_ConfigMCO(LL_RCC_MCO1SOURCE_NOCLOCK, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void systemsettings_mco_init(void)
|
||||||
|
{
|
||||||
|
if (SystemSettings.enable_mco) {
|
||||||
|
assert_param(rsc_claim(&UNIT_SYSTEM, R_PA8) == E_SUCCESS);
|
||||||
|
|
||||||
|
assert_param(E_SUCCESS == hw_configure_gpiorsc_af(R_PA8, LL_GPIO_AF_0));
|
||||||
|
LL_RCC_ConfigMCO(LL_RCC_MCO1SOURCE_SYSCLK, SystemSettings.mco_prediv << RCC_CFGR_MCOPRE_Pos);
|
||||||
|
} else {
|
||||||
|
LL_RCC_ConfigMCO(LL_RCC_MCO1SOURCE_NOCLOCK, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void systemsettings_debug_uart_init_deinit(void)
|
||||||
|
{
|
||||||
|
#if USE_DEBUG_UART
|
||||||
|
if (SystemSettings.enable_debug_uart) {
|
||||||
|
DebugUart_Init();
|
||||||
|
} else {
|
||||||
|
DebugUart_Teardown();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin load of system settings, releasing resources etc
|
||||||
|
*/
|
||||||
|
void systemsettings_begin_load(void)
|
||||||
|
{
|
||||||
|
systemsettings_mco_teardown();
|
||||||
|
com_release_resources_for_alt_transfers();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Claim resources and set up system components based on the loaded settings
|
||||||
|
*/
|
||||||
|
void systemsettings_finalize_load(void)
|
||||||
|
{
|
||||||
|
systemsettings_mco_init();
|
||||||
|
systemsettings_debug_uart_init_deinit();
|
||||||
|
com_claim_resources_for_alt_transfers();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write system settings to INI (without section)
|
* Write system settings to INI (without section)
|
||||||
*/
|
*/
|
||||||
@@ -64,10 +176,53 @@ void systemsettings_build_ini(IniWriter *iw)
|
|||||||
iw_section(iw, "SYSTEM");
|
iw_section(iw, "SYSTEM");
|
||||||
|
|
||||||
iw_comment(iw, "Data link accessible as virtual comport (Y, N)");
|
iw_comment(iw, "Data link accessible as virtual comport (Y, N)");
|
||||||
iw_entry(iw, "expose_vcom", str_yn(SystemSettings.visible_vcom));
|
iw_entry_s(iw, "expose-vcom", str_yn(SystemSettings.visible_vcom));
|
||||||
|
|
||||||
iw_comment(iw, "Show comments in INI files (Y, N)");
|
iw_comment(iw, "Show comments in INI files (Y, N)");
|
||||||
iw_entry(iw, "ini_comments", str_yn(SystemSettings.ini_comments));
|
iw_entry_s(iw, "ini-comments", str_yn(SystemSettings.ini_comments));
|
||||||
|
|
||||||
|
iw_comment(iw, "Enable debug UART-Tx on PA9 (Y, N)"); // TODO update if moved to a different pin
|
||||||
|
iw_entry_s(iw, "debug-uart", str_yn(SystemSettings.enable_debug_uart));
|
||||||
|
|
||||||
|
iw_cmt_newline(iw);
|
||||||
|
iw_comment(iw, "Output core clock on PA8 (Y, N)");
|
||||||
|
iw_entry_s(iw, "mco-enable", str_yn(SystemSettings.enable_mco));
|
||||||
|
iw_comment(iw, "Output clock prediv (1,2,...,128)");
|
||||||
|
iw_entry_d(iw, "mco-prediv", (1<<SystemSettings.mco_prediv));
|
||||||
|
|
||||||
|
iw_cmt_newline(iw);
|
||||||
|
iw_comment(iw, "--- Allowed fallback communication ports ---");
|
||||||
|
|
||||||
|
iw_cmt_newline(iw);
|
||||||
|
iw_comment(iw, "UART Tx:PA2, Rx:PA3");
|
||||||
|
iw_entry_s(iw, "com-uart", str_yn(SystemSettings.use_comm_uart));
|
||||||
|
iw_entry_d(iw, "com-uart-baud", SystemSettings.comm_uart_baud);
|
||||||
|
|
||||||
|
#if SUPPORT_NRF
|
||||||
|
iw_cmt_newline(iw);
|
||||||
|
iw_comment(iw, "nRF24L01+ radio");
|
||||||
|
iw_entry_s(iw, "com-nrf", str_yn(SystemSettings.use_comm_nordic));
|
||||||
|
|
||||||
|
iw_comment(iw, "Radio channel (0-125)");
|
||||||
|
iw_entry_d(iw, "nrf-channel", SystemSettings.nrf_channel);
|
||||||
|
|
||||||
|
iw_comment(iw, "Network prefix (hex, 4 bytes)");
|
||||||
|
iw_entry(iw, "nrf-network", "%02X:%02X:%02X:%02X",
|
||||||
|
SystemSettings.nrf_network[0],
|
||||||
|
SystemSettings.nrf_network[1],
|
||||||
|
SystemSettings.nrf_network[2],
|
||||||
|
SystemSettings.nrf_network[3]);
|
||||||
|
|
||||||
|
iw_comment(iw, "Node address (1-255)");
|
||||||
|
iw_entry(iw, "nrf-address", "%d", (int)SystemSettings.nrf_address);
|
||||||
|
#endif // SUPPORT_NRF
|
||||||
|
|
||||||
|
// those aren't implement yet, don't tease the user
|
||||||
|
// TODO show pin-out, extra settings if applicable
|
||||||
|
#if 0
|
||||||
|
iw_comment(iw, "LoRa/GFSK sx127x");
|
||||||
|
iw_entry_s(iw, "com-lora", str_yn(SystemSettings.use_comm_sx127x));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,15 +231,78 @@ void systemsettings_build_ini(IniWriter *iw)
|
|||||||
bool systemsettings_load_ini(const char *restrict key, const char *restrict value)
|
bool systemsettings_load_ini(const char *restrict key, const char *restrict value)
|
||||||
{
|
{
|
||||||
bool suc = true;
|
bool suc = true;
|
||||||
if (streq(key, "expose_vcom")) {
|
if (streq(key, "expose-vcom")) {
|
||||||
bool yn = str_parse_yn(value, &suc);
|
bool yn = cfg_bool_parse(value, &suc);
|
||||||
if (suc) SystemSettings.visible_vcom = yn;
|
if (suc) SystemSettings.visible_vcom = yn;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streq(key, "ini_comments")) {
|
if (streq(key, "ini-comments")) {
|
||||||
bool yn = str_parse_yn(value, &suc);
|
bool yn = cfg_bool_parse(value, &suc);
|
||||||
if (suc) SystemSettings.ini_comments = yn;
|
if (suc) SystemSettings.ini_comments = yn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (streq(key, "mco-enable")) {
|
||||||
|
bool yn = cfg_bool_parse(value, &suc);
|
||||||
|
if (suc) SystemSettings.enable_mco = yn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streq(key, "mco-prediv")) {
|
||||||
|
int val = cfg_u8_parse(value, &suc);
|
||||||
|
if (suc) {
|
||||||
|
switch (val) {
|
||||||
|
case 1: SystemSettings.mco_prediv = 0; break;
|
||||||
|
case 2: SystemSettings.mco_prediv = 1; break;
|
||||||
|
case 4: SystemSettings.mco_prediv = 2; break;
|
||||||
|
case 8: SystemSettings.mco_prediv = 3; break;
|
||||||
|
case 16: SystemSettings.mco_prediv = 4; break;
|
||||||
|
case 32: SystemSettings.mco_prediv = 5; break;
|
||||||
|
case 64: SystemSettings.mco_prediv = 6; break;
|
||||||
|
default:
|
||||||
|
case 128: SystemSettings.mco_prediv = 7; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streq(key, "debug-uart")) {
|
||||||
|
bool yn = cfg_bool_parse(value, &suc);
|
||||||
|
if (suc) SystemSettings.enable_debug_uart = yn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streq(key, "com-uart")) {
|
||||||
|
bool yn = cfg_bool_parse(value, &suc);
|
||||||
|
if (suc) SystemSettings.use_comm_uart = yn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streq(key, "com-uart-baud")) {
|
||||||
|
uint32_t baud = cfg_u32_parse(value, &suc);
|
||||||
|
if (suc) SystemSettings.comm_uart_baud = baud;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SUPPORT_NRF
|
||||||
|
if (streq(key, "com-nrf")) {
|
||||||
|
bool yn = cfg_bool_parse(value, &suc);
|
||||||
|
if (suc) SystemSettings.use_comm_nordic = yn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streq(key, "nrf-channel")) {
|
||||||
|
SystemSettings.nrf_channel = cfg_u8_parse(value, &suc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streq(key, "nrf-address")) {
|
||||||
|
SystemSettings.nrf_address = cfg_u8_parse(value, &suc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streq(key, "nrf-network")) {
|
||||||
|
cfg_hex_parse(&SystemSettings.nrf_network[0], 4, value, &suc);
|
||||||
|
}
|
||||||
|
#endif // SUPPORT_NRF
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (streq(key, "com-lora")) {
|
||||||
|
bool yn = cfg_bool_parse(value, &suc);
|
||||||
|
if (suc) SystemSettings.use_comm_lora = yn;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return suc;
|
return suc;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,18 @@
|
|||||||
struct system_settings {
|
struct system_settings {
|
||||||
bool visible_vcom;
|
bool visible_vcom;
|
||||||
bool ini_comments;
|
bool ini_comments;
|
||||||
|
bool enable_mco;
|
||||||
|
uint8_t mco_prediv;
|
||||||
|
bool enable_debug_uart;
|
||||||
|
|
||||||
|
// enable alternate communication ports if USB doesn't enumerate (e.g. running from battery / solar cell remotely)
|
||||||
|
bool use_comm_uart;
|
||||||
|
uint32_t comm_uart_baud; // baud rate for the uart transport
|
||||||
|
bool use_comm_lora; // SX1276/8
|
||||||
|
bool use_comm_nordic; // nRF24L01+
|
||||||
|
uint8_t nrf_channel;
|
||||||
|
uint8_t nrf_network[4];
|
||||||
|
uint8_t nrf_address;
|
||||||
|
|
||||||
// Support flags put here for scoping, but not atcually part of the persistent settings
|
// Support flags put here for scoping, but not atcually part of the persistent settings
|
||||||
volatile bool editable; //!< True if we booted with the LOCK jumper removed
|
volatile bool editable; //!< True if we booted with the LOCK jumper removed
|
||||||
@@ -60,4 +72,9 @@ void systemsettings_build_ini(IniWriter *iw);
|
|||||||
*/
|
*/
|
||||||
bool systemsettings_load_ini(const char *restrict key, const char *restrict value);
|
bool systemsettings_load_ini(const char *restrict key, const char *restrict value);
|
||||||
|
|
||||||
|
/** Release system resources before system settings init */
|
||||||
|
void systemsettings_begin_load(void);
|
||||||
|
/** Claim system resources and apply system settings */
|
||||||
|
void systemsettings_finalize_load(void);
|
||||||
|
|
||||||
#endif //GEX_SYSTEM_SETTINGS_H
|
#endif //GEX_SYSTEM_SETTINGS_H
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "unit.h"
|
#include "unit.h"
|
||||||
#include "hw_utils.h"
|
#include "hw_utils.h"
|
||||||
|
#include "cfg_utils.h"
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
#include "utils/str_utils.h"
|
#include "utils/str_utils.h"
|
||||||
#include "utils/malloc_safe.h"
|
#include "utils/malloc_safe.h"
|
||||||
|
|||||||
@@ -276,7 +276,7 @@ bool ureg_instantiate_by_ini(const char *restrict driver_name, const char *restr
|
|||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
if (delim != NULL) {
|
if (delim != NULL) {
|
||||||
// not last
|
// not last
|
||||||
name = strndup_ck(p, delim - p);
|
name = strndup_ck(p, delim - p + 1);
|
||||||
p = delim + 1;
|
p = delim + 1;
|
||||||
} else {
|
} else {
|
||||||
// last name
|
// last name
|
||||||
@@ -334,6 +334,7 @@ bool ureg_finalize_all_init(void)
|
|||||||
uint8_t callsign = 1;
|
uint8_t callsign = 1;
|
||||||
while (li != NULL) {
|
while (li != NULL) {
|
||||||
Unit *const pUnit = &li->unit;
|
Unit *const pUnit = &li->unit;
|
||||||
|
dbg("+ %s \"%s\"", pUnit->driver->name, pUnit->name);
|
||||||
|
|
||||||
if (pUnit->status == E_SUCCESS) {
|
if (pUnit->status == E_SUCCESS) {
|
||||||
dbg("! Unit seems already loaded, skipping");
|
dbg("! Unit seems already loaded, skipping");
|
||||||
|
|||||||
+1
-1
@@ -147,7 +147,7 @@ void MX_FREERTOS_Init(void) {
|
|||||||
stackmon_register("Main", mainTaskStack, sizeof(mainTaskStack));
|
stackmon_register("Main", mainTaskStack, sizeof(mainTaskStack));
|
||||||
stackmon_register("Job+Msg", msgJobQueTaskStack, sizeof(msgJobQueTaskStack));
|
stackmon_register("Job+Msg", msgJobQueTaskStack, sizeof(msgJobQueTaskStack));
|
||||||
stackmon_register("Idle", xIdleStack, sizeof(xIdleStack));
|
stackmon_register("Idle", xIdleStack, sizeof(xIdleStack));
|
||||||
stackmon_register("Timers", xTimersStack, sizeof(xTimersStack));
|
// stackmon_register("Timers", xTimersStack, sizeof(xTimersStack));
|
||||||
/* USER CODE END Init */
|
/* USER CODE END Init */
|
||||||
|
|
||||||
/* Create the mutex(es) */
|
/* Create the mutex(es) */
|
||||||
|
|||||||
@@ -1,58 +1,28 @@
|
|||||||
GEX_SRC_DIR = \
|
#####################################################
|
||||||
User \
|
# Platform-independent, not directly related to GEX
|
||||||
User/utils \
|
#####################################################
|
||||||
User/comm \
|
|
||||||
User/framework \
|
|
||||||
User/platform \
|
|
||||||
User/units \
|
|
||||||
User/units/neopixel \
|
|
||||||
User/units/test \
|
|
||||||
User/units/digital_out \
|
|
||||||
User/units/digital_in \
|
|
||||||
User/units/usart \
|
|
||||||
User/units/1wire \
|
|
||||||
User/units/i2c \
|
|
||||||
User/units/spi \
|
|
||||||
User/units/adc \
|
|
||||||
User/units/sipo \
|
|
||||||
User/units/fcap \
|
|
||||||
User/TinyFrame \
|
|
||||||
User/CWPack \
|
|
||||||
User/tasks
|
|
||||||
|
|
||||||
GEX_SOURCES = \
|
# C
|
||||||
User/USB/usb_device.c \
|
COMMON_C_DIRS = \
|
||||||
User/USB/usbd_cdc_if.c \
|
Drivers \
|
||||||
User/USB/usbd_conf.c \
|
Drivers/CMSIS \
|
||||||
User/USB/usbd_desc.c \
|
Middlewares \
|
||||||
User/USB/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c \
|
Middlewares/FreeRTOS
|
||||||
User/USB/STM32_USB_Device_Library/Class/MSC_CDC/usbd_msc_cdc.c \
|
|
||||||
User/USB/STM32_USB_Device_Library/Core/Src/usbd_core.c \
|
|
||||||
User/USB/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c \
|
|
||||||
User/USB/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c
|
|
||||||
|
|
||||||
GEX_INCLUDES = \
|
COMMON_C_FILES = \
|
||||||
-IUser \
|
Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.c \
|
||||||
-IUser/USB \
|
Middlewares/Third_Party/FreeRTOS/Source/croutine.c \
|
||||||
-IUser/USB/MSC_CDC \
|
Middlewares/Third_Party/FreeRTOS/Source/event_groups.c \
|
||||||
-IUser/TinyFrame \
|
Middlewares/Third_Party/FreeRTOS/Source/list.c \
|
||||||
-IUser/vfs \
|
Middlewares/Third_Party/FreeRTOS/Source/queue.c \
|
||||||
-IUser/utils \
|
Middlewares/Third_Party/FreeRTOS/Source/tasks.c \
|
||||||
-IUser/units \
|
Middlewares/Third_Party/FreeRTOS/Source/timers.c \
|
||||||
-IUser/framework \
|
Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c \
|
||||||
-IUser/platform \
|
Src/main.c
|
||||||
-IUser/tasks \
|
|
||||||
-IUser/USB/STM32_USB_Device_Library/Core/Inc \
|
|
||||||
-IUser/USB/STM32_USB_Device_Library/Class/AUDIO/Inc \
|
|
||||||
-IUser/USB/STM32_USB_Device_Library/Class/CDC/Inc \
|
|
||||||
-IUser/USB/STM32_USB_Device_Library/Class/CustomHID/Inc \
|
|
||||||
-IUser/USB/STM32_USB_Device_Library/Class/DFU/Inc \
|
|
||||||
-IUser/USB/STM32_USB_Device_Library/Class/HID/Inc \
|
|
||||||
-IUser/USB/STM32_USB_Device_Library/Class/MSC/Inc \
|
|
||||||
-IUser/USB/STM32_USB_Device_Library/Class/MSC_CDC
|
|
||||||
|
|
||||||
GEX_CFLAGS = \
|
COMMON_C_FLAGS = \
|
||||||
-D__weak="__attribute__((weak))" -D__packed="__attribute__((__packed__))" \
|
-DUSE_HAL_DRIVER \
|
||||||
|
-DUSE_FULL_LL_DRIVER \
|
||||||
-std=gnu99 -Wfatal-errors \
|
-std=gnu99 -Wfatal-errors \
|
||||||
-Wall -Wextra -Wshadow \
|
-Wall -Wextra -Wshadow \
|
||||||
-Wwrite-strings -Wold-style-definition -Winline -Wstrict-prototypes -Wreturn-type \
|
-Wwrite-strings -Wold-style-definition -Winline -Wstrict-prototypes -Wreturn-type \
|
||||||
@@ -64,16 +34,88 @@ GEX_CFLAGS = \
|
|||||||
-fno-exceptions -finline-small-functions -findirect-inlining -Wno-strict-aliasing -Wno-float-equal \
|
-fno-exceptions -finline-small-functions -findirect-inlining -Wno-strict-aliasing -Wno-float-equal \
|
||||||
-Wno-discarded-qualifiers -fstack-usage
|
-Wno-discarded-qualifiers -fstack-usage
|
||||||
|
|
||||||
GEX_CDEFS_BASE = \
|
ifeq ($(DEBUG), 1)
|
||||||
|
COMMON_C_FLAGS += -ggdb -g -gdwarf-2
|
||||||
|
endif
|
||||||
|
|
||||||
|
COMMON_C_INCLUDES = \
|
||||||
|
-IInc \
|
||||||
|
-IMiddlewares/Third_Party/FreeRTOS/Source/include \
|
||||||
|
-IMiddlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS \
|
||||||
|
-IDrivers/CMSIS/Include
|
||||||
|
|
||||||
|
# ASM
|
||||||
|
COMMON_AS_DIRS = \
|
||||||
|
|
||||||
|
COMMON_AS_FILES = \
|
||||||
|
|
||||||
|
COMMON_AS_FLAGS = \
|
||||||
|
-Wall -fdata-sections -ffunction-sections
|
||||||
|
|
||||||
|
COMMON_AS_INCLUDES = \
|
||||||
|
-IInc
|
||||||
|
|
||||||
|
#####################################################
|
||||||
|
# Platform-independent, GEX specific
|
||||||
|
#####################################################
|
||||||
|
|
||||||
|
GEX_UNIT_DIRS := $(foreach x,$(GEX_UNITS), GexUnits/$(x))
|
||||||
|
GEX_UNIT_DEFS := $(foreach x,$(GEX_UNITS), -DENABLE_UNIT_$(shell echo $(x) | tr a-z A-Z)=1) \
|
||||||
|
-DUNITS_REGISTER_CMD="$(foreach x,$(GEX_UNITS),ureg_add_type(&UNIT_$(shell echo $(x) | tr a-z A-Z));)"
|
||||||
|
|
||||||
|
GEX_C_DIRS = \
|
||||||
|
GexCore \
|
||||||
|
GexCore/utils \
|
||||||
|
GexCore/comm \
|
||||||
|
GexCore/framework \
|
||||||
|
GexCore/platform \
|
||||||
|
GexCore/units \
|
||||||
|
GexCore/TinyFrame \
|
||||||
|
GexCore/tasks \
|
||||||
|
$(GEX_UNIT_DIRS)
|
||||||
|
|
||||||
|
GEX_C_FILES = \
|
||||||
|
GexCore/USB/usb_device.c \
|
||||||
|
GexCore/USB/usbd_cdc_if.c \
|
||||||
|
GexCore/USB/usbd_conf.c \
|
||||||
|
GexCore/USB/usbd_desc.c \
|
||||||
|
GexCore/USB/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c \
|
||||||
|
GexCore/USB/STM32_USB_Device_Library/Class/MSC_CDC/usbd_msc_cdc.c \
|
||||||
|
GexCore/USB/STM32_USB_Device_Library/Core/Src/usbd_core.c \
|
||||||
|
GexCore/USB/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c \
|
||||||
|
GexCore/USB/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c \
|
||||||
|
Src/platform_resources.c
|
||||||
|
|
||||||
|
GEX_C_INCLUDES = \
|
||||||
|
-IGexUnits \
|
||||||
|
-IGexCore \
|
||||||
|
-IGexCore/USB \
|
||||||
|
-IGexCore/USB/MSC_CDC \
|
||||||
|
-IGexCore/TinyFrame \
|
||||||
|
-IGexCore/vfs \
|
||||||
|
-IGexCore/utils \
|
||||||
|
-IGexCore/units \
|
||||||
|
-IGexCore/framework \
|
||||||
|
-IGexCore/platform \
|
||||||
|
-IGexCore/tasks \
|
||||||
|
-IGexCore/USB/STM32_USB_Device_Library/Core/Inc \
|
||||||
|
-IGexCore/USB/STM32_USB_Device_Library/Class/AUDIO/Inc \
|
||||||
|
-IGexCore/USB/STM32_USB_Device_Library/Class/CDC/Inc \
|
||||||
|
-IGexCore/USB/STM32_USB_Device_Library/Class/CustomHID/Inc \
|
||||||
|
-IGexCore/USB/STM32_USB_Device_Library/Class/DFU/Inc \
|
||||||
|
-IGexCore/USB/STM32_USB_Device_Library/Class/HID/Inc \
|
||||||
|
-IGexCore/USB/STM32_USB_Device_Library/Class/MSC/Inc \
|
||||||
|
-IGexCore/USB/STM32_USB_Device_Library/Class/MSC_CDC
|
||||||
|
|
||||||
|
GEX_C_FLAGS := \
|
||||||
|
-DGEX_PLAT_$(GEX_PLAT) \
|
||||||
-D__weak="__attribute__((weak))" \
|
-D__weak="__attribute__((weak))" \
|
||||||
-D__packed="__attribute__((__packed__))" \
|
-D__packed="__attribute__((__packed__))" \
|
||||||
-DUSE_FULL_LL_DRIVER \
|
$(GEX_UNIT_DEFS)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Option to disable debug
|
||||||
ifeq '$(DISABLE_DEBUG)' '1'
|
ifeq '$(DISABLE_DEBUG)' '1'
|
||||||
|
GEX_C_FLAGS += \
|
||||||
GEX_CDEFS = $(GEX_CDEFS_BASE) \
|
|
||||||
-DUSE_FULL_ASSERT=0 \
|
-DUSE_FULL_ASSERT=0 \
|
||||||
-DASSERT_FILENAMES=0 \
|
-DASSERT_FILENAMES=0 \
|
||||||
-DDEBUG_VFS=0 \
|
-DDEBUG_VFS=0 \
|
||||||
@@ -83,45 +125,177 @@ GEX_CDEFS = $(GEX_CDEFS_BASE) \
|
|||||||
-DUSE_DEBUG_UART=0 \
|
-DUSE_DEBUG_UART=0 \
|
||||||
-DDEBUG_MALLOC=0 \
|
-DDEBUG_MALLOC=0 \
|
||||||
-DDEBUG_RSC=0
|
-DDEBUG_RSC=0
|
||||||
|
|
||||||
else
|
else
|
||||||
|
GEX_C_FLAGS += \
|
||||||
GEX_CDEFS = $(GEX_CDEFS_BASE) \
|
|
||||||
-DUSE_FULL_ASSERT=1 \
|
-DUSE_FULL_ASSERT=1 \
|
||||||
-DASSERT_FILENAMES=1 \
|
-DASSERT_FILENAMES=1 \
|
||||||
-DDEBUG_VFS=0 \
|
-DDEBUG_VFS=0 \
|
||||||
-DDEBUG_FLASH_WRITE=0 \
|
-DDEBUG_FLASH_WRITE=0 \
|
||||||
-DVERBOSE_HARDFAULT=1 \
|
-DVERBOSE_HARDFAULT=1 \
|
||||||
-DUSE_STACK_MONITOR=1 \
|
-DUSE_STACK_MONITOR=0 \
|
||||||
-DUSE_DEBUG_UART=1 \
|
-DUSE_DEBUG_UART=1 \
|
||||||
-DDEBUG_MALLOC=0 \
|
-DDEBUG_MALLOC=0 \
|
||||||
-DDEBUG_RSC=0
|
-DDEBUG_RSC=0
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
# Option to disable mass storage
|
||||||
ifeq '$(DISABLE_MSC)' '1'
|
ifeq '$(DISABLE_MSC)' '1'
|
||||||
|
GEX_C_FLAGS += -DDISABLE_MSC
|
||||||
GEX_CDEFS += -DDISABLE_MSC
|
|
||||||
|
|
||||||
else
|
else
|
||||||
|
GEX_C_FILES += \
|
||||||
GEX_SOURCES += \
|
GexCore/USB/usbd_storage_if.c \
|
||||||
User/USB/usbd_storage_if.c \
|
GexCore/USB/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc.c \
|
||||||
User/USB/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc.c \
|
GexCore/USB/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_bot.c \
|
||||||
User/USB/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_bot.c \
|
GexCore/USB/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_data.c \
|
||||||
User/USB/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_data.c \
|
GexCore/USB/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_scsi.c
|
||||||
User/USB/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_scsi.c
|
GEX_C_DIRS += \
|
||||||
|
GexCore/vfs
|
||||||
GEX_SRC_DIR += \
|
|
||||||
User/vfs
|
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq '$(DISABLE_TEST_UNIT)' '1'
|
|
||||||
GEX_CDEFS += -DDISABLE_TEST_UNIT=1
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
# Option to enable CDC loopback (testing USB)
|
||||||
ifeq '$(CDC_LOOPBACK_TEST)' '1'
|
ifeq '$(CDC_LOOPBACK_TEST)' '1'
|
||||||
GEX_CDEFS += -DCDC_LOOPBACK_TEST=1
|
GEX_C_FLAGS += -DCDC_LOOPBACK_TEST=1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
#####################################################
|
||||||
|
# Common build infrastructure
|
||||||
|
#####################################################
|
||||||
|
|
||||||
|
# Build path
|
||||||
|
BUILD_DIR = build
|
||||||
|
# target
|
||||||
|
TARGET = firmware
|
||||||
|
# Specs (determines which stdlib version is included)
|
||||||
|
SPECS = nano.specs
|
||||||
|
|
||||||
|
C_SOURCES := \
|
||||||
|
$(COMMON_C_FILES) $(PLAT_C_FILES) $(GEX_C_FILES) \
|
||||||
|
$(foreach x,$(COMMON_C_DIRS),$(wildcard $(x)/*.c)) \
|
||||||
|
$(foreach x,$(PLAT_C_DIRS),$(wildcard $(x)/*.c)) \
|
||||||
|
$(foreach x,$(GEX_C_DIRS),$(wildcard $(x)/*.c)) \
|
||||||
|
|
||||||
|
AS_SOURCES := \
|
||||||
|
$(COMMON_AS_FILES) $(PLAT_AS_FILES) $(GEX_AS_FILES)
|
||||||
|
$(foreach x,$(COMMON_AS_DIRS),$(wildcard $(x)/*.s)) \
|
||||||
|
$(foreach x,$(PLAT_AS_DIRS),$(wildcard $(x)/*.s)) \
|
||||||
|
$(foreach x,$(GEX_AS_DIRS),$(wildcard $(x)/*.s))
|
||||||
|
|
||||||
|
# mcu
|
||||||
|
MCU := $(PLAT_CPU) -mthumb $(PLAT_FPU) $(PLAT_FLOAT-ABI)
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# binaries
|
||||||
|
#######################################
|
||||||
|
BINPATH = /usr/bin
|
||||||
|
PREFIX = arm-none-eabi-
|
||||||
|
CC := $(BINPATH)/$(PREFIX)gcc
|
||||||
|
AS := $(BINPATH)/$(PREFIX)gcc -x assembler-with-cpp
|
||||||
|
CP := $(BINPATH)/$(PREFIX)objcopy
|
||||||
|
AR := $(BINPATH)/$(PREFIX)ar
|
||||||
|
SZ := $(BINPATH)/$(PREFIX)size
|
||||||
|
HEX := $(CP) -O ihex
|
||||||
|
BIN := $(CP) -O binary -S
|
||||||
|
|
||||||
|
|
||||||
|
LIBS = -lc -lm -lnosys
|
||||||
|
LDFLAGS := \
|
||||||
|
$(MCU) -specs=$(SPECS) -T$(PLAT_LDSCRIPT) $(LIBS) \
|
||||||
|
-Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref \
|
||||||
|
-Wl,--gc-sections
|
||||||
|
|
||||||
|
# optimization (possible to set in build.mk)
|
||||||
|
ifeq ($(OPT),)
|
||||||
|
OPT = -Os
|
||||||
|
endif
|
||||||
|
|
||||||
|
C_FLAGS := \
|
||||||
|
$(MCU) $(OPT) \
|
||||||
|
$(GEX_C_INCLUDES) $(PLAT_C_INCLUDES) $(COMMON_C_INCLUDES) \
|
||||||
|
$(GEX_C_FLAGS) $(PLAT_C_FLAGS) $(COMMON_C_FLAGS)
|
||||||
|
|
||||||
|
AS_FLAGS := \
|
||||||
|
$(MCU) $(OPT) \
|
||||||
|
$(GEX_AS_INCLUDES) $(PLAT_AS_INCLUDES) $(COMMON_AS_INCLUDES) \
|
||||||
|
$(GEX_AS_FLAGS) $(PLAT_AS_FLAGS) $(COMMON_AS_FLAGS)
|
||||||
|
|
||||||
|
|
||||||
|
# Generate dependency information
|
||||||
|
DEPENDENCY_TRACKER = -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)"
|
||||||
|
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Targets
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
# # list of objects
|
||||||
|
# OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))
|
||||||
|
# vpath %.c $(sort $(dir $(C_SOURCES)))
|
||||||
|
# # list of ASM program objects
|
||||||
|
# OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(AS_SOURCES:.s=.o)))
|
||||||
|
# vpath %.s $(sort $(dir $(AS_SOURCES)))
|
||||||
|
|
||||||
|
# list of objects
|
||||||
|
OBJECTS := $(addprefix $(BUILD_DIR)/,$(C_SOURCES:.c=.o)) \
|
||||||
|
$(addprefix $(BUILD_DIR)/,$(AS_SOURCES:.s=.o))
|
||||||
|
|
||||||
|
vpath %.c $(sort $(dir $(C_SOURCES)))
|
||||||
|
vpath %.s $(sort $(dir $(AS_SOURCES)))
|
||||||
|
|
||||||
|
MAKEFILES = Makefile GexCore/gex.mk build.mk
|
||||||
|
|
||||||
|
# default action: build all
|
||||||
|
all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
|
||||||
|
|
||||||
|
$(BUILD_DIR)/%.o: %.c $(MAKEFILES) | $(BUILD_DIR)
|
||||||
|
@echo -e "\x1b[32mCC\x1b[m $<\n \x1b[90m-> $@\x1b[m"
|
||||||
|
@mkdir -p `dirname "$(BUILD_DIR)/$(<)"`
|
||||||
|
@$(CC) -c $(C_FLAGS) $(DEPENDENCY_TRACKER) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(<:.c=.lst) $< -o $@
|
||||||
|
|
||||||
|
$(BUILD_DIR)/%.o: %.s $(MAKEFILES) | $(BUILD_DIR)
|
||||||
|
@$(AS) -c $(C_FLAGS) $(DEPENDENCY_TRACKER) $< -o $@
|
||||||
|
|
||||||
|
$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) $(MAKEFILES)
|
||||||
|
@printf "LD $< -> $@\n"
|
||||||
|
$(CC) $(OBJECTS) $(LDFLAGS) -o $@
|
||||||
|
@$(SZ) $@
|
||||||
|
|
||||||
|
$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf $(MAKEFILES) | $(BUILD_DIR)
|
||||||
|
@printf "OBJDUMP $< -> $(BUILD_DIR)/$(TARGET).hex \n"
|
||||||
|
@$(HEX) $< $@
|
||||||
|
|
||||||
|
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf $(MAKEFILES) | $(BUILD_DIR)
|
||||||
|
@printf "OBJDUMP $< -> $(BUILD_DIR)/$(TARGET).bin \n"
|
||||||
|
@$(BIN) $< $@
|
||||||
|
|
||||||
|
flash: $(BUILD_DIR)/$(TARGET).bin $(MAKEFILES)
|
||||||
|
@printf "FLASH $<\n"
|
||||||
|
@st-flash write $< 0x8000000
|
||||||
|
|
||||||
|
$(BUILD_DIR)/$(TARGET).dfu: $(BUILD_DIR)/$(TARGET).hex $(MAKEFILES)
|
||||||
|
@printf "DFU GEN $<\n"
|
||||||
|
dfu-convert -i $< $@
|
||||||
|
|
||||||
|
dfu: $(BUILD_DIR)/$(TARGET).dfu $(MAKEFILES)
|
||||||
|
@printf "DFU UPLOAD $<\n"
|
||||||
|
dfu-util -a 0 -D $<
|
||||||
|
|
||||||
|
dis: $(BUILD_DIR)/$(TARGET).elf $(MAKEFILES)
|
||||||
|
@printf "DIS $<\n"
|
||||||
|
@arm-none-eabi-objdump -Sslrtd build/$(TARGET).elf > disassembly.lst
|
||||||
|
|
||||||
|
$(BUILD_DIR):
|
||||||
|
@mkdir -p $@
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# clean up
|
||||||
|
#######################################
|
||||||
|
clean:
|
||||||
|
-rm -fR .dep $(BUILD_DIR)
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# dependencies
|
||||||
|
#######################################
|
||||||
|
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
|
||||||
|
|||||||
+23
@@ -10,12 +10,18 @@
|
|||||||
#include "platform/debug_uart.h"
|
#include "platform/debug_uart.h"
|
||||||
#include "gex_hooks.h"
|
#include "gex_hooks.h"
|
||||||
#include "unit_registry.h"
|
#include "unit_registry.h"
|
||||||
|
#include "comm/interfaces.h"
|
||||||
|
#include "system_settings.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a systick callback for GEX application logic
|
* This is a systick callback for GEX application logic
|
||||||
*/
|
*/
|
||||||
void GEX_MsTick(void)
|
void GEX_MsTick(void)
|
||||||
{
|
{
|
||||||
|
if (gActiveComport == COMPORT_USART) {
|
||||||
|
com_iface_flush_buffer();
|
||||||
|
}
|
||||||
|
|
||||||
TF_Tick(comm);
|
TF_Tick(comm);
|
||||||
Indicator_Tick();
|
Indicator_Tick();
|
||||||
ureg_tick_units();
|
ureg_tick_units();
|
||||||
@@ -26,6 +32,11 @@ void GEX_MsTick(void)
|
|||||||
*/
|
*/
|
||||||
void GEX_PreInit(void)
|
void GEX_PreInit(void)
|
||||||
{
|
{
|
||||||
|
// this is a hack to make logging of the initial messages work
|
||||||
|
// it's problematic because we shouldn't even enable the debug uart if it's disabled in the system settings
|
||||||
|
// TODO move system settings load earlier and check the uart flag in advance
|
||||||
|
SystemSettings.enable_debug_uart = true;
|
||||||
|
|
||||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||||
@@ -43,6 +54,18 @@ void GEX_PreInit(void)
|
|||||||
dbg("\r\n\033[37;1m*** GEX "GEX_VERSION" on "GEX_PLATFORM" ***\033[m");
|
dbg("\r\n\033[37;1m*** GEX "GEX_VERSION" on "GEX_PLATFORM" ***\033[m");
|
||||||
dbg("Build "__DATE__" "__TIME__);
|
dbg("Build "__DATE__" "__TIME__);
|
||||||
|
|
||||||
|
PRINTF("Reset cause:");
|
||||||
|
if (LL_RCC_IsActiveFlag_LPWRRST()) PRINTF(" LPWR");
|
||||||
|
if (LL_RCC_IsActiveFlag_WWDGRST()) PRINTF(" WWDG");
|
||||||
|
if (LL_RCC_IsActiveFlag_IWDGRST()) PRINTF(" IWDG");
|
||||||
|
if (LL_RCC_IsActiveFlag_SFTRST()) PRINTF(" SFT");
|
||||||
|
if (LL_RCC_IsActiveFlag_PORRST()) PRINTF(" POR");
|
||||||
|
if (LL_RCC_IsActiveFlag_PINRST()) PRINTF(" PIN");
|
||||||
|
if (LL_RCC_IsActiveFlag_OBLRST()) PRINTF(" OBL");
|
||||||
|
if (LL_RCC_IsActiveFlag_V18PWRRST()) PRINTF(" V18PWR");
|
||||||
|
PUTNL();
|
||||||
|
LL_RCC_ClearResetFlags();
|
||||||
|
|
||||||
plat_init();
|
plat_init();
|
||||||
|
|
||||||
MX_USB_DEVICE_Init();
|
MX_USB_DEVICE_Init();
|
||||||
|
|||||||
@@ -0,0 +1,342 @@
|
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/02/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "cfg_utils.h"
|
||||||
|
#include "hw_utils.h"
|
||||||
|
#include "utils/avrlibc.h"
|
||||||
|
#include "utils/str_utils.h"
|
||||||
|
|
||||||
|
/** Parse a string representation of a pin directly to a resource constant */
|
||||||
|
Resource cfg_pinrsc_parse(const char *str, bool *suc)
|
||||||
|
{
|
||||||
|
char pname;
|
||||||
|
uint8_t pnum;
|
||||||
|
|
||||||
|
if (!cfg_portpin_parse(str, &pname, &pnum)) {
|
||||||
|
*suc = false;
|
||||||
|
return R_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rsc_portpin2rsc(pname, pnum, suc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert a resource to a pin name - uses a static buffer, result must not be stored! */
|
||||||
|
char *cfg_pinrsc_encode(Resource rsc)
|
||||||
|
{
|
||||||
|
static char buf[4];
|
||||||
|
uint32_t index = rsc - R_PA0;
|
||||||
|
uint32_t portnum = (index/16);
|
||||||
|
uint8_t pinnum = (uint8_t) (index % 16);
|
||||||
|
if (portnum >= PORTS_COUNT) return "";
|
||||||
|
buf[0] = (char) ('A' + portnum);
|
||||||
|
if (pinnum>9) {
|
||||||
|
buf[1] = '1';
|
||||||
|
buf[2] = (char) ('0' + (pinnum - 10));
|
||||||
|
buf[3] = 0;
|
||||||
|
} else {
|
||||||
|
buf[1] = (char) ('0' + pinnum);
|
||||||
|
buf[2] = 0;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parse single pin */
|
||||||
|
bool cfg_portpin_parse(const char *value, char *targetName, uint8_t *targetNumber)
|
||||||
|
{
|
||||||
|
// discard leading 'P'
|
||||||
|
if (value[0] == 'P') {
|
||||||
|
value++;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = strlen(value);
|
||||||
|
if (len<2||len>3) return false;
|
||||||
|
|
||||||
|
*targetName = (uint8_t) value[0];
|
||||||
|
if (!(*targetName >= 'A' && *targetName <= 'H')) return false;
|
||||||
|
|
||||||
|
// lets just hope it's OK
|
||||||
|
*targetNumber = (uint8_t) avr_atoi(value + 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parse port name */
|
||||||
|
bool cfg_port_parse(const char *value, char *targetName)
|
||||||
|
{
|
||||||
|
*targetName = (uint8_t) value[0];
|
||||||
|
if (!(*targetName >= 'A' && *targetName < 'A' + PORTS_COUNT)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parse a list of pin numbers with ranges and commans/semicolons to a bitmask */
|
||||||
|
uint32_t cfg_pinmask_parse_32(const char *value, bool *suc)
|
||||||
|
{
|
||||||
|
uint32_t bits = 0;
|
||||||
|
uint32_t acu = 0;
|
||||||
|
bool inrange = false;
|
||||||
|
uint32_t rangestart = 0;
|
||||||
|
|
||||||
|
// shortcut if none are set
|
||||||
|
if (value[0] == 0) return 0;
|
||||||
|
|
||||||
|
char c;
|
||||||
|
do {
|
||||||
|
c = *value++;
|
||||||
|
if (c == ' ' || c == '\t') {
|
||||||
|
// skip
|
||||||
|
}
|
||||||
|
else if (c >= '0' && c <= '9') {
|
||||||
|
acu = acu*10 + (c-'0');
|
||||||
|
}
|
||||||
|
else if (c == ',' || c == ';' || c == 0) {
|
||||||
|
// end of number or range
|
||||||
|
if (!inrange) rangestart = acu;
|
||||||
|
|
||||||
|
// swap them if they're in the wrong order
|
||||||
|
if (acu < rangestart) {
|
||||||
|
uint32_t swp = acu;
|
||||||
|
acu = rangestart;
|
||||||
|
rangestart = swp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rangestart > 31) rangestart = 31;
|
||||||
|
if (acu > 31) acu = 31;
|
||||||
|
|
||||||
|
for(uint32_t i=rangestart; i <= acu; i++) {
|
||||||
|
bits |= 1<<i;
|
||||||
|
}
|
||||||
|
|
||||||
|
inrange = false;
|
||||||
|
rangestart = 0;
|
||||||
|
acu = 0;
|
||||||
|
}
|
||||||
|
else if (c == '-' || c == ':') {
|
||||||
|
rangestart = acu;
|
||||||
|
inrange = true;
|
||||||
|
acu=0;
|
||||||
|
} else {
|
||||||
|
*suc = false;
|
||||||
|
}
|
||||||
|
} while (c != 0);
|
||||||
|
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert a pin bitmask to the ASCII format understood by str_parse_pinmask() */
|
||||||
|
char *cfg_pinmask_encode(uint32_t pins, char *buffer, bool ascending)
|
||||||
|
{
|
||||||
|
char *b = buffer;
|
||||||
|
uint32_t start = 0;
|
||||||
|
bool on = false;
|
||||||
|
bool first = true;
|
||||||
|
bool bit;
|
||||||
|
|
||||||
|
// shortcut if none are set
|
||||||
|
if (pins == 0) {
|
||||||
|
buffer[0] = 0;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ascending) {
|
||||||
|
for (int32_t i = 0; i <= 32; i++) {
|
||||||
|
if (i == 32) {
|
||||||
|
bit = false;
|
||||||
|
} else {
|
||||||
|
bit = 0 != (pins & 1);
|
||||||
|
pins >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bit) {
|
||||||
|
if (!on) {
|
||||||
|
start = (uint32_t) i;
|
||||||
|
on = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (on) {
|
||||||
|
if (!first) {
|
||||||
|
b += SPRINTF(b, ", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start == (uint32_t)(i - 1)) {
|
||||||
|
b += SPRINTF(b, "%"PRIu32, start);
|
||||||
|
} else {
|
||||||
|
b += SPRINTF(b, "%"PRIu32"-%"PRIu32, start, i - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
first = false;
|
||||||
|
on = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int32_t i = 31; i >= -1; i--) {
|
||||||
|
if (i == -1) {
|
||||||
|
bit = false;
|
||||||
|
} else {
|
||||||
|
bit = 0 != (pins & 0x80000000);
|
||||||
|
pins <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bit) {
|
||||||
|
if (!on) {
|
||||||
|
start = (uint32_t) i;
|
||||||
|
on = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (on) {
|
||||||
|
if (!first) {
|
||||||
|
b += SPRINTF(b, ", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start == (uint32_t) (i + 1)) {
|
||||||
|
b += SPRINTF(b, "%"PRIu32, start);
|
||||||
|
} else {
|
||||||
|
b += SPRINTF(b, "%"PRIu32"-%"PRIu32, start, i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
first = false;
|
||||||
|
on = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cfg_bool_parse(const char *str, bool *suc)
|
||||||
|
{
|
||||||
|
// TODO implement strcasecmp without the locale crap from newlib and use it here
|
||||||
|
if (streq(str, "Y")) return true;
|
||||||
|
if (streq(str, "N")) return false;
|
||||||
|
|
||||||
|
if (streq(str, "1")) return true;
|
||||||
|
if (streq(str, "0")) return false;
|
||||||
|
|
||||||
|
if (streq(str, "H")) return true;
|
||||||
|
if (streq(str, "L")) return false;
|
||||||
|
|
||||||
|
if (streq(str, "YES")) return true;
|
||||||
|
if (streq(str, "NO")) return false;
|
||||||
|
|
||||||
|
if (streq(str, "ON")) return true;
|
||||||
|
if (streq(str, "OFF")) return false;
|
||||||
|
|
||||||
|
*suc = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert number to one of 2 options */
|
||||||
|
const char *cfg_enum2_encode(uint32_t n,
|
||||||
|
uint32_t na, const char *a,
|
||||||
|
uint32_t nb, const char *b)
|
||||||
|
{
|
||||||
|
if (n == nb) return b;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert number to one of 3 options */
|
||||||
|
const char *cfg_enum3_encode(uint32_t n,
|
||||||
|
uint32_t na, const char *a,
|
||||||
|
uint32_t nb, const char *b,
|
||||||
|
uint32_t nc, const char *c)
|
||||||
|
{
|
||||||
|
if (n == nb) return b;
|
||||||
|
if (n == nc) return c;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert number to one of 4 options */
|
||||||
|
const char *cfg_enum4_encode(uint32_t n,
|
||||||
|
uint32_t na, const char *a,
|
||||||
|
uint32_t nb, const char *b,
|
||||||
|
uint32_t nc, const char *c,
|
||||||
|
uint32_t nd, const char *d)
|
||||||
|
{
|
||||||
|
if (n == nb) return b;
|
||||||
|
if (n == nc) return c;
|
||||||
|
if (n == nd) return d;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t cfg_enum2_parse(const char *value,
|
||||||
|
const char *a, uint32_t na,
|
||||||
|
const char *b, uint32_t nb,
|
||||||
|
bool *suc)
|
||||||
|
{
|
||||||
|
if (streq(value, a)) return na;
|
||||||
|
if (streq(value, b)) return nb;
|
||||||
|
*suc = false;
|
||||||
|
return na;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t cfg_enum3_parse(const char *value,
|
||||||
|
const char *a, uint32_t na,
|
||||||
|
const char *b, uint32_t nb,
|
||||||
|
const char *c, uint32_t nc,
|
||||||
|
bool *suc)
|
||||||
|
{
|
||||||
|
if (streq(value, a)) return na;
|
||||||
|
if (streq(value, b)) return nb;
|
||||||
|
if (streq(value, c)) return nc;
|
||||||
|
*suc = false;
|
||||||
|
return na;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t cfg_enum4_parse(const char *value,
|
||||||
|
const char *a, uint32_t na,
|
||||||
|
const char *b, uint32_t nb,
|
||||||
|
const char *c, uint32_t nc,
|
||||||
|
const char *d, uint32_t nd,
|
||||||
|
bool *suc)
|
||||||
|
{
|
||||||
|
if (streq(value, a)) return na;
|
||||||
|
if (streq(value, b)) return nb;
|
||||||
|
if (streq(value, c)) return nc;
|
||||||
|
if (streq(value, d)) return nd;
|
||||||
|
*suc = false;
|
||||||
|
return na;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cfg_hex_parse(uint8_t *dest, uint32_t count, const char *value, bool *suc)
|
||||||
|
{
|
||||||
|
// discard possible leading 0x
|
||||||
|
if (value[0] == '0' && value[1] == 'x') {
|
||||||
|
value += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t bytebuf = 0;
|
||||||
|
for (uint32_t digit = 0; digit < count * 2;) {
|
||||||
|
char v = *value;
|
||||||
|
if (v != 0) value++;
|
||||||
|
|
||||||
|
uint8_t nibble = 0;
|
||||||
|
if (v == ' ' || v == '.' || v == ',' || v == '-' || v == ':') {
|
||||||
|
continue; // junk
|
||||||
|
}
|
||||||
|
else if (v >= '0' && v <= '9') {
|
||||||
|
nibble = (uint8_t) (v - '0');
|
||||||
|
}
|
||||||
|
else if (v >= 'a' && v <= 'f') {
|
||||||
|
nibble = (uint8_t) (10 + (v - 'a'));
|
||||||
|
}
|
||||||
|
else if (v >= 'A' && v <= 'F') {
|
||||||
|
nibble = (uint8_t) (10 + (v - 'A'));
|
||||||
|
}
|
||||||
|
else if (v == 0) {
|
||||||
|
nibble = 0; // pad with zeros
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*suc = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
digit++;
|
||||||
|
bytebuf <<= 4;
|
||||||
|
bytebuf |= nibble;
|
||||||
|
if ((digit % 2 == 0) && digit > 0) { // whole byte
|
||||||
|
*dest++ = bytebuf;
|
||||||
|
bytebuf = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/02/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GEX_CORE_CFG_UTILS_H
|
||||||
|
#define GEX_CORE_CFG_UTILS_H
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#include "rsc_enum.h"
|
||||||
|
#include "utils/avrlibc.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a pin name (e.g. PA0 or A0) to port name and pin number
|
||||||
|
*
|
||||||
|
* @param str - source string
|
||||||
|
* @param targetName - output: port name (one character)
|
||||||
|
* @param targetNumber - output: pin number 0-15
|
||||||
|
* @return success
|
||||||
|
*/
|
||||||
|
bool cfg_portpin_parse(const char *str, char *targetName, uint8_t *targetNumber);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a string representation of a pin directly to a resource constant
|
||||||
|
*
|
||||||
|
* @param[in] str - source string - e.g. PA0 or A0
|
||||||
|
* @param[out] suc - written to false on failure
|
||||||
|
* @return the parsed resource
|
||||||
|
*/
|
||||||
|
Resource cfg_pinrsc_parse(const char *str, bool *suc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a resource to a pin name - uses a static buffer, result must not be stored!
|
||||||
|
*
|
||||||
|
* @param[in] rsc - resource to print
|
||||||
|
* @return a pointer to a static buffer used for exporting the names
|
||||||
|
*/
|
||||||
|
char *cfg_pinrsc_encode(Resource rsc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a port name (one character) - validates that it's within range
|
||||||
|
*
|
||||||
|
* @param value - source string
|
||||||
|
* @param targetName - output: port name (one character)
|
||||||
|
* @return success
|
||||||
|
*/
|
||||||
|
bool cfg_port_parse(const char *value, char *targetName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a list of pin numbers with ranges and commands/semicolons to a bitmask.
|
||||||
|
* Supported syntax:
|
||||||
|
* - comma separated numbers
|
||||||
|
* - numbers connected by dash or colon form a range (can be in any order)
|
||||||
|
*
|
||||||
|
* @param value - source string
|
||||||
|
* @param suc - set to False if parsing failed
|
||||||
|
* @return the resulting bitmap
|
||||||
|
*/
|
||||||
|
uint32_t cfg_pinmask_parse_32(const char *value, bool *suc);
|
||||||
|
|
||||||
|
/** same as cfg_pinmask_parse_32(), but with a cast to u16 */
|
||||||
|
static inline uint16_t cfg_pinmask_parse(const char *value, bool *suc)
|
||||||
|
{
|
||||||
|
return (uint16_t) cfg_pinmask_parse_32(value, suc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a pin bitmap to the ASCII format understood by str_parse_pinmask()
|
||||||
|
*
|
||||||
|
* @param[in] pins - sparse pin map
|
||||||
|
* @param[out] buffer - output string buffer
|
||||||
|
* @param[in] ascending - use ordering 0..31 rather than 31..0
|
||||||
|
* @return the output buffer
|
||||||
|
*/
|
||||||
|
char *cfg_pinmask_encode(uint32_t pins, char *buffer, bool ascending);
|
||||||
|
|
||||||
|
|
||||||
|
/** Parse Y/N to bool */
|
||||||
|
bool cfg_bool_parse(const char *str, bool *suc);
|
||||||
|
|
||||||
|
/** Convert number to one of 4 options */
|
||||||
|
const char *cfg_enum2_encode(uint32_t n,
|
||||||
|
uint32_t na, const char *a,
|
||||||
|
uint32_t nb, const char *b);
|
||||||
|
|
||||||
|
/** Convert number to one of 4 options */
|
||||||
|
const char *cfg_enum3_encode(uint32_t n,
|
||||||
|
uint32_t na, const char *a,
|
||||||
|
uint32_t nb, const char *b,
|
||||||
|
uint32_t nc, const char *c);
|
||||||
|
|
||||||
|
/** Convert number to one of 4 options */
|
||||||
|
const char *cfg_enum4_encode(uint32_t n,
|
||||||
|
uint32_t na, const char *a,
|
||||||
|
uint32_t nb, const char *b,
|
||||||
|
uint32_t nc, const char *c,
|
||||||
|
uint32_t nd, const char *d);
|
||||||
|
|
||||||
|
/** Convert string to one of two numeric options */
|
||||||
|
uint32_t cfg_enum2_parse(const char *tpl,
|
||||||
|
const char *a, uint32_t na,
|
||||||
|
const char *b, uint32_t nb,
|
||||||
|
bool *suc);
|
||||||
|
|
||||||
|
/** Convert string to one of three numeric options */
|
||||||
|
uint32_t cfg_enum3_parse(const char *tpl,
|
||||||
|
const char *a, uint32_t na,
|
||||||
|
const char *b, uint32_t nb,
|
||||||
|
const char *c, uint32_t nc,
|
||||||
|
bool *suc);
|
||||||
|
|
||||||
|
/** Convert string to one of four numeric options */
|
||||||
|
uint32_t cfg_enum4_parse(const char *tpl,
|
||||||
|
const char *a, uint32_t na,
|
||||||
|
const char *b, uint32_t nb,
|
||||||
|
const char *c, uint32_t nc,
|
||||||
|
const char *d, uint32_t nd,
|
||||||
|
bool *suc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a hexa string to a byte array.
|
||||||
|
* Skips 0x prefix, '.', '-', ':', ' '.
|
||||||
|
*
|
||||||
|
* @param[out] dest - storage array
|
||||||
|
* @param[in] count - expected number of bytes
|
||||||
|
* @param[in] value - parsed string
|
||||||
|
* @param[out] suc - success flag
|
||||||
|
*/
|
||||||
|
void cfg_hex_parse(uint8_t *dest, uint32_t count,
|
||||||
|
const char *value, bool *suc);
|
||||||
|
|
||||||
|
/** Convert bool to a Y or N constant string */
|
||||||
|
#define str_yn(cond) ((cond) ? ("Y") : ("N"))
|
||||||
|
|
||||||
|
|
||||||
|
static inline uint8_t cfg_u8_parse(const char *value, bool *suc)
|
||||||
|
{
|
||||||
|
return (uint8_t) avr_atoi(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int8_t cfg_i8_parse(const char *value, bool *suc)
|
||||||
|
{
|
||||||
|
return (int8_t) avr_atoi(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint16_t cfg_u16_parse(const char *value, bool *suc)
|
||||||
|
{
|
||||||
|
return (uint16_t) avr_atoi(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int16_t cfg_i16_parse(const char *value, bool *suc)
|
||||||
|
{
|
||||||
|
return (int16_t) avr_atoi(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t cfg_u32_parse(const char *value, bool *suc)
|
||||||
|
{
|
||||||
|
return (uint32_t) avr_atoi(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int32_t cfg_i32_parse(const char *value, bool *suc)
|
||||||
|
{
|
||||||
|
return (int32_t) avr_atoi(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //GEX_CORE_CFG_UTILS_H
|
||||||
+36
-43
@@ -5,65 +5,31 @@
|
|||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "framework/resources.h"
|
#include "framework/resources.h"
|
||||||
#include "debug_uart.h"
|
#include "debug_uart.h"
|
||||||
#include "plat_compat.h"
|
|
||||||
#include "hw_utils.h"
|
#include "hw_utils.h"
|
||||||
|
#include "framework/system_settings.h"
|
||||||
|
|
||||||
#if USE_DEBUG_UART
|
#if USE_DEBUG_UART
|
||||||
|
|
||||||
#define DEBUG_USART_BAUD 115200
|
static bool debug_uart_inited = false;
|
||||||
|
static bool debug_uart_preinited = false;
|
||||||
#if GEX_PLAT_F072_DISCOVERY
|
|
||||||
|
|
||||||
#define DEBUG_USART USART1
|
|
||||||
#define DEBUG_USART_RSC R_USART1
|
|
||||||
#define DEBUG_USART_PORT 'A'
|
|
||||||
#define DEBUG_USART_PIN 9
|
|
||||||
#define DEBUG_USART_AF 1
|
|
||||||
#define DEBUG_USART_PCLK PLAT_APB1_HZ
|
|
||||||
|
|
||||||
#elif GEX_PLAT_F103_BLUEPILL
|
|
||||||
|
|
||||||
#define DEBUG_USART USART2
|
|
||||||
#define DEBUG_USART_RSC R_USART2
|
|
||||||
#define DEBUG_USART_PORT 'A'
|
|
||||||
#define DEBUG_USART_PIN 2
|
|
||||||
#define DEBUG_USART_PCLK PLAT_APB1_HZ
|
|
||||||
|
|
||||||
#elif GEX_PLAT_F303_DISCOVERY
|
|
||||||
|
|
||||||
#define DEBUG_USART USART3
|
|
||||||
#define DEBUG_USART_RSC R_USART3
|
|
||||||
#define DEBUG_USART_PORT 'D'
|
|
||||||
#define DEBUG_USART_PIN 8
|
|
||||||
#define DEBUG_USART_AF 7
|
|
||||||
#define DEBUG_USART_PCLK PLAT_APB1_HZ
|
|
||||||
|
|
||||||
#elif GEX_PLAT_F407_DISCOVERY
|
|
||||||
|
|
||||||
#define DEBUG_USART USART2
|
|
||||||
#define DEBUG_USART_RSC R_USART2
|
|
||||||
#define DEBUG_USART_PORT 'A'
|
|
||||||
#define DEBUG_USART_PIN 2
|
|
||||||
#define DEBUG_USART_AF 7
|
|
||||||
#define DEBUG_USART_PCLK PLAT_APB1_HZ
|
|
||||||
|
|
||||||
#else
|
|
||||||
#error "BAD PLATFORM!"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Init the submodule. */
|
/** Init the submodule. */
|
||||||
void DebugUart_Init(void)
|
void DebugUart_Init(void)
|
||||||
{
|
{
|
||||||
|
if (debug_uart_inited) return;
|
||||||
|
if (!debug_uart_preinited) DebugUart_PreInit();
|
||||||
// Debug UART
|
// Debug UART
|
||||||
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, DEBUG_USART_RSC));
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, DEBUG_USART_RSC));
|
||||||
assert_param(E_SUCCESS == rsc_claim_pin(&UNIT_SYSTEM, DEBUG_USART_PORT, DEBUG_USART_PIN));
|
assert_param(E_SUCCESS == rsc_claim_pin(&UNIT_SYSTEM, DEBUG_USART_PORT, DEBUG_USART_PIN));
|
||||||
|
|
||||||
|
debug_uart_inited = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Init the hardware peripheral - this is called early in the boot process */
|
/** Init the hardware peripheral - this is called early in the boot process */
|
||||||
void DebugUart_PreInit(void)
|
void DebugUart_PreInit(void)
|
||||||
{
|
{
|
||||||
|
debug_uart_preinited = true;
|
||||||
|
|
||||||
// configure AF only if platform uses AF numbers
|
// configure AF only if platform uses AF numbers
|
||||||
#if !PLAT_NO_AFNUM
|
#if !PLAT_NO_AFNUM
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
@@ -89,8 +55,35 @@ void DebugUart_PreInit(void)
|
|||||||
LL_USART_Enable(DEBUG_USART);
|
LL_USART_Enable(DEBUG_USART);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DebugUart_Teardown(void)
|
||||||
|
{
|
||||||
|
if (!debug_uart_inited) return;
|
||||||
|
|
||||||
|
dbg("Disabling debug UART!");
|
||||||
|
|
||||||
|
// TODO wait for Tx (after debug print DMA is implemented)
|
||||||
|
|
||||||
|
LL_USART_Disable(DEBUG_USART);
|
||||||
|
rsc_free(&UNIT_SYSTEM, DEBUG_USART_RSC);
|
||||||
|
hw_periph_clock_disable(DEBUG_USART);
|
||||||
|
|
||||||
|
bool suc = true;
|
||||||
|
Resource r = rsc_portpin2rsc(DEBUG_USART_PORT, DEBUG_USART_PIN, &suc);
|
||||||
|
rsc_free(&UNIT_SYSTEM, r);
|
||||||
|
hw_deinit_pin_rsc(r);
|
||||||
|
|
||||||
|
debug_uart_preinited = false;
|
||||||
|
debug_uart_inited = false;
|
||||||
|
|
||||||
|
assert_param(suc);
|
||||||
|
}
|
||||||
|
|
||||||
void debug_write(const char *buf, uint16_t len)
|
void debug_write(const char *buf, uint16_t len)
|
||||||
{
|
{
|
||||||
|
if (!SystemSettings.enable_debug_uart) return;
|
||||||
|
|
||||||
|
// TODO wait for DMA complete
|
||||||
|
// TODO use DMA
|
||||||
for (uint16_t i = 0; i < len; i++) {
|
for (uint16_t i = 0; i < len; i++) {
|
||||||
while (!LL_USART_IsActiveFlag_TC(DEBUG_USART));
|
while (!LL_USART_IsActiveFlag_TC(DEBUG_USART));
|
||||||
LL_USART_TransmitData8(DEBUG_USART, (uint8_t) *buf++);
|
LL_USART_TransmitData8(DEBUG_USART, (uint8_t) *buf++);
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
#ifndef GEX_DEBUG_UART_H
|
#ifndef GEX_DEBUG_UART_H
|
||||||
#define GEX_DEBUG_UART_H
|
#define GEX_DEBUG_UART_H
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pre-init the debug uart
|
* Pre-init the debug uart
|
||||||
*
|
*
|
||||||
@@ -17,7 +19,13 @@
|
|||||||
void DebugUart_PreInit(void);
|
void DebugUart_PreInit(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finalize the init (claim resources)
|
* Release the peripheral and deinit pin
|
||||||
|
*/
|
||||||
|
void DebugUart_Teardown(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalize the init (claim resources).
|
||||||
|
* If not pre-inited (i.e. Teardown was called before), also pre-init.
|
||||||
*/
|
*/
|
||||||
void DebugUart_Init(void);
|
void DebugUart_Init(void);
|
||||||
|
|
||||||
|
|||||||
+59
-224
@@ -3,10 +3,8 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "utils/avrlibc.h"
|
|
||||||
#include "hw_utils.h"
|
#include "hw_utils.h"
|
||||||
|
|
||||||
|
|
||||||
/** Convert pin number to LL bitfield */
|
/** Convert pin number to LL bitfield */
|
||||||
uint32_t hw_pin2ll(uint8_t pin_number, bool *suc)
|
uint32_t hw_pin2ll(uint8_t pin_number, bool *suc)
|
||||||
{
|
{
|
||||||
@@ -36,210 +34,19 @@ GPIO_TypeDef *hw_port2periph(char port_name, bool *suc)
|
|||||||
return GPIO_PERIPHS[num];
|
return GPIO_PERIPHS[num];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Convert a pin to resource handle */
|
/** Convert a pin resource to it's LL lib values */
|
||||||
Resource hw_pin2resource(char port_name, uint8_t pin_number, bool *suc)
|
bool hw_pinrsc2ll(Resource rsc, GPIO_TypeDef **port, uint32_t *llpin)
|
||||||
{
|
{
|
||||||
assert_param(suc != NULL);
|
if (rsc > R_PF15) return false;
|
||||||
|
uint32_t index = rsc - R_PA0;
|
||||||
if(port_name < 'A' || port_name >= ('A'+PORTS_COUNT)) {
|
uint32_t pname = (index/16);
|
||||||
dbg("Bad port: %c", port_name); // TODO proper report
|
uint8_t pnum = (uint8_t) (index % 16);
|
||||||
*suc = false;
|
if (pname >= PORTS_COUNT) return false;
|
||||||
return R_NONE;
|
*port = GPIO_PERIPHS[pname];
|
||||||
}
|
*llpin = LL_GPIO_PINS[pnum];
|
||||||
|
|
||||||
if(pin_number > 15) {
|
|
||||||
dbg("Bad pin: %d", pin_number); // TODO proper report
|
|
||||||
*suc = false;
|
|
||||||
return R_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t num = (uint8_t) (port_name - 'A');
|
|
||||||
|
|
||||||
return R_PA0 + num*16 + pin_number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Parse single pin */
|
|
||||||
bool parse_pin(const char *value, char *targetName, uint8_t *targetNumber)
|
|
||||||
{
|
|
||||||
// discard leading 'P'
|
|
||||||
if (value[0] == 'P') {
|
|
||||||
value++;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t len = strlen(value);
|
|
||||||
if (len<2||len>3) return false;
|
|
||||||
|
|
||||||
*targetName = (uint8_t) value[0];
|
|
||||||
if (!(*targetName >= 'A' && *targetName <= 'H')) return false;
|
|
||||||
|
|
||||||
// lets just hope it's OK
|
|
||||||
*targetNumber = (uint8_t) avr_atoi(value + 1);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Parse port name */
|
|
||||||
bool parse_port_name(const char *value, char *targetName)
|
|
||||||
{
|
|
||||||
*targetName = (uint8_t) value[0];
|
|
||||||
if (!(*targetName >= 'A' && *targetName < 'A' + PORTS_COUNT)) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Parse a list of pin numbers with ranges and commans/semicolons to a bitmask */
|
|
||||||
uint32_t parse_pinmask(const char *value, bool *suc)
|
|
||||||
{
|
|
||||||
uint32_t bits = 0;
|
|
||||||
uint32_t acu = 0;
|
|
||||||
bool inrange = false;
|
|
||||||
uint32_t rangestart = 0;
|
|
||||||
|
|
||||||
// shortcut if none are set
|
|
||||||
if (value[0] == 0) return 0;
|
|
||||||
|
|
||||||
char c;
|
|
||||||
do {
|
|
||||||
c = *value++;
|
|
||||||
if (c == ' ' || c == '\t') {
|
|
||||||
// skip
|
|
||||||
}
|
|
||||||
else if (c >= '0' && c <= '9') {
|
|
||||||
acu = acu*10 + (c-'0');
|
|
||||||
}
|
|
||||||
else if (c == ',' || c == ';' || c == 0) {
|
|
||||||
// end of number or range
|
|
||||||
if (!inrange) rangestart = acu;
|
|
||||||
|
|
||||||
// swap them if they're in the wrong order
|
|
||||||
if (acu < rangestart) {
|
|
||||||
uint32_t swp = acu;
|
|
||||||
acu = rangestart;
|
|
||||||
rangestart = swp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rangestart > 31) rangestart = 31;
|
|
||||||
if (acu > 31) acu = 31;
|
|
||||||
|
|
||||||
for(uint32_t i=rangestart; i <= acu; i++) {
|
|
||||||
bits |= 1<<i;
|
|
||||||
}
|
|
||||||
|
|
||||||
inrange = false;
|
|
||||||
rangestart = 0;
|
|
||||||
acu = 0;
|
|
||||||
}
|
|
||||||
else if (c == '-' || c == ':') {
|
|
||||||
rangestart = acu;
|
|
||||||
inrange = true;
|
|
||||||
acu=0;
|
|
||||||
} else {
|
|
||||||
*suc = false;
|
|
||||||
}
|
|
||||||
} while (c != 0);
|
|
||||||
|
|
||||||
return bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Convert a pin bitmask to the ASCII format understood by str_parse_pinmask() */
|
|
||||||
char * pinmask2str(uint32_t pins, char *buffer)
|
|
||||||
{
|
|
||||||
char *b = buffer;
|
|
||||||
uint32_t start = 0;
|
|
||||||
bool on = false;
|
|
||||||
bool first = true;
|
|
||||||
|
|
||||||
// shortcut if none are set
|
|
||||||
if (pins == 0) {
|
|
||||||
buffer[0] = 0;
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int32_t i = 31; i >= -1; i--) {
|
|
||||||
bool bit;
|
|
||||||
|
|
||||||
if (i == -1) {
|
|
||||||
bit = false;
|
|
||||||
} else {
|
|
||||||
bit = 0 != (pins & 0x80000000);
|
|
||||||
pins <<= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bit) {
|
|
||||||
if (!on) {
|
|
||||||
start = (uint32_t) i;
|
|
||||||
on = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (on) {
|
|
||||||
if (!first) {
|
|
||||||
b += SPRINTF(b, ", ");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start == (uint32_t)(i+1)) {
|
|
||||||
b += SPRINTF(b, "%"PRIu32, start);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
b += SPRINTF(b, "%"PRIu32"-%"PRIu32, start, i + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
first = false;
|
|
||||||
on = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
char * pinmask2str_up(uint32_t pins, char *buffer)
|
|
||||||
{
|
|
||||||
char *b = buffer;
|
|
||||||
uint32_t start = 0;
|
|
||||||
bool on = false;
|
|
||||||
bool first = true;
|
|
||||||
|
|
||||||
// shortcut if none are set
|
|
||||||
if (pins == 0) {
|
|
||||||
buffer[0] = 0;
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int32_t i = 0; i <= 32; i++) {
|
|
||||||
bool bit;
|
|
||||||
|
|
||||||
if (i == 32) {
|
|
||||||
bit = false;
|
|
||||||
} else {
|
|
||||||
bit = 0 != (pins & 1);
|
|
||||||
pins >>= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bit) {
|
|
||||||
if (!on) {
|
|
||||||
start = (uint32_t) i;
|
|
||||||
on = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (on) {
|
|
||||||
if (!first) {
|
|
||||||
b += SPRINTF(b, ", ");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start == (uint32_t)(i-1)) {
|
|
||||||
b += SPRINTF(b, "%"PRIu32, start);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
b += SPRINTF(b, "%"PRIu32"-%"PRIu32, start, i - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
first = false;
|
|
||||||
on = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma GCC push_options
|
#pragma GCC push_options
|
||||||
#pragma GCC optimize ("O2")
|
#pragma GCC optimize ("O2")
|
||||||
/** spread a packed pinfield using a mask */
|
/** spread a packed pinfield using a mask */
|
||||||
@@ -285,33 +92,26 @@ uint32_t pinmask_pack_32(uint32_t spread, uint32_t mask)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Convert spread port pin number to a packed index using a mask */
|
|
||||||
uint8_t pinmask_translate(uint32_t mask, uint8_t index)
|
|
||||||
{
|
|
||||||
int cnt = 0;
|
|
||||||
for (int i = 0; i<32; i++) {
|
|
||||||
if (mask & (1<<i)) {
|
|
||||||
if (i == index) return (uint8_t) cnt;
|
|
||||||
cnt++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#pragma GCC pop_options
|
#pragma GCC pop_options
|
||||||
|
|
||||||
/** Configure unit pins as analog (part of unit teardown) */
|
/** Configure unit pins as analog (part of unit teardown) */
|
||||||
void hw_deinit_unit_pins(Unit *unit)
|
void hw_deinit_unit_pins(Unit *unit)
|
||||||
{
|
{
|
||||||
for (uint32_t rsc = R_PA0; rsc <= R_PF15; rsc++) {
|
for (uint32_t rsc = R_PA0; rsc <= R_PF15; rsc++) {
|
||||||
if (RSC_IS_HELD(unit->resources, rsc)) {
|
if (RSC_IS_HELD(unit->resources, (Resource)rsc)) {
|
||||||
rsc_dbg("Freeing pin %s", rsc_get_name((Resource)rsc));
|
hw_deinit_pin_rsc((Resource)rsc);
|
||||||
GPIO_TypeDef *port = GPIO_PERIPHS[(rsc-R_PA0) / 16];
|
|
||||||
uint32_t ll_pin = LL_GPIO_PINS[(rsc-R_PA0)%16];
|
|
||||||
LL_GPIO_SetPinMode(port, ll_pin, LL_GPIO_MODE_ANALOG);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hw_deinit_pin_rsc(Resource rsc)
|
||||||
|
{
|
||||||
|
rsc_dbg("Freeing pin %s", rsc_get_name((Resource)rsc));
|
||||||
|
GPIO_TypeDef *port = GPIO_PERIPHS[(rsc-R_PA0) / 16];
|
||||||
|
uint32_t ll_pin = LL_GPIO_PINS[(rsc-R_PA0)%16];
|
||||||
|
LL_GPIO_SetPinMode(port, ll_pin, LL_GPIO_MODE_ANALOG);
|
||||||
|
}
|
||||||
|
|
||||||
/** Configure a pin to alternate function */
|
/** Configure a pin to alternate function */
|
||||||
error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af)
|
error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af)
|
||||||
{
|
{
|
||||||
@@ -335,6 +135,30 @@ error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af)
|
|||||||
return E_SUCCESS;
|
return E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Configure a pin to alternate function */
|
||||||
|
error_t hw_configure_gpiorsc_af(Resource rsc, uint32_t ll_af)
|
||||||
|
{
|
||||||
|
#if PLAT_NO_AFNUM
|
||||||
|
trap("Illegal call to hw_configure_gpio_af() on this platform");
|
||||||
|
#else
|
||||||
|
|
||||||
|
bool suc = true;
|
||||||
|
GPIO_TypeDef *port;
|
||||||
|
uint32_t ll_pin;
|
||||||
|
suc = hw_pinrsc2ll(rsc, &port, &ll_pin);
|
||||||
|
if (!suc) return E_BAD_CONFIG;
|
||||||
|
|
||||||
|
if (ll_pin & 0xFF)
|
||||||
|
LL_GPIO_SetAFPin_0_7(port, ll_pin, ll_af);
|
||||||
|
else
|
||||||
|
LL_GPIO_SetAFPin_8_15(port, ll_pin, ll_af);
|
||||||
|
|
||||||
|
LL_GPIO_SetPinMode(port, ll_pin, LL_GPIO_MODE_ALTERNATE);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
return E_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/** Configure pins using sparse map */
|
/** Configure pins using sparse map */
|
||||||
error_t hw_configure_sparse_pins(char port_name, uint16_t mask, GPIO_TypeDef **port_dest,
|
error_t hw_configure_sparse_pins(char port_name, uint16_t mask, GPIO_TypeDef **port_dest,
|
||||||
uint32_t ll_mode, uint32_t ll_otype)
|
uint32_t ll_mode, uint32_t ll_otype)
|
||||||
@@ -360,8 +184,8 @@ error_t hw_configure_sparse_pins(char port_name, uint16_t mask, GPIO_TypeDef **p
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Solve a timer/counter's count and prescaller value */
|
/** Solve a timer/counter's count and prescaller value */
|
||||||
bool solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
|
bool hw_solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
|
||||||
uint16_t *presc, uint32_t *count, float *real_freq)
|
uint16_t *presc, uint32_t *count, float *real_freq)
|
||||||
{
|
{
|
||||||
if (required_freq == 0) return false;
|
if (required_freq == 0) return false;
|
||||||
|
|
||||||
@@ -394,7 +218,6 @@ bool solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void hw_periph_clock_enable(void *periph)
|
void hw_periph_clock_enable(void *periph)
|
||||||
{
|
{
|
||||||
// GPIOs are enabled by default on start-up
|
// GPIOs are enabled by default on start-up
|
||||||
@@ -445,7 +268,7 @@ void hw_periph_clock_enable(void *periph)
|
|||||||
else if (periph == TIM5) __HAL_RCC_TIM5_CLK_ENABLE();
|
else if (periph == TIM5) __HAL_RCC_TIM5_CLK_ENABLE();
|
||||||
#endif
|
#endif
|
||||||
#ifdef TIM6
|
#ifdef TIM6
|
||||||
else if (periph == TIM6) __HAL_RCC_TIM7_CLK_ENABLE();
|
else if (periph == TIM6) __HAL_RCC_TIM6_CLK_ENABLE();
|
||||||
#endif
|
#endif
|
||||||
#ifdef TIM7
|
#ifdef TIM7
|
||||||
else if (periph == TIM7) __HAL_RCC_TIM7_CLK_ENABLE();
|
else if (periph == TIM7) __HAL_RCC_TIM7_CLK_ENABLE();
|
||||||
@@ -493,6 +316,12 @@ void hw_periph_clock_enable(void *periph)
|
|||||||
#ifdef DAC2
|
#ifdef DAC2
|
||||||
else if (periph == DAC2) __HAL_RCC_DAC2_CLK_ENABLE();
|
else if (periph == DAC2) __HAL_RCC_DAC2_CLK_ENABLE();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// --- TSC ---
|
||||||
|
#ifdef TSC
|
||||||
|
else if (periph == TSC) __HAL_RCC_TSC_CLK_ENABLE();
|
||||||
|
#endif
|
||||||
|
|
||||||
else {
|
else {
|
||||||
dbg("Periph 0x%p missing in hw clock enable func", periph);
|
dbg("Periph 0x%p missing in hw clock enable func", periph);
|
||||||
trap("BUG");
|
trap("BUG");
|
||||||
@@ -550,7 +379,7 @@ void hw_periph_clock_disable(void *periph)
|
|||||||
else if (periph == TIM5) __HAL_RCC_TIM5_CLK_DISABLE();
|
else if (periph == TIM5) __HAL_RCC_TIM5_CLK_DISABLE();
|
||||||
#endif
|
#endif
|
||||||
#ifdef TIM6
|
#ifdef TIM6
|
||||||
else if (periph == TIM6) __HAL_RCC_TIM7_CLK_DISABLE();
|
else if (periph == TIM6) __HAL_RCC_TIM6_CLK_DISABLE();
|
||||||
#endif
|
#endif
|
||||||
#ifdef TIM7
|
#ifdef TIM7
|
||||||
else if (periph == TIM7) __HAL_RCC_TIM7_CLK_DISABLE();
|
else if (periph == TIM7) __HAL_RCC_TIM7_CLK_DISABLE();
|
||||||
@@ -598,6 +427,12 @@ void hw_periph_clock_disable(void *periph)
|
|||||||
#ifdef DAC2
|
#ifdef DAC2
|
||||||
else if (periph == DAC2) __HAL_RCC_DAC2_CLK_DISABLE();
|
else if (periph == DAC2) __HAL_RCC_DAC2_CLK_DISABLE();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// --- TSC ---
|
||||||
|
#ifdef TSC
|
||||||
|
else if (periph == TSC) __HAL_RCC_TSC_CLK_DISABLE();
|
||||||
|
#endif
|
||||||
|
|
||||||
else {
|
else {
|
||||||
dbg("Periph 0x%p missing in hw clock disable func", periph);
|
dbg("Periph 0x%p missing in hw clock disable func", periph);
|
||||||
trap("BUG");
|
trap("BUG");
|
||||||
|
|||||||
+11
-64
@@ -21,16 +21,6 @@
|
|||||||
*/
|
*/
|
||||||
uint32_t hw_pin2ll(uint8_t pin_number, bool *suc);
|
uint32_t hw_pin2ll(uint8_t pin_number, bool *suc);
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert pin name and number to a resource enum
|
|
||||||
*
|
|
||||||
* @param port_name - char 'A'..'Z'
|
|
||||||
* @param pin_number - number 0..15
|
|
||||||
* @param suc - set to false on failure, left unchanged on success
|
|
||||||
* @return the resource, or R_NONE
|
|
||||||
*/
|
|
||||||
Resource hw_pin2resource(char port_name, uint8_t pin_number, bool *suc);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert port name to peripheral instance
|
* Convert port name to peripheral instance
|
||||||
*
|
*
|
||||||
@@ -41,55 +31,16 @@ Resource hw_pin2resource(char port_name, uint8_t pin_number, bool *suc);
|
|||||||
GPIO_TypeDef *hw_port2periph(char port_name, bool *suc);
|
GPIO_TypeDef *hw_port2periph(char port_name, bool *suc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a pin name (e.g. PA0 or A0) to port name and pin number
|
* Convert a pin resource to it's LL lib values
|
||||||
*
|
*
|
||||||
* @param str - source string
|
* @param[in] rsc - resource to process
|
||||||
* @param targetName - output: port name (one character)
|
* @param[out] port - output port
|
||||||
* @param targetNumber - output: pin number 0-15
|
* @param[out] llpin - output LL pin mask
|
||||||
* @return success
|
* @return success
|
||||||
*/
|
*/
|
||||||
bool parse_pin(const char *str, char *targetName, uint8_t *targetNumber);
|
bool hw_pinrsc2ll(Resource rsc, GPIO_TypeDef **port, uint32_t *llpin) __attribute__((warn_unused_result));
|
||||||
|
|
||||||
/**
|
void hw_deinit_pin_rsc(Resource rsc);
|
||||||
* Parse a port name (one character) - validates that it's within range
|
|
||||||
*
|
|
||||||
* @param value - source string
|
|
||||||
* @param targetName - output: port name (one character)
|
|
||||||
* @return success
|
|
||||||
*/
|
|
||||||
bool parse_port_name(const char *value, char *targetName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse a list of pin numbers with ranges and commands/semicolons to a bitmask.
|
|
||||||
* Supported syntax:
|
|
||||||
* - comma separated numbers
|
|
||||||
* - numbers connected by dash or colon form a range (can be in any order)
|
|
||||||
*
|
|
||||||
* @param value - source string
|
|
||||||
* @param suc - set to False if parsing failed
|
|
||||||
* @return the resulting bitmap
|
|
||||||
*/
|
|
||||||
uint32_t parse_pinmask(const char *value, bool *suc);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a pin bitmap to the ASCII format understood by str_parse_pinmask()
|
|
||||||
* This is the downto variant (15..0)
|
|
||||||
*
|
|
||||||
* @param pins - sparse pin map
|
|
||||||
* @param buffer - output string buffer
|
|
||||||
* @return the output buffer
|
|
||||||
*/
|
|
||||||
char * pinmask2str(uint32_t pins, char *buffer);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a pin bitmap to the ASCII format understood by str_parse_pinmask()
|
|
||||||
* This is the ascending variant (0..15)
|
|
||||||
*
|
|
||||||
* @param pins - sparse pin map
|
|
||||||
* @param buffer - output string buffer
|
|
||||||
* @return the output buffer
|
|
||||||
*/
|
|
||||||
char * pinmask2str_up(uint32_t pins, char *buffer);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spread packed port pins using a mask
|
* Spread packed port pins using a mask
|
||||||
@@ -121,13 +72,6 @@ static inline uint16_t pinmask_pack(uint32_t spread, uint32_t mask)
|
|||||||
return (uint16_t) pinmask_pack_32(spread, mask);
|
return (uint16_t) pinmask_pack_32(spread, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert spread port pin number to a packed index using a mask
|
|
||||||
*
|
|
||||||
* eg. with a mask 0b1010 and index 3, the result is 1 (bit 1 of the packed - 0bX0)
|
|
||||||
*/
|
|
||||||
uint8_t pinmask_translate(uint32_t mask, uint8_t index);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set all GPIO resources held by unit to analog.
|
* Set all GPIO resources held by unit to analog.
|
||||||
* This is a part of unit teardown.
|
* This is a part of unit teardown.
|
||||||
@@ -146,6 +90,9 @@ void hw_deinit_unit_pins(Unit *unit);
|
|||||||
*/
|
*/
|
||||||
error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af) __attribute__((warn_unused_result));
|
error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af) __attribute__((warn_unused_result));
|
||||||
|
|
||||||
|
/** Configure a pin to alternate function via rsc */
|
||||||
|
error_t hw_configure_gpiorsc_af(Resource rsc, uint32_t ll_af) __attribute__((warn_unused_result));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure multiple pins using the bitmap pattern
|
* Configure multiple pins using the bitmap pattern
|
||||||
*
|
*
|
||||||
@@ -192,8 +139,8 @@ void hw_periph_clock_disable(void *periph);
|
|||||||
* @param[out] real_freq - field for storing the computed real frequency
|
* @param[out] real_freq - field for storing the computed real frequency
|
||||||
* @return true on success
|
* @return true on success
|
||||||
*/
|
*/
|
||||||
bool solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
|
bool hw_solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
|
||||||
uint16_t *presc, uint32_t *count, float *real_freq);
|
uint16_t *presc, uint32_t *count, float *real_freq) __attribute__((warn_unused_result));
|
||||||
|
|
||||||
#define hw_wait_while(call, timeout) \
|
#define hw_wait_while(call, timeout) \
|
||||||
do { \
|
do { \
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ static struct callbacks_ {
|
|||||||
struct cbslot tim16;
|
struct cbslot tim16;
|
||||||
|
|
||||||
struct cbslot adc1;
|
struct cbslot adc1;
|
||||||
|
struct cbslot tsc;
|
||||||
|
|
||||||
// XXX add more callbacks here when needed
|
// XXX add more callbacks here when needed
|
||||||
} callbacks;
|
} callbacks;
|
||||||
@@ -92,7 +93,8 @@ void irqd_init(void)
|
|||||||
HAL_NVIC_SetPriority(EXTI2_3_IRQn, 2, 0);
|
HAL_NVIC_SetPriority(EXTI2_3_IRQn, 2, 0);
|
||||||
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 2, 0);
|
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 2, 0);
|
||||||
|
|
||||||
// NVIC_EnableIRQ(TSC_IRQn); /*!< Touch Sensing Controller Interrupts */
|
NVIC_EnableIRQ(TSC_IRQn); /*!< Touch Sensing Controller Interrupts */
|
||||||
|
HAL_NVIC_SetPriority(TSC_IRQn, 2, 0);
|
||||||
|
|
||||||
NVIC_EnableIRQ(DMA1_Channel1_IRQn); /*!< DMA1 Channel 1 Interrupt */
|
NVIC_EnableIRQ(DMA1_Channel1_IRQn); /*!< DMA1 Channel 1 Interrupt */
|
||||||
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); /*!< DMA1 Channel 2 and Channel 3 Interrupt */
|
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); /*!< DMA1 Channel 2 and Channel 3 Interrupt */
|
||||||
@@ -111,7 +113,7 @@ void irqd_init(void)
|
|||||||
// NVIC_EnableIRQ(TIM3_IRQn); /*!< TIM3 global Interrupt */
|
// NVIC_EnableIRQ(TIM3_IRQn); /*!< TIM3 global Interrupt */
|
||||||
|
|
||||||
NVIC_EnableIRQ(TIM6_DAC_IRQn); /*!< TIM6 global and DAC channel underrun error Interrupt */
|
NVIC_EnableIRQ(TIM6_DAC_IRQn); /*!< TIM6 global and DAC channel underrun error Interrupt */
|
||||||
HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0); // Used for DAC timing
|
HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 2, 0); // Used for DAC timing
|
||||||
|
|
||||||
NVIC_EnableIRQ(TIM7_IRQn); /*!< TIM7 global Interrupt */
|
NVIC_EnableIRQ(TIM7_IRQn); /*!< TIM7 global Interrupt */
|
||||||
HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0);// this will be for dac (?)
|
HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0);// this will be for dac (?)
|
||||||
@@ -178,6 +180,8 @@ static struct cbslot *get_slot_for_periph(void *periph)
|
|||||||
else if (periph == TIM16) slot = &callbacks.tim16;
|
else if (periph == TIM16) slot = &callbacks.tim16;
|
||||||
// 17 - used by timebase
|
// 17 - used by timebase
|
||||||
|
|
||||||
|
else if (periph == TSC) slot = &callbacks.tsc;
|
||||||
|
|
||||||
else if (periph == ADC1) slot = &callbacks.adc1;
|
else if (periph == ADC1) slot = &callbacks.adc1;
|
||||||
|
|
||||||
else if (periph >= EXTIS[0] && periph <= EXTIS[15]) {
|
else if (periph >= EXTIS[0] && periph <= EXTIS[15]) {
|
||||||
@@ -242,7 +246,12 @@ void* irqd_detach(void *periph, IrqCallback callback)
|
|||||||
|
|
||||||
return oldArg;
|
return oldArg;
|
||||||
} else {
|
} else {
|
||||||
trap("Detach IRQ %p() from %p but %p() bound instead", callback, periph, slot->callback);
|
// catch bugs, but ignore an attempt to unbind when not bound
|
||||||
|
if (slot->callback != NULL) {
|
||||||
|
trap("Detach IRQ %p() from %p but %p() bound instead", callback, periph, slot->callback);
|
||||||
|
} else {
|
||||||
|
return NULL; // the arg - none
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,6 +361,11 @@ void ADC1_COMP_IRQHandler(void)
|
|||||||
CALL_IRQ_HANDLER(callbacks.adc1);
|
CALL_IRQ_HANDLER(callbacks.adc1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TSC_IRQHandler(void)
|
||||||
|
{
|
||||||
|
CALL_IRQ_HANDLER(callbacks.tsc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// other ISRs...
|
// other ISRs...
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
// Provides a trampoline system for redirecting IRQ calls to assigned callbacks.
|
// Provides a trampoline system for redirecting IRQ calls to assigned callbacks.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef GEX_F072_IRQ_DISPATCHER_H
|
#ifndef GEX_CORE_IRQ_DISPATCHER_H
|
||||||
#define GEX_F072_IRQ_DISPATCHER_H
|
#define GEX_CORE_IRQ_DISPATCHER_H
|
||||||
|
|
||||||
// Dummy peripherals for use with the
|
// Dummy peripherals for use with the
|
||||||
extern void * const EXTIS[16];
|
extern void * const EXTIS[16];
|
||||||
@@ -42,4 +42,4 @@ void irqd_attach(void *periph, IrqCallback callback, void *data);
|
|||||||
*/
|
*/
|
||||||
void* irqd_detach(void *periph, IrqCallback callback);
|
void* irqd_detach(void *periph, IrqCallback callback);
|
||||||
|
|
||||||
#endif //GEX_F072_IRQ_DISPATCHER_H
|
#endif //GEX_CORE_IRQ_DISPATCHER_H
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
// Created by MightyPork on 2018/02/04.
|
// Created by MightyPork on 2018/02/04.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef GEX_F072_LL_EXTENSION_H
|
#ifndef GEX_CORE_LL_EXTENSION_H
|
||||||
#define GEX_F072_LL_EXTENSION_H
|
#define GEX_CORE_LL_EXTENSION_H
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
@@ -57,4 +57,4 @@ static inline void LL_DMA_ClearFlags(DMA_TypeDef *DMAx, uint8_t channel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif //GEX_F072_LL_EXTENSION_H
|
#endif //GEX_CORE_LL_EXTENSION_H
|
||||||
|
|||||||
@@ -26,16 +26,11 @@ void LockJumper_Init(void)
|
|||||||
{
|
{
|
||||||
bool suc = true;
|
bool suc = true;
|
||||||
|
|
||||||
// Resolve and claim resource
|
Resource pinrsc = rsc_portpin2rsc(LOCK_JUMPER_PORT, LOCK_JUMPER_PIN, &suc);
|
||||||
Resource rsc = hw_pin2resource(LOCK_JUMPER_PORT, LOCK_JUMPER_PIN, &suc);
|
|
||||||
assert_param(suc);
|
assert_param(suc);
|
||||||
|
|
||||||
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, rsc));
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, pinrsc));
|
||||||
|
assert_param(hw_pinrsc2ll(pinrsc, &lock_periph, &lock_llpin));
|
||||||
// Resolve pin
|
|
||||||
lock_periph = hw_port2periph(LOCK_JUMPER_PORT, &suc);
|
|
||||||
lock_llpin = hw_pin2ll(LOCK_JUMPER_PIN, &suc);
|
|
||||||
assert_param(suc);
|
|
||||||
|
|
||||||
// Configure for input
|
// Configure for input
|
||||||
LL_GPIO_SetPinMode(lock_periph, lock_llpin, LL_GPIO_MODE_INPUT);
|
LL_GPIO_SetPinMode(lock_periph, lock_llpin, LL_GPIO_MODE_INPUT);
|
||||||
@@ -47,7 +42,11 @@ void LockJumper_Init(void)
|
|||||||
LL_GPIO_SetPinPull(lock_periph, lock_llpin, LL_GPIO_PULL_UP);
|
LL_GPIO_SetPinPull(lock_periph, lock_llpin, LL_GPIO_PULL_UP);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SystemSettings.editable = (bool) LL_GPIO_IsInputPinSet(lock_periph, lock_llpin);
|
#if PLAT_LOCK_BTN
|
||||||
|
SystemSettings.editable = false;
|
||||||
|
#else
|
||||||
|
SystemSettings.editable = (PLAT_LOCK_1CLOSED != LL_GPIO_IsInputPinSet(lock_periph, lock_llpin));
|
||||||
|
#endif
|
||||||
dbg("Settings editable? %d", SystemSettings.editable);
|
dbg("Settings editable? %d", SystemSettings.editable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,6 @@
|
|||||||
#ifndef GEX_LOCK_JUMPER_H
|
#ifndef GEX_LOCK_JUMPER_H
|
||||||
#define GEX_LOCK_JUMPER_H
|
#define GEX_LOCK_JUMPER_H
|
||||||
|
|
||||||
#include "plat_compat.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init the lock jumper subsystem
|
* Init the lock jumper subsystem
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/07/07.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GEX_CORE_PLAT_CONFIG_H
|
||||||
|
#define GEX_CORE_PLAT_CONFIG_H
|
||||||
|
|
||||||
|
#define VFS_DRIVE_NAME "GEX"
|
||||||
|
|
||||||
|
// -------- Priorities -------------
|
||||||
|
#define TSK_MAIN_PRIO osPriorityNormal
|
||||||
|
#define TSK_JOBS_PRIO osPriorityHigh
|
||||||
|
#define TSK_TIMERS_PRIO 4 // this must be in the 0-7 range
|
||||||
|
|
||||||
|
// -------- Static buffers ---------
|
||||||
|
// USB / VFS task stack size
|
||||||
|
#if DISABLE_MSC
|
||||||
|
#define TSK_STACK_MAIN 100 // without MSC the stack usage is significantly lower
|
||||||
|
#else
|
||||||
|
#define TSK_STACK_MAIN 160
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 180 is normally enough if not doing extensive debug logging
|
||||||
|
#define TSK_STACK_MSG 220 // TF message handler task stack size (all unit commands run on this thread)
|
||||||
|
#define TSK_STACK_IDLE 64 //configMINIMAL_STACK_SIZE
|
||||||
|
#define TSK_STACK_TIMERS 64 //configTIMER_TASK_STACK_DEPTH
|
||||||
|
|
||||||
|
#define PLAT_HEAP_SIZE 4096
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define BULK_READ_BUF_LEN 256 // Buffer for TF bulk reads
|
||||||
|
#define UNIT_TMP_LEN 256 // Buffer for internal unit operations
|
||||||
|
|
||||||
|
#define FLASH_SAVE_BUF_LEN 128 // Malloc'd buffer for saving to flash
|
||||||
|
|
||||||
|
#define MSG_QUE_SLOT_SIZE 64 // FIXME this should be possible to lower, but there's some bug with bulk transfer / INI parser
|
||||||
|
#define RX_QUE_CAPACITY 16 // TinyFrame rx queue size (64 bytes each)
|
||||||
|
|
||||||
|
#define TF_MAX_PAYLOAD_RX 512 // TF max Rx payload
|
||||||
|
#define TF_SENDBUF_LEN 512 // TF transmit buffer (can be less than a full frame)
|
||||||
|
|
||||||
|
#define TF_MAX_ID_LST 4 // Frame ID listener count
|
||||||
|
#define TF_MAX_TYPE_LST 6 // Frame Type listener count
|
||||||
|
#define TF_MAX_GEN_LST 1 // Generic listener count
|
||||||
|
|
||||||
|
#define USBD_MAX_STR_DESC_SIZ 64 // Descriptor conversion buffer (used for converting ASCII to UTF-16, must be 2x the size of the longest descriptor)
|
||||||
|
#define MSC_MEDIA_PACKET 512 // Mass storage sector size (packet)
|
||||||
|
|
||||||
|
#define INI_KEY_MAX 20 // Ini parser key buffer
|
||||||
|
#define INI_VALUE_MAX 30 // Ini parser value buffer
|
||||||
|
|
||||||
|
// -------- Stack buffers ----------
|
||||||
|
#define DBG_BUF_LEN 100 // Size of the snprintf buffer for debug messages
|
||||||
|
#define ERR_MSG_STR_LEN 64 // Error message buffer size
|
||||||
|
#define IWBUFFER_LEN 80 // Ini writer buffer for sprintf
|
||||||
|
|
||||||
|
// -------- Timeouts ------------
|
||||||
|
#define TF_PARSER_TIMEOUT_TICKS 100 // Timeout for receiving & parsing a frame
|
||||||
|
#define BULK_LST_TIMEOUT_MS 2000 // timeout for the bulk transaction to expire
|
||||||
|
#define MSG_QUE_POST_TIMEOUT 200 // Time to post to the messages / jobs queue
|
||||||
|
|
||||||
|
|
||||||
|
#endif //GEX_CORE_PLAT_CONFIG_H
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "debug_uart.h"
|
#include "debug_uart.h"
|
||||||
#include "irq_dispatcher.h"
|
#include "irq_dispatcher.h"
|
||||||
#include "timebase.h"
|
#include "timebase.h"
|
||||||
|
#include "watchdog.h"
|
||||||
|
|
||||||
void plat_init(void)
|
void plat_init(void)
|
||||||
{
|
{
|
||||||
@@ -39,4 +40,6 @@ void plat_init(void)
|
|||||||
settings_load(); // XXX maybe this should be moved to the main task
|
settings_load(); // XXX maybe this should be moved to the main task
|
||||||
|
|
||||||
comm_init();
|
comm_init();
|
||||||
|
|
||||||
|
wd_init();
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-220
@@ -2,243 +2,42 @@
|
|||||||
// Created by MightyPork on 2017/11/26.
|
// Created by MightyPork on 2017/11/26.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <units/fcap/unit_fcap.h>
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "usbd_core.h"
|
#include "usbd_core.h"
|
||||||
#include "USB/usb_device.h"
|
#include "USB/usb_device.h"
|
||||||
#include "framework/resources.h"
|
#include "framework/resources.h"
|
||||||
#include "framework/unit_registry.h"
|
#include "framework/unit_registry.h"
|
||||||
#include "units/digital_out/unit_dout.h"
|
#include "comm/interfaces.h"
|
||||||
|
|
||||||
#include "units/digital_in/unit_din.h"
|
|
||||||
#include "units/neopixel/unit_neopixel.h"
|
|
||||||
#include "units/i2c/unit_i2c.h"
|
|
||||||
#include "units/1wire/unit_1wire.h"
|
|
||||||
#include "units/adc/unit_adc.h"
|
|
||||||
#include "units/test/unit_test.h"
|
|
||||||
#include "units/usart/unit_usart.h"
|
|
||||||
#include "units/spi/unit_spi.h"
|
|
||||||
#include "units/sipo/unit_sipo.h"
|
|
||||||
#include "hw_utils.h"
|
#include "hw_utils.h"
|
||||||
|
|
||||||
|
#include "units_manifest.h"
|
||||||
|
|
||||||
|
extern uint32_t plat_init_resources2(void);
|
||||||
|
|
||||||
|
// TODO split this and the plat_compat files to per-platform ones stored in the platform project
|
||||||
|
|
||||||
void plat_init_resources(void)
|
void plat_init_resources(void)
|
||||||
{
|
{
|
||||||
|
// we use |= here, even though return values are not booleans - success is 0,
|
||||||
|
// thus any problem results in nonzero and the assert will trip.
|
||||||
uint32_t rv = 0;
|
uint32_t rv = 0;
|
||||||
|
|
||||||
// enable clock for units we use
|
// periphs available everywhere - enable clock
|
||||||
hw_periph_clock_enable(DMA1);
|
hw_periph_clock_enable(DMA1);
|
||||||
#ifdef DMA2
|
#ifdef DMA2
|
||||||
hw_periph_clock_enable(DMA2);
|
hw_periph_clock_enable(DMA2);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// --- Common unit drivers ---
|
// EXTI are always available
|
||||||
|
rsc_free_range(NULL, R_EXTI0, R_EXTI15);
|
||||||
#if HAVE_TEST_UNIT
|
|
||||||
ureg_add_type(&UNIT_TEST);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// --- platform specific resource releases and claims ---
|
// --- platform specific resource releases and claims ---
|
||||||
|
|
||||||
#if defined(GEX_PLAT_F103_BLUEPILL)
|
|
||||||
// Platform STM32F103C8T6 Bluepill ($4 board from eBay)
|
|
||||||
|
|
||||||
// Units supported by the platform (known to work correctly)
|
// Units supported by the platform (known to work correctly)
|
||||||
|
// - this is a macro created in the Makefile, registering all enabled units
|
||||||
|
UNITS_REGISTER_CMD;
|
||||||
|
|
||||||
// free all present resources
|
rv = plat_init_resources2();
|
||||||
{
|
|
||||||
rsc_free_range(NULL, R_ADC1, R_ADC2);
|
|
||||||
rsc_free_range(NULL, R_I2C1, R_I2C2);
|
|
||||||
rsc_free_range(NULL, R_SPI1, R_SPI2);
|
|
||||||
rsc_free_range(NULL, R_TIM1, R_TIM4);
|
|
||||||
rsc_free_range(NULL, R_USART1, R_USART3);
|
|
||||||
rsc_free_range(NULL, R_PA0, R_PA15);
|
|
||||||
rsc_free_range(NULL, R_PB0, R_PB15);
|
|
||||||
rsc_free_range(NULL, R_PC13, R_PC15);
|
|
||||||
rsc_free_range(NULL, R_PD0, R_PD1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Claim resources not available due to board layout or internal usage
|
|
||||||
{
|
|
||||||
// HAL timebase
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_TIM1);
|
|
||||||
// HSE crystal
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PD0);
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PD1);
|
|
||||||
// SWD
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA13);
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA14);
|
|
||||||
// USB
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA11);
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA12);
|
|
||||||
// BOOT pin(s)
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PB2); // BOOT1
|
|
||||||
}
|
|
||||||
#elif defined(GEX_PLAT_F072_DISCOVERY)
|
|
||||||
// Platform STM32F073RBT
|
|
||||||
|
|
||||||
// Additional GPIO ports
|
|
||||||
__HAL_RCC_GPIOF_CLK_ENABLE();
|
|
||||||
|
|
||||||
// Units supported by the platform (known to work correctly)
|
|
||||||
ureg_add_type(&UNIT_DOUT);
|
|
||||||
ureg_add_type(&UNIT_DIN);
|
|
||||||
ureg_add_type(&UNIT_NEOPIXEL);
|
|
||||||
ureg_add_type(&UNIT_I2C);
|
|
||||||
ureg_add_type(&UNIT_SPI);
|
|
||||||
ureg_add_type(&UNIT_USART);
|
|
||||||
ureg_add_type(&UNIT_1WIRE);
|
|
||||||
ureg_add_type(&UNIT_ADC);
|
|
||||||
ureg_add_type(&UNIT_SIPO);
|
|
||||||
ureg_add_type(&UNIT_FCAP);
|
|
||||||
|
|
||||||
// Free all present resources
|
|
||||||
{
|
|
||||||
rsc_free(NULL, R_ADC1);
|
|
||||||
// rsc_free(NULL, R_CAN1);
|
|
||||||
// rsc_free_range(NULL, R_COMP1, R_COMP2);
|
|
||||||
rsc_free(NULL, R_DAC1);
|
|
||||||
// rsc_free(NULL, R_HDMI_CEC);
|
|
||||||
// rsc_free(NULL, R_TSC);
|
|
||||||
rsc_free_range(NULL, R_I2C1, R_I2C2);
|
|
||||||
// rsc_free_range(NULL, R_I2S1, R_I2S2);
|
|
||||||
rsc_free_range(NULL, R_SPI1, R_SPI2);
|
|
||||||
rsc_free_range(NULL, R_TIM1, R_TIM3);
|
|
||||||
rsc_free_range(NULL, R_TIM6, R_TIM7);
|
|
||||||
rsc_free_range(NULL, R_TIM14, R_TIM17);
|
|
||||||
rsc_free_range(NULL, R_USART1, R_USART4);
|
|
||||||
rsc_free_range(NULL, R_DMA1_1, R_DMA1_7);
|
|
||||||
|
|
||||||
rsc_free_range(NULL, R_PA0, R_PA15);
|
|
||||||
rsc_free_range(NULL, R_PB0, R_PB15);
|
|
||||||
rsc_free_range(NULL, R_PC0, R_PC15);
|
|
||||||
rsc_free(NULL, R_PD2);
|
|
||||||
rsc_free_range(NULL, R_PF0, R_PF1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Claim resources not available due to board layout or internal usage
|
|
||||||
{
|
|
||||||
// HAL timebase
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_TIM1);
|
|
||||||
// HSE crystal
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PF0);
|
|
||||||
//rv |= rsc_claim(&UNIT_SYSTEM, R_PF1); // - not used in BYPASS mode
|
|
||||||
// SWD
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA13);
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA14);
|
|
||||||
// USB
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA11);
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA12);
|
|
||||||
// BOOT pin(s)
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PB2); // BOOT1
|
|
||||||
}
|
|
||||||
#elif defined(GEX_PLAT_F303_DISCOVERY)
|
|
||||||
// Platform STM32F303VCT
|
|
||||||
|
|
||||||
// Additional GPIO ports
|
|
||||||
__HAL_RCC_GPIOF_CLK_ENABLE();
|
|
||||||
|
|
||||||
// Units supported by the platform (known to work correctly)
|
|
||||||
// ureg_add_type(&UNIT_XYZ);
|
|
||||||
|
|
||||||
// Free all present resources
|
|
||||||
{
|
|
||||||
rsc_free_range(NULL, R_ADC1, R_ADC4);
|
|
||||||
// rsc_free(NULL, R_CAN1);
|
|
||||||
// rsc_free_range(NULL, R_COMP1, R_COMP7);
|
|
||||||
// rsc_free(NULL, R_HDMI_CEC);
|
|
||||||
rsc_free(NULL, R_DAC1);
|
|
||||||
rsc_free_range(NULL, R_I2C1, R_I2C2);
|
|
||||||
rsc_free_range(NULL, R_I2S2, R_I2S3);
|
|
||||||
// rsc_free_range(NULL, R_OPAMP1, R_OPAMP4);
|
|
||||||
rsc_free_range(NULL, R_SPI1, R_SPI3);
|
|
||||||
rsc_free_range(NULL, R_TIM1, R_TIM4);
|
|
||||||
rsc_free_range(NULL, R_TIM6, R_TIM8);
|
|
||||||
rsc_free_range(NULL, R_TIM15, R_TIM17);
|
|
||||||
// rsc_free(NULL, R_TSC);
|
|
||||||
rsc_free_range(NULL, R_USART1, R_USART5);
|
|
||||||
|
|
||||||
rsc_free_range(NULL, R_PA0, R_PA15);
|
|
||||||
rsc_free_range(NULL, R_PB0, R_PB15);
|
|
||||||
rsc_free_range(NULL, R_PC0, R_PC15);
|
|
||||||
rsc_free_range(NULL, R_PD0, R_PD15);
|
|
||||||
rsc_free_range(NULL, R_PE0, R_PE15);
|
|
||||||
|
|
||||||
rsc_free_range(NULL, R_PF0, R_PF2);
|
|
||||||
rsc_free(NULL, R_PF4);
|
|
||||||
rsc_free_range(NULL, R_PF9, R_PF10);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Claim resources not available due to board layout or internal usage
|
|
||||||
{
|
|
||||||
// HAL timebase
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_TIM1);
|
|
||||||
// HSE crystal
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PF0);
|
|
||||||
//rv |= rsc_claim(&UNIT_SYSTEM, R_PF1); // - not used in BYPASS mode
|
|
||||||
// SWD
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA13);
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA14);
|
|
||||||
// USB
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA11);
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA12);
|
|
||||||
// BOOT pin(s)
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PB2); // BOOT1
|
|
||||||
}
|
|
||||||
#elif defined(GEX_PLAT_F407_DISCOVERY)
|
|
||||||
// Platform STM32F407VGT
|
|
||||||
|
|
||||||
// Additional GPIO ports
|
|
||||||
__HAL_RCC_GPIOF_CLK_ENABLE();
|
|
||||||
|
|
||||||
// Units supported by the platform (known to work correctly)
|
|
||||||
// ureg_add_type(&UNIT_XYZ);
|
|
||||||
|
|
||||||
// Free all present resources
|
|
||||||
{
|
|
||||||
rsc_free_range(NULL, R_ADC1, R_ADC3);
|
|
||||||
// rsc_free_range(NULL, R_CAN1, R_CAN2);
|
|
||||||
// rsc_free_range(NULL, R_COMP1, R_COMP7);
|
|
||||||
rsc_free(NULL, R_DAC1);
|
|
||||||
// rsc_free(NULL, R_DCMI);
|
|
||||||
// rsc_free(NULL, R_ETH);
|
|
||||||
// rsc_free(NULL, R_FSMC);
|
|
||||||
rsc_free_range(NULL, R_I2C1, R_I2C3);
|
|
||||||
rsc_free_range(NULL, R_I2S2, R_I2S3);
|
|
||||||
// rsc_free(NULL, R_SDIO);
|
|
||||||
rsc_free_range(NULL, R_SPI1, R_SPI3);
|
|
||||||
rsc_free_range(NULL, R_TIM1, R_TIM14);
|
|
||||||
rsc_free_range(NULL, R_USART1, R_USART3);
|
|
||||||
rsc_free(NULL, R_USART6);
|
|
||||||
|
|
||||||
rsc_free_range(NULL, R_PA0, R_PA15);
|
|
||||||
rsc_free_range(NULL, R_PB0, R_PB15);
|
|
||||||
rsc_free_range(NULL, R_PC0, R_PC15);
|
|
||||||
rsc_free_range(NULL, R_PD0, R_PD15);
|
|
||||||
rsc_free_range(NULL, R_PE0, R_PE15);
|
|
||||||
// also has 2 PH pins
|
|
||||||
|
|
||||||
// F407 appears to have fewer GPIOs than F303?
|
|
||||||
}
|
|
||||||
|
|
||||||
// Claim resources not available due to board layout or internal usage
|
|
||||||
{
|
|
||||||
// HAL timebase
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_TIM1);
|
|
||||||
// HSE crystal
|
|
||||||
// H0 and H1
|
|
||||||
// SWD
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA13);
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA14);
|
|
||||||
// USB
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA11);
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA12);
|
|
||||||
// BOOT pin(s)
|
|
||||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PB2); // BOOT1
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#error "BAD PLATFORM!"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
assert_param(rv == 0);
|
assert_param(rv == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,13 +49,12 @@ void plat_init_resources(void)
|
|||||||
*/
|
*/
|
||||||
void plat_usb_reconnect(void)
|
void plat_usb_reconnect(void)
|
||||||
{
|
{
|
||||||
// TODO add better reset methods available on different chips
|
if (gActiveComport != COMPORT_USB) return;
|
||||||
|
|
||||||
|
// TODO add other reset methods available on different chips (e.g. externam FET)
|
||||||
USBD_LL_Reset(&hUsbDeviceFS);
|
USBD_LL_Reset(&hUsbDeviceFS);
|
||||||
|
|
||||||
#if defined(GEX_PLAT_F103_BLUEPILL)
|
#if PLAT_USB_PU_CTL
|
||||||
// F103 doesn't have pull-up control
|
|
||||||
#else
|
|
||||||
HAL_PCD_DevDisconnect(&hpcd_USB_FS);
|
HAL_PCD_DevDisconnect(&hpcd_USB_FS);
|
||||||
osDelay(100);
|
osDelay(100);
|
||||||
HAL_PCD_DevConnect(&hpcd_USB_FS);
|
HAL_PCD_DevConnect(&hpcd_USB_FS);
|
||||||
|
|||||||
+7
-1
@@ -17,8 +17,15 @@
|
|||||||
|
|
||||||
// FreeRTOS includes
|
// FreeRTOS includes
|
||||||
#include <cmsis_os.h>
|
#include <cmsis_os.h>
|
||||||
|
// platform-independent GEX config
|
||||||
|
#include "plat_config.h"
|
||||||
// platform-specific stuff (includes stm32 driver headers)
|
// platform-specific stuff (includes stm32 driver headers)
|
||||||
#include "plat_compat.h"
|
#include "plat_compat.h"
|
||||||
|
|
||||||
|
#define PLAT_AHB_HZ (PLAT_AHB_MHZ*1000000)
|
||||||
|
#define PLAT_APB1_HZ (PLAT_APB1_MHZ*1000000)
|
||||||
|
#define PLAT_APB2_HZ (PLAT_APB2_MHZ*1000000)
|
||||||
|
|
||||||
// assert_param, trap...
|
// assert_param, trap...
|
||||||
#include "stm32_assert.h"
|
#include "stm32_assert.h"
|
||||||
// inIRQ etc
|
// inIRQ etc
|
||||||
@@ -34,7 +41,6 @@
|
|||||||
// GEX version string
|
// GEX version string
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+16
-8
@@ -50,13 +50,7 @@ static inline void led_off(void)
|
|||||||
/** Set up the LED */
|
/** Set up the LED */
|
||||||
void Indicator_Init(void)
|
void Indicator_Init(void)
|
||||||
{
|
{
|
||||||
bool suc = true;
|
assert_param(E_SUCCESS == rsc_claim_pin(&UNIT_SYSTEM, STATUS_LED_PORT, STATUS_LED_PIN));
|
||||||
|
|
||||||
// Resolve and claim resource
|
|
||||||
Resource rsc = hw_pin2resource(STATUS_LED_PORT, STATUS_LED_PIN, &suc);
|
|
||||||
assert_param(suc);
|
|
||||||
|
|
||||||
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, rsc));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set indicator ON */
|
/** Set indicator ON */
|
||||||
@@ -67,6 +61,12 @@ void Indicator_Effect(enum GEX_StatusIndicator indicator)
|
|||||||
led_on();
|
led_on();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prevent the two disk ops interfering (happens in write-reload)
|
||||||
|
if (indicator == STATUS_DISK_BUSY && active_effect == STATUS_DISK_BUSY_SHORT) return;
|
||||||
|
if (indicator == STATUS_DISK_BUSY_SHORT && active_effect == STATUS_DISK_BUSY) return;
|
||||||
|
|
||||||
|
// TODO add some better protection against effect overlap?
|
||||||
|
|
||||||
active_effect = indicator;
|
active_effect = indicator;
|
||||||
effect_time = 0;
|
effect_time = 0;
|
||||||
}
|
}
|
||||||
@@ -125,7 +125,15 @@ void Indicator_Tick(void)
|
|||||||
active_effect = STATUS_NONE;
|
active_effect = STATUS_NONE;
|
||||||
}
|
}
|
||||||
else if (effect_time % 100 == 0) led_on();
|
else if (effect_time % 100 == 0) led_on();
|
||||||
else if (effect_time % 100 == 50) led_off();
|
else if (effect_time % 100 == 20) led_off();
|
||||||
|
}
|
||||||
|
else if (active_effect == STATUS_DISK_BUSY_SHORT) {
|
||||||
|
if (effect_time >= 200) {
|
||||||
|
led_off();
|
||||||
|
active_effect = STATUS_NONE;
|
||||||
|
}
|
||||||
|
else if (effect_time % 100 == 0) led_on();
|
||||||
|
else if (effect_time % 100 == 20) led_off();
|
||||||
}
|
}
|
||||||
else if (active_effect == STATUS_WELCOME) {
|
else if (active_effect == STATUS_WELCOME) {
|
||||||
if (effect_time == 0) led_on();
|
if (effect_time == 0) led_on();
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ enum GEX_StatusIndicator {
|
|||||||
STATUS_NONE = 0,
|
STATUS_NONE = 0,
|
||||||
STATUS_FAULT,
|
STATUS_FAULT,
|
||||||
STATUS_DISK_BUSY,
|
STATUS_DISK_BUSY,
|
||||||
|
STATUS_DISK_BUSY_SHORT,
|
||||||
STATUS_DISK_ATTACHED,
|
STATUS_DISK_ATTACHED,
|
||||||
STATUS_DISK_REMOVED,
|
STATUS_DISK_REMOVED,
|
||||||
STATUS_WELCOME,
|
STATUS_WELCOME,
|
||||||
|
|||||||
+20
-7
@@ -7,8 +7,6 @@
|
|||||||
|
|
||||||
// ---------------------------- HAL TIMEBASE -----------------------------
|
// ---------------------------- HAL TIMEBASE -----------------------------
|
||||||
|
|
||||||
#define TIMEBASE_TIMER TIM17
|
|
||||||
|
|
||||||
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
|
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
|
||||||
{
|
{
|
||||||
// EDIT - used 17 instead because 14 was needed for fcap
|
// EDIT - used 17 instead because 14 was needed for fcap
|
||||||
@@ -102,21 +100,36 @@ uint64_t PTIM_GetMicrotime(void)
|
|||||||
return (uint64_t) uwMillis * 1000 + uwMicros;
|
return (uint64_t) uwMillis * 1000 + uwMicros;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** microsecond delay */
|
/** microsecond delay */
|
||||||
void PTIM_MicroDelay(uint16_t usec)
|
void PTIM_MicroDelayAligned(uint32_t usec, register const uint32_t start)
|
||||||
{
|
{
|
||||||
assert_param(usec < 1000);
|
assert_param(usec < 1000);
|
||||||
|
|
||||||
const uint16_t start = (uint16_t) TIMEBASE_TIMER->CNT;
|
register const uint32_t remain = (1000 - start);
|
||||||
const uint16_t remain = (uint16_t) (999 - start);
|
|
||||||
|
|
||||||
if (remain > usec) {
|
if (remain > usec) {
|
||||||
// timer still has enough space going forward to pass the required wait time
|
// timer still has enough space going forward to pass the required wait time
|
||||||
for (; TIMEBASE_TIMER->CNT < start + usec;);
|
register const uint32_t end = start + usec;
|
||||||
|
while (TIMEBASE_TIMER->CNT < end) {
|
||||||
|
__NOP();
|
||||||
|
__NOP();
|
||||||
|
__NOP();
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// timer is too close to the end
|
// timer is too close to the end
|
||||||
usec -= remain;
|
usec -= remain;
|
||||||
for (; TIMEBASE_TIMER->CNT >= start || TIMEBASE_TIMER->CNT < usec;);
|
while (1) {
|
||||||
|
register const uint32_t t = TIMEBASE_TIMER->CNT;
|
||||||
|
if (t < start && t >= usec) return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** microsecond delay */
|
||||||
|
void PTIM_MicroDelay(const uint32_t usec)
|
||||||
|
{
|
||||||
|
PTIM_MicroDelayAligned(usec, TIMEBASE_TIMER->CNT);
|
||||||
|
}
|
||||||
|
|||||||
+24
-4
@@ -8,11 +8,13 @@
|
|||||||
// and interrupts.
|
// and interrupts.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef GEX_F072_TIMEBASE_H
|
#ifndef GEX_CORE_TIMEBASE_H
|
||||||
#define GEX_F072_TIMEBASE_H
|
#define GEX_CORE_TIMEBASE_H
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
|
#define TIMEBASE_TIMER TIM17
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Precision timer: get microtime as uint64_t
|
* Precision timer: get microtime as uint64_t
|
||||||
* This timestamp should be monotonously increasing with a precision of ±0.5µs
|
* This timestamp should be monotonously increasing with a precision of ±0.5µs
|
||||||
@@ -36,6 +38,24 @@ static inline uint32_t PTIM_GetTime(void)
|
|||||||
*
|
*
|
||||||
* @param usec - max 998
|
* @param usec - max 998
|
||||||
*/
|
*/
|
||||||
void PTIM_MicroDelay(uint16_t usec);
|
void PTIM_MicroDelay(uint32_t usec);
|
||||||
|
|
||||||
#endif //GEX_F072_TIMEBASE_H
|
/**
|
||||||
|
* Microsecond busy delay with alignment (reduced length jitter but possible up to 1 us delay)
|
||||||
|
*
|
||||||
|
* @param usec
|
||||||
|
*/
|
||||||
|
void PTIM_MicroDelayAligned(uint32_t usec, uint32_t start);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait until the next micro timer tick
|
||||||
|
*/
|
||||||
|
static inline uint32_t PTIM_MicroDelayAlign(void)
|
||||||
|
{
|
||||||
|
const uint32_t c = TIMEBASE_TIMER->CNT;
|
||||||
|
uint32_t res;
|
||||||
|
while ((res = TIMEBASE_TIMER->CNT) == c);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //GEX_CORE_TIMEBASE_H
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/02/27.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#include "watchdog.h"
|
||||||
|
|
||||||
|
static volatile uint16_t suspend_depth = 0;
|
||||||
|
static volatile bool restart_pending = false;
|
||||||
|
|
||||||
|
void wd_init(void)
|
||||||
|
{
|
||||||
|
dbg("IWDG init, time 2s");
|
||||||
|
|
||||||
|
LL_IWDG_Enable(IWDG);
|
||||||
|
LL_IWDG_EnableWriteAccess(IWDG);
|
||||||
|
LL_IWDG_SetPrescaler(IWDG, LL_IWDG_PRESCALER_32); // 0.8 ms
|
||||||
|
LL_IWDG_SetReloadCounter(IWDG, 2500); // 2s. max 4095
|
||||||
|
while (!LL_IWDG_IsReady(IWDG));
|
||||||
|
|
||||||
|
// reload
|
||||||
|
LL_IWDG_ReloadCounter(IWDG);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wd_suspend(void)
|
||||||
|
{
|
||||||
|
vPortEnterCritical();
|
||||||
|
if (suspend_depth < 0xFFFF) {
|
||||||
|
suspend_depth++;
|
||||||
|
}
|
||||||
|
vPortExitCritical();
|
||||||
|
}
|
||||||
|
|
||||||
|
void wd_resume(void)
|
||||||
|
{
|
||||||
|
vPortEnterCritical();
|
||||||
|
if (suspend_depth > 0) {
|
||||||
|
suspend_depth--;
|
||||||
|
|
||||||
|
if (suspend_depth == 0 && restart_pending) {
|
||||||
|
restart_pending = false;
|
||||||
|
LL_IWDG_ReloadCounter(IWDG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vPortExitCritical();
|
||||||
|
}
|
||||||
|
|
||||||
|
void wd_restart(void)
|
||||||
|
{
|
||||||
|
vPortEnterCritical();
|
||||||
|
if (suspend_depth == 0) {
|
||||||
|
LL_IWDG_ReloadCounter(IWDG);
|
||||||
|
} else {
|
||||||
|
restart_pending = true;
|
||||||
|
}
|
||||||
|
vPortExitCritical();
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2018/02/27.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GEX_CORE_WATCHDOG_H
|
||||||
|
#define GEX_CORE_WATCHDOG_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the application watchdog
|
||||||
|
*/
|
||||||
|
void wd_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Suspend watchdog restarts until resumed
|
||||||
|
* (used in other tasks to prevent the main task clearing the wd if the other task is locked up)
|
||||||
|
*
|
||||||
|
* The suspend/resume calls can be stacked.
|
||||||
|
*/
|
||||||
|
void wd_suspend(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resume restarts
|
||||||
|
*/
|
||||||
|
void wd_resume(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restart the wd. If restarts are suspended, postpone the restart until resumed
|
||||||
|
* and then restart immediately.
|
||||||
|
*/
|
||||||
|
void wd_restart(void);
|
||||||
|
|
||||||
|
#endif //GEX_CORE_WATCHDOG_H
|
||||||
+38
-27
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "platform/lock_jumper.h"
|
#include "platform/lock_jumper.h"
|
||||||
|
#include "platform/watchdog.h"
|
||||||
#include "status_led.h"
|
#include "status_led.h"
|
||||||
#include "utils/stacksmon.h"
|
#include "utils/stacksmon.h"
|
||||||
#include "vfs/vfs_manager.h"
|
#include "vfs/vfs_manager.h"
|
||||||
@@ -11,8 +12,7 @@
|
|||||||
#include "usb_device.h"
|
#include "usb_device.h"
|
||||||
#include "usbd_msc.h"
|
#include "usbd_msc.h"
|
||||||
#include "task_main.h"
|
#include "task_main.h"
|
||||||
|
#include "comm/interfaces.h"
|
||||||
extern void plat_init(void);
|
|
||||||
|
|
||||||
/* TaskUsbEvent function */
|
/* TaskUsbEvent function */
|
||||||
void TaskMain(void const * argument)
|
void TaskMain(void const * argument)
|
||||||
@@ -26,14 +26,16 @@ void TaskMain(void const * argument)
|
|||||||
|
|
||||||
Indicator_Effect(STATUS_WELCOME);
|
Indicator_Effect(STATUS_WELCOME);
|
||||||
|
|
||||||
uint32_t startTime = xTaskGetTickCount();
|
const uint32_t bootTime = HAL_GetTick();
|
||||||
|
uint32_t startTime = bootTime;
|
||||||
uint32_t cnt = 1;
|
uint32_t cnt = 1;
|
||||||
|
bool waiting_for_usb = true;
|
||||||
while(1) {
|
while(1) {
|
||||||
uint32_t msg;
|
uint32_t msg;
|
||||||
xTaskNotifyWait(0, UINT32_MAX, &msg, 100); // time out if nothing happened
|
xTaskNotifyWait(0, UINT32_MAX, &msg, 100); // time out if nothing happened
|
||||||
|
|
||||||
// periodic updates to the VFS driver
|
// periodic updates to the VFS driver
|
||||||
uint32_t now = xTaskGetTickCount();
|
uint32_t now = HAL_GetTick();
|
||||||
uint32_t elapsed = now - startTime;
|
uint32_t elapsed = now - startTime;
|
||||||
if (elapsed >= 100) {
|
if (elapsed >= 100) {
|
||||||
// interval 100ms or more - slow periodic
|
// interval 100ms or more - slow periodic
|
||||||
@@ -47,6 +49,11 @@ void TaskMain(void const * argument)
|
|||||||
|
|
||||||
cnt++;
|
cnt++;
|
||||||
Indicator_Heartbeat();
|
Indicator_Heartbeat();
|
||||||
|
|
||||||
|
wd_restart();
|
||||||
|
|
||||||
|
// If USB has no signal, set up alternate communication interface
|
||||||
|
com_switch_transfer_if_needed();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if no message and it just timed out, go wait some more...
|
// if no message and it just timed out, go wait some more...
|
||||||
@@ -60,35 +67,39 @@ void TaskMain(void const * argument)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Endpoint 0 - control messages for the different classes
|
if (gActiveComport == COMPORT_USB) {
|
||||||
if (msg & USBEVT_FLAG_EP0_RX_RDY) {
|
// Endpoint 0 - control messages for the different classes
|
||||||
USBD_CDC_EP0_RxReady(&hUsbDeviceFS);
|
if (msg & USBEVT_FLAG_EP0_RX_RDY) {
|
||||||
}
|
USBD_CDC_EP0_RxReady(&hUsbDeviceFS);
|
||||||
|
}
|
||||||
|
|
||||||
if (msg & USBEVT_FLAG_EP0_TX_SENT) {
|
if (msg & USBEVT_FLAG_EP0_TX_SENT) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef DISABLE_MSC
|
#ifndef DISABLE_MSC
|
||||||
// MSC - read/write etc
|
// MSC - read/write etc
|
||||||
if (msg & (USBEVT_FLAG_EPx_IN(MSC_EPIN_ADDR))) {
|
if (msg & (USBEVT_FLAG_EPx_IN(MSC_EPIN_ADDR))) {
|
||||||
USBD_MSC_DataIn(&hUsbDeviceFS, MSC_EPIN_ADDR);
|
USBD_MSC_DataIn(&hUsbDeviceFS, MSC_EPIN_ADDR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg & (USBEVT_FLAG_EPx_OUT(MSC_EPOUT_ADDR))) {
|
if (msg & (USBEVT_FLAG_EPx_OUT(MSC_EPOUT_ADDR))) {
|
||||||
USBD_MSC_DataOut(&hUsbDeviceFS, MSC_EPOUT_ADDR);
|
USBD_MSC_DataOut(&hUsbDeviceFS, MSC_EPOUT_ADDR);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// CDC - config packets and data in/out
|
// CDC - config packets and data in/out
|
||||||
// if (msg & (USBEVT_FLAG_EPx_IN(CDC_IN_EP))) {
|
// if (msg & (USBEVT_FLAG_EPx_IN(CDC_IN_EP))) {
|
||||||
// USBD_CDC_DataIn(&hUsbDeviceFS, CDC_IN_EP);
|
// USBD_CDC_DataIn(&hUsbDeviceFS, CDC_IN_EP);
|
||||||
// }
|
// }
|
||||||
if (msg & (USBEVT_FLAG_EPx_IN(CDC_CMD_EP))) {
|
|
||||||
USBD_CDC_DataIn(&hUsbDeviceFS, CDC_CMD_EP);
|
if (msg & (USBEVT_FLAG_EPx_IN(CDC_CMD_EP))) {
|
||||||
}
|
USBD_CDC_DataIn(&hUsbDeviceFS, CDC_CMD_EP);
|
||||||
if (msg & (USBEVT_FLAG_EPx_OUT(CDC_OUT_EP))) {
|
}
|
||||||
USBD_CDC_DataOut(&hUsbDeviceFS, CDC_OUT_EP);
|
|
||||||
|
if (msg & (USBEVT_FLAG_EPx_OUT(CDC_OUT_EP))) {
|
||||||
|
USBD_CDC_DataOut(&hUsbDeviceFS, CDC_OUT_EP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
#include "platform/watchdog.h"
|
||||||
#include "comm/messages.h"
|
#include "comm/messages.h"
|
||||||
#include "task_msg.h"
|
#include "task_msg.h"
|
||||||
|
|
||||||
@@ -85,7 +86,9 @@ void TaskMsgJob(const void *argument)
|
|||||||
#if CDC_LOOPBACK_TEST
|
#if CDC_LOOPBACK_TEST
|
||||||
TF_WriteImpl(comm, slot.msg.data, slot.msg.len);
|
TF_WriteImpl(comm, slot.msg.data, slot.msg.len);
|
||||||
#else
|
#else
|
||||||
|
wd_suspend();
|
||||||
TF_Accept(comm, slot.msg.data, slot.msg.len);
|
TF_Accept(comm, slot.msg.data, slot.msg.len);
|
||||||
|
wd_resume();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -5,8 +5,8 @@
|
|||||||
// and TinyFrame message handling
|
// and TinyFrame message handling
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef GEX_F072_TASK_MSG_H
|
#ifndef GEX_CORE_TASK_MSG_H
|
||||||
#define GEX_F072_TASK_MSG_H
|
#define GEX_CORE_TASK_MSG_H
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "sched_queue.h"
|
#include "sched_queue.h"
|
||||||
@@ -39,4 +39,4 @@ void rxQuePostMsg(uint8_t *buf, uint32_t len);
|
|||||||
extern volatile uint32_t msgQueHighWaterMark;
|
extern volatile uint32_t msgQueHighWaterMark;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif //GEX_F072_TASK_MSG_H
|
#endif //GEX_CORE_TASK_MSG_H
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
//
|
||||||
|
// Definition of nRF24L01+ pin mappings for the platform
|
||||||
|
// This file may be omitted if SUPPORT_NRF is not set in plat_compat.h
|
||||||
|
// See rsc_enum.h for the R_ resource constants
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GEX_NRF_PINS_H
|
||||||
|
#define GEX_NRF_PINS_H
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#include "rsc_enum.h"
|
||||||
|
|
||||||
|
#define NRF_SPI SPI2
|
||||||
|
#define NRF_R_SPI R_SPI2
|
||||||
|
|
||||||
|
#define NRF_IRQ_Pin LL_GPIO_PIN_15
|
||||||
|
#define NRF_IRQ_GPIO_Port GPIOC
|
||||||
|
#define NRF_R_IRQ R_PC15
|
||||||
|
#define NRF_EXTI_LINENUM 15
|
||||||
|
#define NRF_SYSCFG_EXTI_PORT LL_SYSCFG_EXTI_PORTC
|
||||||
|
|
||||||
|
#define NRF_NSS_Pin LL_GPIO_PIN_13
|
||||||
|
#define NRF_NSS_GPIO_Port GPIOC
|
||||||
|
#define NRF_R_NSS R_PC13
|
||||||
|
|
||||||
|
#define NRF_CE_Pin LL_GPIO_PIN_14
|
||||||
|
#define NRF_CE_GPIO_Port GPIOC
|
||||||
|
#define NRF_R_CE R_PC14
|
||||||
|
|
||||||
|
#define NRF_RST_Pin LL_GPIO_PIN_12
|
||||||
|
#define NRF_RST_GPIO_Port GPIOC
|
||||||
|
#define NRF_R_RST R_PC12
|
||||||
|
|
||||||
|
#define NRF_R_SCK R_PB13
|
||||||
|
#define NRF_SCK_AF LL_GPIO_AF_0
|
||||||
|
#define NRF_R_MISO R_PC2
|
||||||
|
#define NRF_MISO_AF LL_GPIO_AF_1
|
||||||
|
#define NRF_R_MOSI R_PC3
|
||||||
|
#define NRF_MOSI_AF LL_GPIO_AF_1
|
||||||
|
|
||||||
|
#endif //GEX_NRF_PINS_H
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#if defined(GEX_PLAT_F103_BLUEPILL) || defined(GEX_PLAT_F303_DISCOVERY) \
|
||||||
|
|| defined(GEX_PLAT_F407_DISCOVERY)
|
||||||
|
// This is for F103+
|
||||||
|
|
||||||
|
/* The lowest interrupt priority that can be used in a call to a "set priority"
|
||||||
|
function. */
|
||||||
|
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
|
||||||
|
|
||||||
|
#define configPRIO_BITS 4
|
||||||
|
|
||||||
|
/* The highest interrupt priority that can be used by any interrupt service
|
||||||
|
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
|
||||||
|
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
|
||||||
|
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
|
||||||
|
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
|
||||||
|
|
||||||
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||||
|
#elif defined(STM32F072xB)
|
||||||
|
// This is for F072
|
||||||
|
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 3
|
||||||
|
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 1
|
||||||
|
|
||||||
|
#define configPRIO_BITS 2
|
||||||
|
|
||||||
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
#else
|
||||||
|
#error "BAD PLATFORM!!"
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
#define DEBUG_USART_BAUD 115200
|
||||||
|
|
||||||
|
#if GEX_PLAT_F072
|
||||||
|
|
||||||
|
#define DEBUG_USART USART1
|
||||||
|
#define DEBUG_USART_RSC R_USART1
|
||||||
|
#define DEBUG_USART_PORT 'A'
|
||||||
|
#define DEBUG_USART_PIN 9
|
||||||
|
#define DEBUG_USART_AF 1
|
||||||
|
#define DEBUG_USART_PCLK PLAT_APB1_HZ
|
||||||
|
|
||||||
|
#elif GEX_PLAT_F103
|
||||||
|
|
||||||
|
#define DEBUG_USART USART2
|
||||||
|
#define DEBUG_USART_RSC R_USART2
|
||||||
|
#define DEBUG_USART_PORT 'A'
|
||||||
|
#define DEBUG_USART_PIN 2
|
||||||
|
#define DEBUG_USART_PCLK PLAT_APB1_HZ
|
||||||
|
|
||||||
|
#elif GEX_PLAT_F303
|
||||||
|
|
||||||
|
#define DEBUG_USART USART3
|
||||||
|
#define DEBUG_USART_RSC R_USART3
|
||||||
|
#define DEBUG_USART_PORT 'D'
|
||||||
|
#define DEBUG_USART_PIN 8
|
||||||
|
#define DEBUG_USART_AF 7
|
||||||
|
#define DEBUG_USART_PCLK PLAT_APB1_HZ
|
||||||
|
|
||||||
|
#elif GEX_PLAT_F407
|
||||||
|
|
||||||
|
#define DEBUG_USART USART2
|
||||||
|
#define DEBUG_USART_RSC R_USART2
|
||||||
|
#define DEBUG_USART_PORT 'A'
|
||||||
|
#define DEBUG_USART_PIN 2
|
||||||
|
#define DEBUG_USART_AF 7
|
||||||
|
#define DEBUG_USART_PCLK PLAT_APB1_HZ
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "BAD PLATFORM!"
|
||||||
|
#endif
|
||||||
@@ -5,72 +5,6 @@
|
|||||||
#ifndef GEX_PLAT_COMPAT_H
|
#ifndef GEX_PLAT_COMPAT_H
|
||||||
#define GEX_PLAT_COMPAT_H
|
#define GEX_PLAT_COMPAT_H
|
||||||
|
|
||||||
#define VFS_DRIVE_NAME "GEX"
|
|
||||||
|
|
||||||
// -------- Priorities -------------
|
|
||||||
#define TSK_MAIN_PRIO osPriorityNormal
|
|
||||||
#define TSK_JOBS_PRIO osPriorityHigh
|
|
||||||
#define TSK_TIMERS_PRIO 4 // this must be in the 0-7 range
|
|
||||||
|
|
||||||
// -------- Static buffers ---------
|
|
||||||
// USB / VFS task stack size
|
|
||||||
#if DISABLE_MSC
|
|
||||||
#define TSK_STACK_MAIN 100 // without MSC the stack usage is significantly lower
|
|
||||||
#else
|
|
||||||
#define TSK_STACK_MAIN 160
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 180 is normally enough if not doing extensive debug logging
|
|
||||||
#define TSK_STACK_MSG 200 // TF message handler task stack size (all unit commands run on this thread)
|
|
||||||
#define TSK_STACK_IDLE 64 //configMINIMAL_STACK_SIZE
|
|
||||||
#define TSK_STACK_TIMERS 64 //configTIMER_TASK_STACK_DEPTH
|
|
||||||
|
|
||||||
#define PLAT_HEAP_SIZE 4096
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define BULK_READ_BUF_LEN 256 // Buffer for TF bulk reads
|
|
||||||
#define UNIT_TMP_LEN 512 // Buffer for internal unit operations
|
|
||||||
|
|
||||||
#define FLASH_SAVE_BUF_LEN 128 // Malloc'd buffer for saving to flash
|
|
||||||
|
|
||||||
#define MSG_QUE_SLOT_SIZE 64 // FIXME this should be possible to lower, but there's some bug with bulk transfer / INI parser
|
|
||||||
#define RX_QUE_CAPACITY 16 // TinyFrame rx queue size (64 bytes each)
|
|
||||||
|
|
||||||
#define TF_MAX_PAYLOAD_RX 512 // TF max Rx payload
|
|
||||||
#define TF_SENDBUF_LEN 64 // TF transmit buffer (can be less than a full frame)
|
|
||||||
|
|
||||||
#define TF_MAX_ID_LST 4 // Frame ID listener count
|
|
||||||
#define TF_MAX_TYPE_LST 6 // Frame Type listener count
|
|
||||||
#define TF_MAX_GEN_LST 1 // Generic listener count
|
|
||||||
|
|
||||||
#define USBD_MAX_STR_DESC_SIZ 64 // Descriptor conversion buffer (used for converting ASCII to UTF-16, must be 2x the size of the longest descriptor)
|
|
||||||
#define MSC_MEDIA_PACKET 512 // Mass storage sector size (packet)
|
|
||||||
|
|
||||||
#define INI_KEY_MAX 20 // Ini parser key buffer
|
|
||||||
#define INI_VALUE_MAX 30 // Ini parser value buffer
|
|
||||||
|
|
||||||
// -------- Stack buffers ----------
|
|
||||||
#define DBG_BUF_LEN 100 // Size of the snprintf buffer for debug messages
|
|
||||||
#define ERR_MSG_STR_LEN 64 // Error message buffer size
|
|
||||||
#define IWBUFFER_LEN 80 // Ini writer buffer for sprintf
|
|
||||||
|
|
||||||
// -------- Timeouts ------------
|
|
||||||
#define TF_PARSER_TIMEOUT_TICKS 300 // Timeout for receiving & parsing a frame
|
|
||||||
#define BULK_LST_TIMEOUT_MS 500 // timeout for the bulk transaction to expire
|
|
||||||
#define MSG_QUE_POST_TIMEOUT 100 // Time to post to the messages / jobs queue
|
|
||||||
|
|
||||||
// -------- Platform specific includes and defines ---------
|
|
||||||
|
|
||||||
/// Feature flags:
|
|
||||||
// PLAT_FLASHBANKS - has the Banks field on the Flash config struct
|
|
||||||
// PLAT_NO_FLOATING_INPUTS - can't have digital inputs with no pull resistor
|
|
||||||
// PLAT_USB_PHYCLOCK - requires special config of phy clock for USB
|
|
||||||
// PLAT_USB_OTGFS - uses the USB OTG IP, needs different config code
|
|
||||||
// PLAT_LOCK_BTN - use a lock button instead of a lock jumper (push to toggle)
|
|
||||||
// PLAT_LOCK_1CLOSED - lock jumper is active (closed / button pressed) in logical 1
|
|
||||||
// PLAT_NO_AFNUM - legacy platform without numbered AF alternatives
|
|
||||||
|
|
||||||
#if defined(GEX_PLAT_F103_BLUEPILL)
|
#if defined(GEX_PLAT_F103_BLUEPILL)
|
||||||
|
|
||||||
// platform name for the version string
|
// platform name for the version string
|
||||||
@@ -124,10 +58,8 @@
|
|||||||
#define STATUS_LED_PORT 'C'
|
#define STATUS_LED_PORT 'C'
|
||||||
#define STATUS_LED_PIN 13
|
#define STATUS_LED_PIN 13
|
||||||
|
|
||||||
#elif defined(GEX_PLAT_F072_DISCOVERY)
|
#elif defined(STM32F072xB)
|
||||||
|
|
||||||
// platform name for the version string
|
|
||||||
#define GEX_PLATFORM "STM32F072-Discovery"
|
|
||||||
#define PLAT_AHB_MHZ 48
|
#define PLAT_AHB_MHZ 48
|
||||||
#define PLAT_APB1_MHZ 48
|
#define PLAT_APB1_MHZ 48
|
||||||
|
|
||||||
@@ -162,15 +94,54 @@
|
|||||||
// Number of GPIO ports A,B,C...
|
// Number of GPIO ports A,B,C...
|
||||||
#define PORTS_COUNT 6
|
#define PORTS_COUNT 6
|
||||||
|
|
||||||
// Lock jumper config
|
#if defined(GEX_PLAT_F072_DISCOVERY)
|
||||||
#define LOCK_JUMPER_PORT 'A'
|
// platform name for the version string
|
||||||
#define LOCK_JUMPER_PIN 0
|
#define GEX_PLATFORM "STM32F072-Discovery"
|
||||||
#define PLAT_LOCK_BTN 1 // toggle button instead of a jumper
|
|
||||||
#define PLAT_LOCK_1CLOSED 1 // toggle button active in log. 1
|
|
||||||
|
|
||||||
// Status LED config
|
// Lock jumper config
|
||||||
#define STATUS_LED_PORT 'C'
|
#define LOCK_JUMPER_PORT 'A'
|
||||||
#define STATUS_LED_PIN 6 // RED LED "UP"
|
#define LOCK_JUMPER_PIN 0
|
||||||
|
#define PLAT_LOCK_BTN 1 // toggle button instead of a jumper
|
||||||
|
#define PLAT_LOCK_1CLOSED 1 // toggle button active in log. 1
|
||||||
|
|
||||||
|
// Status LED config
|
||||||
|
#define STATUS_LED_PORT 'C'
|
||||||
|
#define STATUS_LED_PIN 6 // RED LED "UP"
|
||||||
|
#elif defined(GEX_PLAT_F072_HUB)
|
||||||
|
// platform name for the version string
|
||||||
|
#define GEX_PLATFORM "STM32F072-HUB"
|
||||||
|
|
||||||
|
#define PLAT_FULL_XTAL 1
|
||||||
|
|
||||||
|
// Lock jumper config
|
||||||
|
#define LOCK_JUMPER_PORT 'D'
|
||||||
|
#define LOCK_JUMPER_PIN 2
|
||||||
|
#define PLAT_LOCK_BTN 1 // toggle button instead of a jumper
|
||||||
|
#define PLAT_LOCK_1CLOSED 0 // toggle button active in log. 1
|
||||||
|
|
||||||
|
// Status LED config
|
||||||
|
#define STATUS_LED_PORT 'A'
|
||||||
|
#define STATUS_LED_PIN 15 // RED LED "UP"
|
||||||
|
#elif defined(GEX_PLAT_F072_ZERO)
|
||||||
|
// platform name for the version string
|
||||||
|
#define GEX_PLATFORM "STM32F072-ZERO"
|
||||||
|
|
||||||
|
#define PLAT_FULL_XTAL 1
|
||||||
|
|
||||||
|
// Lock jumper config
|
||||||
|
#define LOCK_JUMPER_PORT 'D'
|
||||||
|
#define LOCK_JUMPER_PIN 2
|
||||||
|
#define PLAT_LOCK_BTN 1 // toggle button instead of a jumper
|
||||||
|
#define PLAT_LOCK_1CLOSED 1 // toggle button active in log. 1
|
||||||
|
|
||||||
|
// Status LED config
|
||||||
|
#define STATUS_LED_PORT 'A'
|
||||||
|
#define STATUS_LED_PIN 15 // RED LED "UP"
|
||||||
|
|
||||||
|
#define SUPPORT_NRF 1
|
||||||
|
#else
|
||||||
|
#error Bad platform
|
||||||
|
#endif
|
||||||
|
|
||||||
#elif defined(GEX_PLAT_F303_DISCOVERY)
|
#elif defined(GEX_PLAT_F303_DISCOVERY)
|
||||||
|
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
|
||||||
|
#if defined(GEX_PLAT_F103_BLUEPILL)
|
||||||
|
// Platform STM32F103C8T6 Bluepill ($4 board from eBay)
|
||||||
|
|
||||||
|
// Units supported by the platform (known to work correctly)
|
||||||
|
|
||||||
|
// free all present resources
|
||||||
|
{
|
||||||
|
rsc_free_range(NULL, R_ADC1, R_ADC2);
|
||||||
|
rsc_free_range(NULL, R_I2C1, R_I2C2);
|
||||||
|
rsc_free_range(NULL, R_SPI1, R_SPI2);
|
||||||
|
rsc_free_range(NULL, R_TIM1, R_TIM4);
|
||||||
|
rsc_free_range(NULL, R_USART1, R_USART3);
|
||||||
|
rsc_free_range(NULL, R_PA0, R_PA15);
|
||||||
|
rsc_free_range(NULL, R_PB0, R_PB15);
|
||||||
|
rsc_free_range(NULL, R_PC13, R_PC15);
|
||||||
|
rsc_free_range(NULL, R_PD0, R_PD1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Claim resources not available due to board layout or internal usage
|
||||||
|
{
|
||||||
|
// HAL timebase
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_TIM1);
|
||||||
|
// HSE crystal
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PD0);
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PD1);
|
||||||
|
// SWD
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PA13);
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PA14);
|
||||||
|
// USB
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PA11);
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PA12);
|
||||||
|
// BOOT pin(s)
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PB2); // BOOT1
|
||||||
|
}
|
||||||
|
#elif defined(STM32F072xB)
|
||||||
|
// Platform STM32F073RBT
|
||||||
|
|
||||||
|
|
||||||
|
// Free all present resources
|
||||||
|
{
|
||||||
|
rsc_free(NULL, R_ADC1);
|
||||||
|
// rsc_free(NULL, R_CAN1);
|
||||||
|
// rsc_free_range(NULL, R_COMP1, R_COMP2);
|
||||||
|
rsc_free(NULL, R_DAC1);
|
||||||
|
// rsc_free(NULL, R_HDMI_CEC);
|
||||||
|
rsc_free(NULL, R_TSC);
|
||||||
|
rsc_free_range(NULL, R_I2C1, R_I2C2);
|
||||||
|
// rsc_free_range(NULL, R_I2S1, R_I2S2);
|
||||||
|
rsc_free_range(NULL, R_SPI1, R_SPI2);
|
||||||
|
rsc_free_range(NULL, R_TIM1, R_TIM3);
|
||||||
|
rsc_free_range(NULL, R_TIM6, R_TIM7);
|
||||||
|
rsc_free_range(NULL, R_TIM14, R_TIM17);
|
||||||
|
rsc_free_range(NULL, R_USART1, R_USART4);
|
||||||
|
rsc_free_range(NULL, R_DMA1_1, R_DMA1_7);
|
||||||
|
|
||||||
|
rsc_free_range(NULL, R_PA0, R_PA15);
|
||||||
|
rsc_free_range(NULL, R_PB0, R_PB15);
|
||||||
|
rsc_free_range(NULL, R_PC0, R_PC15);
|
||||||
|
rsc_free(NULL, R_PD2);
|
||||||
|
rsc_free_range(NULL, R_PF0, R_PF1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Claim resources not available due to board layout or internal usage
|
||||||
|
{
|
||||||
|
// HAL timebase
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_TIM17);
|
||||||
|
// HSE crystal
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PF0);
|
||||||
|
|
||||||
|
#if PLAT_FULL_XTAL
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PF1); // - not used in BYPASS mode
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// SWD
|
||||||
|
// rv |= rsc_claim(&UNIT_SYSTEM, R_PA13);
|
||||||
|
// rv |= rsc_claim(&UNIT_SYSTEM, R_PA14);
|
||||||
|
// USB
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PA11);
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PA12);
|
||||||
|
|
||||||
|
#if defined(GEX_PLAT_F072_ZERO)
|
||||||
|
// unconnected pins
|
||||||
|
rv |= rsc_claim_range(&UNIT_PLATFORM, R_PC0, R_PC1);
|
||||||
|
rv |= rsc_claim_range(&UNIT_PLATFORM, R_PC4, R_PC9);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#elif defined(GEX_PLAT_F303_DISCOVERY)
|
||||||
|
// Platform STM32F303VCT
|
||||||
|
|
||||||
|
// Additional GPIO ports
|
||||||
|
__HAL_RCC_GPIOF_CLK_ENABLE();
|
||||||
|
|
||||||
|
// Units supported by the platform (known to work correctly)
|
||||||
|
// ureg_add_type(&UNIT_XYZ);
|
||||||
|
|
||||||
|
// Free all present resources
|
||||||
|
{
|
||||||
|
rsc_free_range(NULL, R_ADC1, R_ADC4);
|
||||||
|
// rsc_free(NULL, R_CAN1);
|
||||||
|
// rsc_free_range(NULL, R_COMP1, R_COMP7);
|
||||||
|
// rsc_free(NULL, R_HDMI_CEC);
|
||||||
|
rsc_free(NULL, R_DAC1);
|
||||||
|
rsc_free_range(NULL, R_I2C1, R_I2C2);
|
||||||
|
rsc_free_range(NULL, R_I2S2, R_I2S3);
|
||||||
|
// rsc_free_range(NULL, R_OPAMP1, R_OPAMP4);
|
||||||
|
rsc_free_range(NULL, R_SPI1, R_SPI3);
|
||||||
|
rsc_free_range(NULL, R_TIM1, R_TIM4);
|
||||||
|
rsc_free_range(NULL, R_TIM6, R_TIM8);
|
||||||
|
rsc_free_range(NULL, R_TIM15, R_TIM17);
|
||||||
|
rsc_free(NULL, R_TSC);
|
||||||
|
rsc_free_range(NULL, R_USART1, R_USART5);
|
||||||
|
|
||||||
|
rsc_free_range(NULL, R_PA0, R_PA15);
|
||||||
|
rsc_free_range(NULL, R_PB0, R_PB15);
|
||||||
|
rsc_free_range(NULL, R_PC0, R_PC15);
|
||||||
|
rsc_free_range(NULL, R_PD0, R_PD15);
|
||||||
|
rsc_free_range(NULL, R_PE0, R_PE15);
|
||||||
|
|
||||||
|
rsc_free_range(NULL, R_PF0, R_PF2);
|
||||||
|
rsc_free(NULL, R_PF4);
|
||||||
|
rsc_free_range(NULL, R_PF9, R_PF10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Claim resources not available due to board layout or internal usage
|
||||||
|
{
|
||||||
|
// HAL timebase
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_TIM1);
|
||||||
|
// HSE crystal
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PF0);
|
||||||
|
//rv |= rsc_claim(&UNIT_SYSTEM, R_PF1); // - not used in BYPASS mode
|
||||||
|
// SWD
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PA13);
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PA14);
|
||||||
|
// USB
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PA11);
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PA12);
|
||||||
|
// BOOT pin(s)
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PB2); // BOOT1
|
||||||
|
}
|
||||||
|
#elif defined(GEX_PLAT_F407_DISCOVERY)
|
||||||
|
// Platform STM32F407VGT
|
||||||
|
|
||||||
|
// Additional GPIO ports
|
||||||
|
__HAL_RCC_GPIOF_CLK_ENABLE();
|
||||||
|
|
||||||
|
// Units supported by the platform (known to work correctly)
|
||||||
|
// ureg_add_type(&UNIT_XYZ);
|
||||||
|
|
||||||
|
// Free all present resources
|
||||||
|
{
|
||||||
|
rsc_free_range(NULL, R_ADC1, R_ADC3);
|
||||||
|
// rsc_free_range(NULL, R_CAN1, R_CAN2);
|
||||||
|
// rsc_free_range(NULL, R_COMP1, R_COMP7);
|
||||||
|
rsc_free(NULL, R_DAC1);
|
||||||
|
// rsc_free(NULL, R_DCMI);
|
||||||
|
// rsc_free(NULL, R_ETH);
|
||||||
|
// rsc_free(NULL, R_FSMC);
|
||||||
|
rsc_free_range(NULL, R_I2C1, R_I2C3);
|
||||||
|
rsc_free_range(NULL, R_I2S2, R_I2S3);
|
||||||
|
// rsc_free(NULL, R_SDIO);
|
||||||
|
rsc_free_range(NULL, R_SPI1, R_SPI3);
|
||||||
|
rsc_free_range(NULL, R_TIM1, R_TIM14);
|
||||||
|
rsc_free_range(NULL, R_USART1, R_USART3);
|
||||||
|
rsc_free(NULL, R_USART6);
|
||||||
|
|
||||||
|
rsc_free_range(NULL, R_PA0, R_PA15);
|
||||||
|
rsc_free_range(NULL, R_PB0, R_PB15);
|
||||||
|
rsc_free_range(NULL, R_PC0, R_PC15);
|
||||||
|
rsc_free_range(NULL, R_PD0, R_PD15);
|
||||||
|
rsc_free_range(NULL, R_PE0, R_PE15);
|
||||||
|
// also has 2 PH pins
|
||||||
|
|
||||||
|
// F407 appears to have fewer GPIOs than F303?
|
||||||
|
}
|
||||||
|
|
||||||
|
// Claim resources not available due to board layout or internal usage
|
||||||
|
{
|
||||||
|
// HAL timebase
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_TIM1);
|
||||||
|
// HSE crystal
|
||||||
|
// H0 and H1
|
||||||
|
// SWD
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PA13);
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PA14);
|
||||||
|
// USB
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PA11);
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PA12);
|
||||||
|
// BOOT pin(s)
|
||||||
|
rv |= rsc_claim(&UNIT_SYSTEM, R_PB2); // BOOT1
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error "BAD PLATFORM!"
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#ifndef GEX_PLAT_COMPAT_H
|
||||||
|
#define GEX_PLAT_COMPAT_H
|
||||||
|
|
||||||
|
// string identifying the GEX board
|
||||||
|
#define GEX_PLATFORM "Discovery-XYZ"
|
||||||
|
#define GEX_PLAT_XYZ 1 // only with the MCU name
|
||||||
|
|
||||||
|
// GEX_PLAT_XYZ_BOARD is defined in build.mk to identify particular board layout
|
||||||
|
|
||||||
|
#define PLAT_AHB_MHZ 72
|
||||||
|
#define PLAT_APB1_MHZ 36
|
||||||
|
|
||||||
|
#include ... // all useful from the peripheral library (HAL / LL)
|
||||||
|
|
||||||
|
// in bytes
|
||||||
|
#define FLASH_SIZE (128*1024)
|
||||||
|
// in bytes
|
||||||
|
#define SETTINGS_BLOCK_SIZE (2*1024)
|
||||||
|
// address where the settings block starts
|
||||||
|
#define SETTINGS_FLASH_ADDR (0x08000000 + FLASH_SIZE - SETTINGS_BLOCK_SIZE)
|
||||||
|
|
||||||
|
#define PORTS_COUNT 5 // number of available GPIO ports A,B,C,D,E,F...
|
||||||
|
#define LOCK_JUMPER_PORT 'A'
|
||||||
|
#define LOCK_JUMPER_PIN 2
|
||||||
|
|
||||||
|
#define STATUS_LED_PORT 'A'
|
||||||
|
#define STATUS_LED_PIN 15
|
||||||
|
|
||||||
|
// Feature flags:
|
||||||
|
#define PLAT_FLASHBANKS 0 // has the Banks field on the Flash config struct
|
||||||
|
#define PLAT_NO_FLOATING_INPUTS 0 // can't have digital inputs with no pull resistor
|
||||||
|
#define PLAT_USB_PHYCLOCK 0 // requires special config of phy clock for USB
|
||||||
|
#define PLAT_USB_OTGFS 0 // uses the USB OTG IP, needs different config code
|
||||||
|
#define PLAT_LOCK_BTN 1 // use a lock button instead of a lock jumper (push to toggle)
|
||||||
|
#define PLAT_LOCK_1CLOSED 1 // lock jumper is active (closed / button pressed) in logical 1
|
||||||
|
#define PLAT_NO_AFNUM 0 // legacy platform without numbered AF alternatives
|
||||||
|
#define PLAT_FULL_XTAL 1 // use two-wire xtal attachment
|
||||||
|
#define PLAT_USB_PU_CTL 1 // platform has USB pullup control
|
||||||
|
|
||||||
|
// FreeRTOS config
|
||||||
|
#define PLAT_FREERTOS_LOWEST_INTERRUPT_PRIORITY 3
|
||||||
|
#define PLAT_FREERTOS_MAX_SYSCALL_INTERRUPT_PRIORITY 1
|
||||||
|
#define PLAT_FREERTOS_PRIO_BITS 2
|
||||||
|
#define PLAT_FREERTOS_USE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
|
||||||
|
#endif //GEX_PLAT_COMPAT_H
|
||||||
Binary file not shown.
@@ -1,129 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "unit_1wire.h"
|
|
||||||
|
|
||||||
// 1WIRE master
|
|
||||||
#define OW_INTERNAL
|
|
||||||
#include "_ow_internal.h"
|
|
||||||
#include "_ow_commands.h"
|
|
||||||
#include "_ow_low_level.h"
|
|
||||||
|
|
||||||
/* Check presence of any devices on the bus */
|
|
||||||
error_t UU_1WIRE_CheckPresence(Unit *unit, bool *presence)
|
|
||||||
{
|
|
||||||
CHECK_TYPE(unit, &UNIT_1WIRE);
|
|
||||||
// reset
|
|
||||||
*presence = ow_reset(unit);
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read address of a lone device on the bus */
|
|
||||||
error_t UU_1WIRE_ReadAddress(Unit *unit, uint64_t *address)
|
|
||||||
{
|
|
||||||
CHECK_TYPE(unit, &UNIT_1WIRE);
|
|
||||||
*address = 0;
|
|
||||||
if (!ow_reset(unit)) return E_HW_TIMEOUT;
|
|
||||||
|
|
||||||
// command
|
|
||||||
ow_write_u8(unit, OW_ROM_READ);
|
|
||||||
|
|
||||||
// read the ROM code
|
|
||||||
*address = ow_read_u64(unit);
|
|
||||||
|
|
||||||
const uint8_t *addr_as_bytes = (void*)address;
|
|
||||||
if (0 != ow_checksum(addr_as_bytes, 8)) {
|
|
||||||
*address = 0;
|
|
||||||
return E_CHECKSUM_MISMATCH; // checksum mismatch
|
|
||||||
}
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write bytes to a device */
|
|
||||||
error_t UU_1WIRE_Write(Unit *unit, uint64_t address, const uint8_t *buff, uint32_t len)
|
|
||||||
{
|
|
||||||
CHECK_TYPE(unit, &UNIT_1WIRE);
|
|
||||||
if (!ow_reset(unit)) return E_HW_TIMEOUT;
|
|
||||||
|
|
||||||
// MATCH_ROM+addr, or SKIP_ROM
|
|
||||||
if (address != 0) {
|
|
||||||
ow_write_u8(unit, OW_ROM_MATCH);
|
|
||||||
ow_write_u64(unit, address);
|
|
||||||
} else {
|
|
||||||
ow_write_u8(unit, OW_ROM_SKIP);
|
|
||||||
}
|
|
||||||
|
|
||||||
// write the payload;
|
|
||||||
for (uint32_t i = 0; i < len; i++) {
|
|
||||||
ow_write_u8(unit, *buff++);
|
|
||||||
}
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write a request to a device and read a response */
|
|
||||||
error_t UU_1WIRE_Read(Unit *unit, uint64_t address,
|
|
||||||
const uint8_t *request_buff, uint32_t request_len,
|
|
||||||
uint8_t *response_buff, uint32_t response_len, bool check_crc)
|
|
||||||
{
|
|
||||||
CHECK_TYPE(unit, &UNIT_1WIRE);
|
|
||||||
if (!ow_reset(unit)) return E_HW_TIMEOUT;
|
|
||||||
|
|
||||||
uint8_t *rb = response_buff;
|
|
||||||
|
|
||||||
// MATCH_ROM+addr, or SKIP_ROM
|
|
||||||
if (address != 0) {
|
|
||||||
ow_write_u8(unit, OW_ROM_MATCH);
|
|
||||||
ow_write_u64(unit, address);
|
|
||||||
} else {
|
|
||||||
ow_write_u8(unit, OW_ROM_SKIP);
|
|
||||||
}
|
|
||||||
|
|
||||||
// write the payload;
|
|
||||||
for (uint32_t i = 0; i < request_len; i++) {
|
|
||||||
ow_write_u8(unit, *request_buff++);
|
|
||||||
}
|
|
||||||
|
|
||||||
// read the requested number of bytes
|
|
||||||
for (uint32_t i = 0; i < response_len; i++) {
|
|
||||||
*rb++ = ow_read_u8(unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (check_crc) {
|
|
||||||
if (0 != ow_checksum(response_buff, response_len)) {
|
|
||||||
return E_CHECKSUM_MISMATCH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Perform the search algorithm (start or continue) */
|
|
||||||
error_t UU_1WIRE_Search(Unit *unit, bool with_alarm, bool restart,
|
|
||||||
uint64_t *buffer, uint32_t capacity, uint32_t *real_count,
|
|
||||||
bool *have_more)
|
|
||||||
{
|
|
||||||
CHECK_TYPE(unit, &UNIT_1WIRE);
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
if (restart) {
|
|
||||||
uint8_t search_cmd = (uint8_t) (with_alarm ? OW_ROM_ALM_SEARCH : OW_ROM_SEARCH);
|
|
||||||
ow_search_init(unit, search_cmd, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
*real_count = ow_search_run(unit, (ow_romcode_t *) buffer, capacity);
|
|
||||||
|
|
||||||
// resolve the code
|
|
||||||
switch (priv->searchState.status) {
|
|
||||||
case OW_SEARCH_MORE:
|
|
||||||
*have_more = priv->searchState.status == OW_SEARCH_MORE;
|
|
||||||
|
|
||||||
case OW_SEARCH_DONE:
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
case OW_SEARCH_FAILED:
|
|
||||||
return priv->searchState.error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return E_INTERNAL_ERROR;
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/01/29.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef GEX_F072_OW_COMMANDS_H
|
|
||||||
#define GEX_F072_OW_COMMANDS_H
|
|
||||||
|
|
||||||
#ifndef OW_INTERNAL
|
|
||||||
#error bad include!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define OW_ROM_SEARCH 0xF0
|
|
||||||
#define OW_ROM_READ 0x33
|
|
||||||
#define OW_ROM_MATCH 0x55
|
|
||||||
#define OW_ROM_SKIP 0xCC
|
|
||||||
#define OW_ROM_ALM_SEARCH 0xEC
|
|
||||||
|
|
||||||
#endif //GEX_F072_OW_COMMANDS_H
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "unit_base.h"
|
|
||||||
|
|
||||||
#define OW_INTERNAL
|
|
||||||
#include "_ow_internal.h"
|
|
||||||
|
|
||||||
/** Allocate data structure and set defaults */
|
|
||||||
error_t OW_preInit(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
|
|
||||||
if (priv == NULL) return E_OUT_OF_MEM;
|
|
||||||
|
|
||||||
// the timer is not started until needed
|
|
||||||
priv->busyWaitTimer = xTimerCreate("1w_tim", // name
|
|
||||||
750, // interval (will be changed when starting it)
|
|
||||||
true, // periodic (we use this only for the polling variant, the one-shot will stop the timer in the CB)
|
|
||||||
unit, // user data
|
|
||||||
OW_TimerCb); // callback
|
|
||||||
|
|
||||||
if (priv->busyWaitTimer == NULL) return E_OUT_OF_MEM;
|
|
||||||
|
|
||||||
// some defaults
|
|
||||||
priv->pin_number = 0;
|
|
||||||
priv->port_name = 'A';
|
|
||||||
priv->parasitic = false;
|
|
||||||
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Finalize unit set-up */
|
|
||||||
error_t OW_init(Unit *unit)
|
|
||||||
{
|
|
||||||
bool suc = true;
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
// --- Parse config ---
|
|
||||||
priv->ll_pin = hw_pin2ll(priv->pin_number, &suc);
|
|
||||||
priv->port = hw_port2periph(priv->port_name, &suc);
|
|
||||||
Resource rsc = hw_pin2resource(priv->port_name, priv->pin_number, &suc);
|
|
||||||
if (!suc) return E_BAD_CONFIG;
|
|
||||||
|
|
||||||
// --- Claim resources ---
|
|
||||||
TRY(rsc_claim(unit, rsc));
|
|
||||||
|
|
||||||
// --- Init hardware ---
|
|
||||||
LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_OUTPUT);
|
|
||||||
LL_GPIO_SetPinOutputType(priv->port, priv->ll_pin, LL_GPIO_OUTPUT_PUSHPULL);
|
|
||||||
LL_GPIO_SetPinSpeed(priv->port, priv->ll_pin, LL_GPIO_SPEED_FREQ_HIGH);
|
|
||||||
LL_GPIO_SetPinPull(priv->port, priv->ll_pin, LL_GPIO_PULL_UP); // pull-up for OD state
|
|
||||||
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Tear down the unit */
|
|
||||||
void OW_deInit(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
// Release all resources
|
|
||||||
rsc_teardown(unit);
|
|
||||||
|
|
||||||
// Delete the software timer
|
|
||||||
assert_param(pdPASS == xTimerDelete(priv->busyWaitTimer, 1000));
|
|
||||||
|
|
||||||
// Free memory
|
|
||||||
free_ck(unit->data);
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/01/29.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef GEX_F072_OW_INTERNAL_H
|
|
||||||
#define GEX_F072_OW_INTERNAL_H
|
|
||||||
|
|
||||||
#ifndef OW_INTERNAL
|
|
||||||
#error bad include!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "_ow_search.h"
|
|
||||||
|
|
||||||
/** Private data structure */
|
|
||||||
struct priv {
|
|
||||||
char port_name;
|
|
||||||
uint8_t pin_number;
|
|
||||||
bool parasitic;
|
|
||||||
|
|
||||||
GPIO_TypeDef *port;
|
|
||||||
uint32_t ll_pin;
|
|
||||||
|
|
||||||
TimerHandle_t busyWaitTimer; // timer used to wait for ds1820 measurement completion
|
|
||||||
bool busy; // flag used when the timer is running
|
|
||||||
uint32_t busyStart;
|
|
||||||
TF_ID busyRequestId;
|
|
||||||
struct ow_search_state searchState;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Load from a binary buffer stored in Flash */
|
|
||||||
void OW_loadBinary(Unit *unit, PayloadParser *pp);
|
|
||||||
|
|
||||||
/** Write to a binary buffer for storing in Flash */
|
|
||||||
void OW_writeBinary(Unit *unit, PayloadBuilder *pb);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Parse a key-value pair from the INI file */
|
|
||||||
error_t OW_loadIni(Unit *unit, const char *key, const char *value);
|
|
||||||
|
|
||||||
/** Generate INI file section for the unit */
|
|
||||||
void OW_writeIni(Unit *unit, IniWriter *iw);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Allocate data structure and set defaults */
|
|
||||||
error_t OW_preInit(Unit *unit);
|
|
||||||
|
|
||||||
/** Finalize unit set-up */
|
|
||||||
error_t OW_init(Unit *unit);
|
|
||||||
|
|
||||||
/** Tear down the unit */
|
|
||||||
void OW_deInit(Unit *unit);
|
|
||||||
|
|
||||||
/** Callback for the FreeRTOS timer used to wait for device ready */
|
|
||||||
void OW_TimerCb(TimerHandle_t xTimer);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#endif //GEX_F072_OW_INTERNAL_H
|
|
||||||
@@ -1,223 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/01/29.
|
|
||||||
//
|
|
||||||
// 1-Wire unit low level functions
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
|
|
||||||
#define OW_INTERNAL
|
|
||||||
#include "_ow_internal.h"
|
|
||||||
#include "_ow_low_level.h"
|
|
||||||
|
|
||||||
static inline uint8_t crc8_bits(uint8_t data)
|
|
||||||
{
|
|
||||||
uint8_t crc = 0;
|
|
||||||
if(data & 1) crc ^= 0x5e;
|
|
||||||
if(data & 2) crc ^= 0xbc;
|
|
||||||
if(data & 4) crc ^= 0x61;
|
|
||||||
if(data & 8) crc ^= 0xc2;
|
|
||||||
if(data & 0x10) crc ^= 0x9d;
|
|
||||||
if(data & 0x20) crc ^= 0x23;
|
|
||||||
if(data & 0x40) crc ^= 0x46;
|
|
||||||
if(data & 0x80) crc ^= 0x8c;
|
|
||||||
return crc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t crc8_add(uint8_t cksum, uint8_t byte)
|
|
||||||
{
|
|
||||||
return crc8_bits(byte ^ cksum);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t ow_checksum(const uint8_t *buff, uint32_t len)
|
|
||||||
{
|
|
||||||
uint8_t cksum = 0;
|
|
||||||
for(uint32_t i = 0; i < len; i++) {
|
|
||||||
cksum = crc8_add(cksum, buff[i]);
|
|
||||||
}
|
|
||||||
return cksum;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------
|
|
||||||
|
|
||||||
static inline void ow_pull_high(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
LL_GPIO_SetOutputPin(priv->port, priv->ll_pin);
|
|
||||||
LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_OUTPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ow_pull_low(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
LL_GPIO_ResetOutputPin(priv->port, priv->ll_pin);
|
|
||||||
LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_OUTPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ow_release_line(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_INPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool ow_sample_line(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
return (bool) LL_GPIO_IsInputPinSet(priv->port, priv->ll_pin);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the 1-wire bus
|
|
||||||
*/
|
|
||||||
bool ow_reset(Unit *unit)
|
|
||||||
{
|
|
||||||
ow_pull_low(unit);
|
|
||||||
PTIM_MicroDelay(500);
|
|
||||||
|
|
||||||
bool presence;
|
|
||||||
vPortEnterCritical();
|
|
||||||
{
|
|
||||||
// Strong pull-up (for parasitive power)
|
|
||||||
ow_pull_high(unit);
|
|
||||||
PTIM_MicroDelay(2);
|
|
||||||
|
|
||||||
// switch to open-drain
|
|
||||||
ow_release_line(unit);
|
|
||||||
PTIM_MicroDelay(118);
|
|
||||||
|
|
||||||
presence = !ow_sample_line(unit);
|
|
||||||
}
|
|
||||||
vPortExitCritical();
|
|
||||||
|
|
||||||
PTIM_MicroDelay(130);
|
|
||||||
return presence;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a bit to the 1-wire bus
|
|
||||||
*/
|
|
||||||
void ow_write_bit(Unit *unit, bool bit)
|
|
||||||
{
|
|
||||||
vPortEnterCritical();
|
|
||||||
{
|
|
||||||
// start mark
|
|
||||||
ow_pull_low(unit);
|
|
||||||
PTIM_MicroDelay(2);
|
|
||||||
|
|
||||||
if (bit) ow_pull_high(unit);
|
|
||||||
PTIM_MicroDelay(70);
|
|
||||||
|
|
||||||
// Strong pull-up (for parasitive power)
|
|
||||||
ow_pull_high(unit);
|
|
||||||
}
|
|
||||||
vPortExitCritical();
|
|
||||||
|
|
||||||
PTIM_MicroDelay(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a bit from the 1-wire bus
|
|
||||||
*/
|
|
||||||
bool ow_read_bit(Unit *unit)
|
|
||||||
{
|
|
||||||
bool bit;
|
|
||||||
|
|
||||||
vPortEnterCritical();
|
|
||||||
{
|
|
||||||
// start mark
|
|
||||||
ow_pull_low(unit);
|
|
||||||
PTIM_MicroDelay(2);
|
|
||||||
|
|
||||||
ow_release_line(unit);
|
|
||||||
PTIM_MicroDelay(20);
|
|
||||||
|
|
||||||
bit = ow_sample_line(unit);
|
|
||||||
}
|
|
||||||
vPortExitCritical();
|
|
||||||
|
|
||||||
PTIM_MicroDelay(40);
|
|
||||||
|
|
||||||
return bit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a byte to the 1-wire bus
|
|
||||||
*/
|
|
||||||
void ow_write_u8(Unit *unit, uint8_t byte)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
ow_write_bit(unit, 0 != (byte & (1 << i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a halfword to the 1-wire bus
|
|
||||||
*/
|
|
||||||
void ow_write_u16(Unit *unit, uint16_t halfword)
|
|
||||||
{
|
|
||||||
ow_write_u8(unit, (uint8_t) (halfword & 0xFF));
|
|
||||||
ow_write_u8(unit, (uint8_t) ((halfword >> 8) & 0xFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a word to the 1-wire bus
|
|
||||||
*/
|
|
||||||
void ow_write_u32(Unit *unit, uint32_t word)
|
|
||||||
{
|
|
||||||
ow_write_u16(unit, (uint16_t) (word));
|
|
||||||
ow_write_u16(unit, (uint16_t) (word >> 16));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a doubleword to the 1-wire bus
|
|
||||||
*/
|
|
||||||
void ow_write_u64(Unit *unit, uint64_t dword)
|
|
||||||
{
|
|
||||||
ow_write_u32(unit, (uint32_t) (dword));
|
|
||||||
ow_write_u32(unit, (uint32_t) (dword >> 32));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a byte form the 1-wire bus
|
|
||||||
*/
|
|
||||||
uint8_t ow_read_u8(Unit *unit)
|
|
||||||
{
|
|
||||||
uint8_t buf = 0;
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
buf |= (1 & ow_read_bit(unit)) << i;
|
|
||||||
}
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a halfword form the 1-wire bus
|
|
||||||
*/
|
|
||||||
uint16_t ow_read_u16(Unit *unit)
|
|
||||||
{
|
|
||||||
uint16_t acu = 0;
|
|
||||||
acu |= ow_read_u8(unit);
|
|
||||||
acu |= ow_read_u8(unit) << 8;
|
|
||||||
return acu;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a word form the 1-wire bus
|
|
||||||
*/
|
|
||||||
uint32_t ow_read_u32(Unit *unit)
|
|
||||||
{
|
|
||||||
uint32_t acu = 0;
|
|
||||||
acu |= ow_read_u16(unit);
|
|
||||||
acu |= (uint32_t)ow_read_u16(unit) << 16;
|
|
||||||
return acu;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a doubleword form the 1-wire bus
|
|
||||||
*/
|
|
||||||
uint64_t ow_read_u64(Unit *unit)
|
|
||||||
{
|
|
||||||
uint64_t acu = 0;
|
|
||||||
acu |= ow_read_u32(unit);
|
|
||||||
acu |= (uint64_t)ow_read_u32(unit) << 32;
|
|
||||||
return acu;
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/01.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef GEX_F072_OW_LOW_LEVEL_H
|
|
||||||
#define GEX_F072_OW_LOW_LEVEL_H
|
|
||||||
|
|
||||||
#ifndef OW_INTERNAL
|
|
||||||
#error bad include!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "unit_base.h"
|
|
||||||
#include "_ow_low_level.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compute a 1-wire type checksum.
|
|
||||||
* If the buffer includes the checksum, the result should be 0.
|
|
||||||
*
|
|
||||||
* (this function may be used externally, or you can delete the implementation
|
|
||||||
* from the c file if another implementation is already available)
|
|
||||||
*
|
|
||||||
* @param[in] buf - buffer of bytes to verify
|
|
||||||
* @param[in] len - buffer length
|
|
||||||
* @return checksum
|
|
||||||
*/
|
|
||||||
uint8_t ow_checksum(const uint8_t *buf, uint32_t len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the 1-wire bus
|
|
||||||
*/
|
|
||||||
bool ow_reset(Unit *unit);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a bit to the 1-wire bus
|
|
||||||
*/
|
|
||||||
void ow_write_bit(Unit *unit, bool bit);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a bit from the 1-wire bus
|
|
||||||
*/
|
|
||||||
bool ow_read_bit(Unit *unit);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a byte to the 1-wire bus
|
|
||||||
*/
|
|
||||||
void ow_write_u8(Unit *unit, uint8_t byte);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a halfword to the 1-wire bus
|
|
||||||
*/
|
|
||||||
void ow_write_u16(Unit *unit, uint16_t halfword);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a word to the 1-wire bus
|
|
||||||
*/
|
|
||||||
void ow_write_u32(Unit *unit, uint32_t word);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a doubleword to the 1-wire bus
|
|
||||||
*/
|
|
||||||
void ow_write_u64(Unit *unit, uint64_t dword);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a byte form the 1-wire bus
|
|
||||||
*/
|
|
||||||
uint8_t ow_read_u8(Unit *unit);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a halfword form the 1-wire bus
|
|
||||||
*/
|
|
||||||
uint16_t ow_read_u16(Unit *unit);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a word form the 1-wire bus
|
|
||||||
*/
|
|
||||||
uint32_t ow_read_u32(Unit *unit);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a doubleword form the 1-wire bus
|
|
||||||
*/
|
|
||||||
uint64_t ow_read_u64(Unit *unit);
|
|
||||||
|
|
||||||
#endif //GEX_F072_OW_LOW_LEVEL_H
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/01.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "unit_1wire.h"
|
|
||||||
|
|
||||||
#define OW_INTERNAL
|
|
||||||
#include "_ow_search.h"
|
|
||||||
#include "_ow_internal.h"
|
|
||||||
#include "_ow_low_level.h"
|
|
||||||
#include "_ow_commands.h"
|
|
||||||
|
|
||||||
void ow_search_init(Unit *unit, uint8_t command, bool test_checksums)
|
|
||||||
{
|
|
||||||
if (unit->driver != &UNIT_1WIRE)
|
|
||||||
trap("Wrong unit type - %s", unit->driver->name);
|
|
||||||
|
|
||||||
assert_param(command == OW_ROM_SEARCH || command == OW_ROM_ALM_SEARCH);
|
|
||||||
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
struct ow_search_state *state = &priv->searchState;
|
|
||||||
|
|
||||||
state->prev_last_fork = 64;
|
|
||||||
memset(state->prev_code, 0, 8);
|
|
||||||
state->status = OW_SEARCH_MORE;
|
|
||||||
state->error = E_SUCCESS;
|
|
||||||
state->command = command;
|
|
||||||
state->first = true;
|
|
||||||
state->test_checksums = test_checksums;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t ow_search_run(Unit *unit, ow_romcode_t *codes, uint32_t capacity)
|
|
||||||
{
|
|
||||||
if (unit->driver != &UNIT_1WIRE)
|
|
||||||
trap("Wrong unit type - %s", unit->driver->name);
|
|
||||||
|
|
||||||
assert_param(codes);
|
|
||||||
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
struct ow_search_state *state = &priv->searchState;
|
|
||||||
|
|
||||||
if (state->status != OW_SEARCH_MORE) return 0;
|
|
||||||
|
|
||||||
uint32_t found_devices = 0;
|
|
||||||
|
|
||||||
while (found_devices < capacity) {
|
|
||||||
uint8_t index = 0;
|
|
||||||
ow_romcode_t code = {};
|
|
||||||
int8_t last_fork = -1;
|
|
||||||
|
|
||||||
// Start a new transaction. Devices respond to reset
|
|
||||||
if (!ow_reset(unit)) {
|
|
||||||
state->status = OW_SEARCH_FAILED;
|
|
||||||
state->error = E_HW_TIMEOUT;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
// Send the search command (SEARCH_ROM, SEARCH_ALARM)
|
|
||||||
ow_write_u8(unit, state->command);
|
|
||||||
|
|
||||||
uint8_t *code_byte = &code[0];
|
|
||||||
|
|
||||||
bool p, n;
|
|
||||||
while (index != 64) {
|
|
||||||
// Read a bit and its complement
|
|
||||||
p = ow_read_bit(unit);
|
|
||||||
n = ow_read_bit(unit);
|
|
||||||
|
|
||||||
if (!p && !n) {
|
|
||||||
// A fork: there are devices on the bus with different bit value
|
|
||||||
// (the bus is open-drain, in both cases one device pulls it low)
|
|
||||||
if ((found_devices > 0 || !state->first) && index < state->prev_last_fork) {
|
|
||||||
// earlier than the last fork, take the same turn as before
|
|
||||||
p = ow_code_getbit(state->prev_code, index);
|
|
||||||
if (!p) last_fork = index; // remember for future runs, 1 not explored yet
|
|
||||||
}
|
|
||||||
else if (index == state->prev_last_fork) {
|
|
||||||
p = 1; // both forks are now exhausted
|
|
||||||
}
|
|
||||||
else { // a new fork
|
|
||||||
last_fork = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (p && n) {
|
|
||||||
// No devices left connected - this doesn't normally happen
|
|
||||||
state->status = OW_SEARCH_FAILED;
|
|
||||||
state->error = E_BUS_FAULT;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All devices have a matching bit here, or it was resolved in a fork
|
|
||||||
if (p) *code_byte |= (1 << (index & 7));
|
|
||||||
ow_write_bit(unit, p);
|
|
||||||
|
|
||||||
index++;
|
|
||||||
if((index & 7) == 0) {
|
|
||||||
code_byte++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(state->prev_code, code, 8);
|
|
||||||
|
|
||||||
if (state->test_checksums) {
|
|
||||||
if (0 != ow_checksum(code, 8)) {
|
|
||||||
state->status = OW_SEARCH_FAILED;
|
|
||||||
state->error = E_CHECKSUM_MISMATCH;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record a found address
|
|
||||||
memcpy(codes[found_devices], code, 8);
|
|
||||||
found_devices++;
|
|
||||||
|
|
||||||
// Stop condition
|
|
||||||
if (last_fork == -1) {
|
|
||||||
state->status = OW_SEARCH_DONE;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->prev_last_fork = last_fork;
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
state->first = false;
|
|
||||||
return found_devices;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/01.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef GEX_F072_OW_SEARCH_H
|
|
||||||
#define GEX_F072_OW_SEARCH_H
|
|
||||||
|
|
||||||
#ifndef OW_INTERNAL
|
|
||||||
#error bad include!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include "unit_base.h"
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Data type holding a romcode
|
|
||||||
*/
|
|
||||||
typedef uint8_t ow_romcode_t[8];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a single bit from a romcode
|
|
||||||
*/
|
|
||||||
#define ow_code_getbit(code, index) (bool)((code)[(index) >> 3] & (1 << ((index) & 7)))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert to unsigned 64-bit integer
|
|
||||||
* (works only on little-endian systems - eg. OK on x86/x86_64, not on PowerPC)
|
|
||||||
*/
|
|
||||||
#define ow_romcode_to_u64(code) (*((uint64_t *) (void *)(code)))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* States of the search algorithm
|
|
||||||
*/
|
|
||||||
enum ow_search_result {
|
|
||||||
OW_SEARCH_DONE = 0,
|
|
||||||
OW_SEARCH_MORE = 1,
|
|
||||||
OW_SEARCH_FAILED = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal state of the search algorithm.
|
|
||||||
* Check status to see if more remain to be read or an error occurred.
|
|
||||||
*/
|
|
||||||
struct ow_search_state {
|
|
||||||
int8_t prev_last_fork;
|
|
||||||
ow_romcode_t prev_code;
|
|
||||||
uint8_t command;
|
|
||||||
enum ow_search_result status;
|
|
||||||
bool first;
|
|
||||||
bool test_checksums;
|
|
||||||
error_t error;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Init the search algorithm state structure
|
|
||||||
*
|
|
||||||
* @param[out] state - inited struct
|
|
||||||
* @param[in] command - command to send for requesting the search (e.g. SEARCH_ROM)
|
|
||||||
* @param[in] test_checksums - verify checksums of all read romcodes
|
|
||||||
*/
|
|
||||||
void ow_search_init(Unit *unit, uint8_t command, bool test_checksums);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a search of the 1-wire bus, with a state struct pre-inited
|
|
||||||
* using ow_search_init().
|
|
||||||
*
|
|
||||||
* Romcodes are stored in the provided array in a numerically ascending order.
|
|
||||||
*
|
|
||||||
* This function may be called repeatedly to retrieve more addresses than could fit
|
|
||||||
* in the address buffer.
|
|
||||||
*
|
|
||||||
* @param[in,out] state - search state, used for multiple calls with limited buffer size
|
|
||||||
* @param[out] codes - buffer for found romcodes
|
|
||||||
* @param[in] capacity - buffer capacity
|
|
||||||
* @return number of romcodes found. Search status is stored in `state->status`,
|
|
||||||
* possible error code in `status->error`
|
|
||||||
*/
|
|
||||||
uint32_t ow_search_run(Unit *unit, ow_romcode_t *codes, uint32_t capacity);
|
|
||||||
|
|
||||||
#endif //GEX_F072_OW_SEARCH_H
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "unit_base.h"
|
|
||||||
|
|
||||||
#define OW_INTERNAL
|
|
||||||
#include "_ow_internal.h"
|
|
||||||
|
|
||||||
/** Load from a binary buffer stored in Flash */
|
|
||||||
void OW_loadBinary(Unit *unit, PayloadParser *pp)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
uint8_t version = pp_u8(pp);
|
|
||||||
(void)version;
|
|
||||||
|
|
||||||
priv->port_name = pp_char(pp);
|
|
||||||
priv->pin_number = pp_u8(pp);
|
|
||||||
if (version >= 1) {
|
|
||||||
priv->parasitic = pp_bool(pp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Write to a binary buffer for storing in Flash */
|
|
||||||
void OW_writeBinary(Unit *unit, PayloadBuilder *pb)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
pb_u8(pb, 1); // version
|
|
||||||
|
|
||||||
pb_char(pb, priv->port_name);
|
|
||||||
pb_u8(pb, priv->pin_number);
|
|
||||||
pb_bool(pb, priv->parasitic);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Parse a key-value pair from the INI file */
|
|
||||||
error_t OW_loadIni(Unit *unit, const char *key, const char *value)
|
|
||||||
{
|
|
||||||
bool suc = true;
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
if (streq(key, "pin")) {
|
|
||||||
suc = parse_pin(value, &priv->port_name, &priv->pin_number);
|
|
||||||
}
|
|
||||||
else if (streq(key, "parasitic")) {
|
|
||||||
priv->parasitic = str_parse_yn(value, &suc);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return E_BAD_KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!suc) return E_BAD_VALUE;
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Generate INI file section for the unit */
|
|
||||||
void OW_writeIni(Unit *unit, IniWriter *iw)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
iw_comment(iw, "Data pin");
|
|
||||||
iw_entry(iw, "pin", "%c%d", priv->port_name, priv->pin_number);
|
|
||||||
|
|
||||||
iw_comment(iw, "Parasitic (bus-powered) mode");
|
|
||||||
iw_entry(iw, "parasitic", str_yn(priv->parasitic));
|
|
||||||
}
|
|
||||||
@@ -1,245 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/01/29.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "comm/messages.h"
|
|
||||||
#include "unit_base.h"
|
|
||||||
#include "unit_1wire.h"
|
|
||||||
|
|
||||||
// 1WIRE master
|
|
||||||
#define OW_INTERNAL
|
|
||||||
#include "_ow_internal.h"
|
|
||||||
#include "_ow_low_level.h"
|
|
||||||
|
|
||||||
/** Callback for sending a poll_ready success / failure report */
|
|
||||||
static void OW_TimerRespCb(Job *job)
|
|
||||||
{
|
|
||||||
Unit *unit = job->unit;
|
|
||||||
assert_param(unit);
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
bool success = (bool) job->data1;
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
com_respond_ok(priv->busyRequestId);
|
|
||||||
} else {
|
|
||||||
com_respond_error(priv->busyRequestId, E_HW_TIMEOUT);
|
|
||||||
}
|
|
||||||
priv->busy = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1-Wire timer callback, used for the 'wait_ready' function.
|
|
||||||
*
|
|
||||||
* - In parasitic mode, this is a simple 750ms wait, after which a SUCCESS response is sent.
|
|
||||||
* - In 3-wire mode, the callback is fired periodically and performs a Read operation on the bus.
|
|
||||||
* The unit responds with 0 while the operation is ongoing. On receiving 1 a SUCCESS response is sent.
|
|
||||||
* The polling is abandoned after a timeout, sending a TIMEOUT response.
|
|
||||||
*
|
|
||||||
* @param xTimer
|
|
||||||
*/
|
|
||||||
void OW_TimerCb(TimerHandle_t xTimer)
|
|
||||||
{
|
|
||||||
Unit *unit = pvTimerGetTimerID(xTimer);
|
|
||||||
assert_param(unit);
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
assert_param(priv->busy);
|
|
||||||
|
|
||||||
if (priv->parasitic) {
|
|
||||||
// this is the end of the 750ms measurement time
|
|
||||||
goto halt_ok;
|
|
||||||
} else {
|
|
||||||
bool ready = ow_read_bit(unit);
|
|
||||||
if (ready) {
|
|
||||||
goto halt_ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t time = PTIM_GetTime();
|
|
||||||
if (time - priv->busyStart > 1000) {
|
|
||||||
xTimerStop(xTimer, 100);
|
|
||||||
|
|
||||||
Job j = {
|
|
||||||
.unit = unit,
|
|
||||||
.data1 = 0, // failure
|
|
||||||
.cb = OW_TimerRespCb,
|
|
||||||
};
|
|
||||||
scheduleJob(&j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
halt_ok:
|
|
||||||
xTimerStop(xTimer, 100);
|
|
||||||
|
|
||||||
Job j = {
|
|
||||||
.unit = unit,
|
|
||||||
.data1 = 1, // success
|
|
||||||
.cb = OW_TimerRespCb,
|
|
||||||
};
|
|
||||||
scheduleJob(&j);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
enum PinCmd_ {
|
|
||||||
CMD_CHECK_PRESENCE = 0, // simply tests that any devices are attached
|
|
||||||
CMD_SEARCH_ADDR = 1, // perform a scan of the bus, retrieving all found device ROMs
|
|
||||||
CMD_SEARCH_ALARM = 2, // like normal scan, but retrieve only devices with alarm
|
|
||||||
CMD_SEARCH_CONTINUE = 3, // continue the previously started scan, retrieving more devices
|
|
||||||
CMD_READ_ADDR = 4, // read the ROM code from a single device (for single-device bus)
|
|
||||||
|
|
||||||
CMD_WRITE = 10, // write multiple bytes using the SKIP_ROM command
|
|
||||||
CMD_READ = 11, // write multiple bytes using a ROM address
|
|
||||||
|
|
||||||
CMD_POLL_FOR_1 = 20,
|
|
||||||
|
|
||||||
CMD_TEST = 100,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/** Handle a request message */
|
|
||||||
static error_t OW_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
bool presence;
|
|
||||||
uint64_t addr;
|
|
||||||
uint32_t remain;
|
|
||||||
const uint8_t *tail;
|
|
||||||
|
|
||||||
if (priv->busy) return E_BUSY;
|
|
||||||
|
|
||||||
bool with_alarm = false;
|
|
||||||
bool search_reset = false;
|
|
||||||
|
|
||||||
switch (command) {
|
|
||||||
/**
|
|
||||||
* This is the delay function for DS1820 measurements.
|
|
||||||
*
|
|
||||||
* Parasitic: Returns success after the required 750ms
|
|
||||||
* Non-parasitic: Returns SUCCESS after device responds '1', HW_TIMEOUT after 1s
|
|
||||||
*/
|
|
||||||
case CMD_POLL_FOR_1:
|
|
||||||
// This can't be exposed via the UU API, due to being async
|
|
||||||
if (priv->parasitic) {
|
|
||||||
assert_param(pdPASS == xTimerChangePeriod(priv->busyWaitTimer, 750, 100));
|
|
||||||
} else {
|
|
||||||
// every 10 ticks
|
|
||||||
assert_param(pdPASS == xTimerChangePeriod(priv->busyWaitTimer, 10, 100));
|
|
||||||
}
|
|
||||||
assert_param(pdPASS == xTimerStart(priv->busyWaitTimer, 100));
|
|
||||||
priv->busy = true;
|
|
||||||
priv->busyStart = PTIM_GetTime();
|
|
||||||
priv->busyRequestId = frame_id;
|
|
||||||
return E_SUCCESS; // We will respond when the timer expires
|
|
||||||
|
|
||||||
/** Search devices with alarm. No payload, restarts the search. */
|
|
||||||
case CMD_SEARCH_ALARM:
|
|
||||||
with_alarm = true;
|
|
||||||
// fall-through
|
|
||||||
/** Search all devices. No payload, restarts the search. */
|
|
||||||
case CMD_SEARCH_ADDR:
|
|
||||||
search_reset = true;
|
|
||||||
// fall-through
|
|
||||||
/** Continue a previously begun search. */
|
|
||||||
case CMD_SEARCH_CONTINUE:;
|
|
||||||
uint32_t found_count = 0;
|
|
||||||
bool have_more = false;
|
|
||||||
if (!search_reset && priv->searchState.status != OW_SEARCH_MORE) {
|
|
||||||
dbg("Search not ongoing!");
|
|
||||||
return E_PROTOCOL_BREACH;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRY(UU_1WIRE_Search(unit, with_alarm, search_reset,
|
|
||||||
(void *) unit_tmp512, UNIT_TMP_LEN/8, &found_count,
|
|
||||||
&have_more));
|
|
||||||
|
|
||||||
// use multipart to avoid allocating extra buffer
|
|
||||||
uint8_t status_code = (uint8_t) have_more;
|
|
||||||
TF_Msg msg = {
|
|
||||||
.frame_id = frame_id,
|
|
||||||
.type = MSG_SUCCESS,
|
|
||||||
.len = (TF_LEN) (found_count * 8 + 1),
|
|
||||||
};
|
|
||||||
TF_Respond_Multipart(comm, &msg);
|
|
||||||
TF_Multipart_Payload(comm, &status_code, 1);
|
|
||||||
// the codes are back-to-back stored inside the buffer, we send it directly
|
|
||||||
// (it's already little-endian, as if built by PayloadBuilder)
|
|
||||||
TF_Multipart_Payload(comm, (uint8_t *) unit_tmp512, found_count * 8);
|
|
||||||
TF_Multipart_Close(comm);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/** Simply check presence of any devices on the bus. Responds with SUCCESS or HW_TIMEOUT */
|
|
||||||
case CMD_CHECK_PRESENCE:
|
|
||||||
TRY(UU_1WIRE_CheckPresence(unit, &presence));
|
|
||||||
|
|
||||||
com_respond_u8(frame_id, (uint8_t) presence);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/** Read address of the single device on the bus - returns u64 */
|
|
||||||
case CMD_READ_ADDR:
|
|
||||||
TRY(UU_1WIRE_ReadAddress(unit, &addr));
|
|
||||||
|
|
||||||
// build response
|
|
||||||
PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL);
|
|
||||||
pb_u64(&pb, addr);
|
|
||||||
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write payload to the bus, no confirmation (unless requested).
|
|
||||||
*
|
|
||||||
* Payload:
|
|
||||||
* addr:u64, rest:write_data
|
|
||||||
* if addr is 0, use SKIP_ROM
|
|
||||||
*/
|
|
||||||
case CMD_WRITE:
|
|
||||||
addr = pp_u64(pp);
|
|
||||||
tail = pp_tail(pp, &remain);
|
|
||||||
TRY(UU_1WIRE_Write(unit, addr, tail, remain));
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write and read.
|
|
||||||
*
|
|
||||||
* Payload:
|
|
||||||
* addr:u64, read_len:u16, rest:write_data
|
|
||||||
* if addr is 0, use SKIP_ROM
|
|
||||||
*/
|
|
||||||
case CMD_READ:
|
|
||||||
addr = pp_u64(pp);
|
|
||||||
uint16_t rcount = pp_u16(pp);
|
|
||||||
bool test_crc = pp_bool(pp);
|
|
||||||
tail = pp_tail(pp, &remain);
|
|
||||||
|
|
||||||
TRY(UU_1WIRE_Read(unit, addr,
|
|
||||||
tail, remain,
|
|
||||||
(uint8_t *) unit_tmp512, rcount,
|
|
||||||
test_crc));
|
|
||||||
|
|
||||||
// build response
|
|
||||||
com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, rcount);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return E_UNKNOWN_COMMAND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Unit template */
|
|
||||||
const UnitDriver UNIT_1WIRE = {
|
|
||||||
.name = "1WIRE",
|
|
||||||
.description = "1-Wire master",
|
|
||||||
// Settings
|
|
||||||
.preInit = OW_preInit,
|
|
||||||
.cfgLoadBinary = OW_loadBinary,
|
|
||||||
.cfgWriteBinary = OW_writeBinary,
|
|
||||||
.cfgLoadIni = OW_loadIni,
|
|
||||||
.cfgWriteIni = OW_writeIni,
|
|
||||||
// Init
|
|
||||||
.init = OW_init,
|
|
||||||
.deInit = OW_deInit,
|
|
||||||
// Function
|
|
||||||
.handleRequest = OW_handleRequest,
|
|
||||||
};
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/01/02.
|
|
||||||
//
|
|
||||||
// Dallas 1-Wire master unit
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef GEX_F072_UNIT_1WIRE_H
|
|
||||||
#define GEX_F072_UNIT_1WIRE_H
|
|
||||||
|
|
||||||
#include "unit.h"
|
|
||||||
|
|
||||||
extern const UnitDriver UNIT_1WIRE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if there are any units present on the bus
|
|
||||||
*
|
|
||||||
* @param[in,out] unit
|
|
||||||
* @param[out] presence - any devices present
|
|
||||||
* @return success
|
|
||||||
*/
|
|
||||||
error_t UU_1WIRE_CheckPresence(Unit *unit, bool *presence);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a device's address (use only with a single device attached)
|
|
||||||
*
|
|
||||||
* @param[in,out] unit
|
|
||||||
* @param[out] address - the device's address, 0 on error or CRC mismatch
|
|
||||||
* @return success
|
|
||||||
*/
|
|
||||||
error_t UU_1WIRE_ReadAddress(Unit *unit, uint64_t *address);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write bytes to a device / devices
|
|
||||||
*
|
|
||||||
* @param[in,out] unit
|
|
||||||
* @param[in] address - device address, 0 to skip match (single device or broadcast)
|
|
||||||
* @param[in] buff - bytes to write
|
|
||||||
* @param[in] len - buffer length
|
|
||||||
* @return success
|
|
||||||
*/
|
|
||||||
error_t UU_1WIRE_Write(Unit *unit, uint64_t address, const uint8_t *buff, uint32_t len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read bytes from a device / devices, first writing a query
|
|
||||||
*
|
|
||||||
* @param[in,out] unit
|
|
||||||
* @param[in] address - device address, 0 to skip match (single device ONLY!)
|
|
||||||
* @param[in] request_buff - bytes to write before reading a response
|
|
||||||
* @param[in] request_len - number of bytes to write
|
|
||||||
* @param[out] response_buff - buffer for storing the read response
|
|
||||||
* @param[in] response_len - number of bytes to read
|
|
||||||
* @param[in] check_crc - verify CRC
|
|
||||||
* @return success
|
|
||||||
*/
|
|
||||||
error_t UU_1WIRE_Read(Unit *unit, uint64_t address,
|
|
||||||
const uint8_t *request_buff, uint32_t request_len,
|
|
||||||
uint8_t *response_buff, uint32_t response_len, bool check_crc);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a ROM search operation.
|
|
||||||
* The algorithm is on a depth-first search without backtracking,
|
|
||||||
* taking advantage of the open-drain topology.
|
|
||||||
*
|
|
||||||
* This function either starts the search, or continues it.
|
|
||||||
*
|
|
||||||
* @param[in,out] unit
|
|
||||||
* @param[in] with_alarm - true to match only devices in alarm state
|
|
||||||
* @param[in] restart - true to restart the search (search from the lowest address)
|
|
||||||
* @param[out] buffer - buffer for storing found addresses
|
|
||||||
* @param[in] capacity - buffer capacity in address entries (8 bytes)
|
|
||||||
* @param[out] real_count - real number of found addresses (for which the CRC matched)
|
|
||||||
* @param[out] have_more - flag indicating there are more devices to be found
|
|
||||||
* @return success
|
|
||||||
*/
|
|
||||||
error_t UU_1WIRE_Search(Unit *unit, bool with_alarm, bool restart,
|
|
||||||
uint64_t *buffer, uint32_t capacity, uint32_t *real_count,
|
|
||||||
bool *have_more);
|
|
||||||
|
|
||||||
#endif //GEX_F072_UNIT_1WIRE_H
|
|
||||||
@@ -1,653 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/04.
|
|
||||||
//
|
|
||||||
// The core functionality of the ADC unit is defined here.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "unit_base.h"
|
|
||||||
#include "unit_adc.h"
|
|
||||||
|
|
||||||
#define ADC_INTERNAL
|
|
||||||
#include "_adc_internal.h"
|
|
||||||
|
|
||||||
#define DMA_POS(priv) ((priv)->buf_itemcount - (priv)->DMA_CHx->CNDTR)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Async job to send a chunk of the DMA buffer to PC.
|
|
||||||
* This can't be done directly because the interrupt couldn't wait for the TinyFrame mutex.
|
|
||||||
*
|
|
||||||
* unit - unit
|
|
||||||
* data1 - start index
|
|
||||||
* data2 - number of samples to send
|
|
||||||
* data3 - bit flags: 0x80 if this is the last sample and we should close
|
|
||||||
* 0x01 if this was the TC interrupt (otherwise it's HT)
|
|
||||||
*/
|
|
||||||
static void UADC_JobSendBlockChunk(Job *job)
|
|
||||||
{
|
|
||||||
Unit *unit = job->unit;
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
const uint32_t start = job->data1;
|
|
||||||
const uint32_t count = job->data2;
|
|
||||||
const bool close = (bool) (job->data3 & 0x80);
|
|
||||||
const bool tc = (bool) (job->data3 & 0x01);
|
|
||||||
|
|
||||||
const TF_TYPE type = close ? EVT_CAPT_DONE : EVT_CAPT_MORE;
|
|
||||||
|
|
||||||
TF_Msg msg = {
|
|
||||||
.frame_id = priv->stream_frame_id,
|
|
||||||
.len = (TF_LEN) (1 /*seq*/ + count * sizeof(uint16_t)),
|
|
||||||
.type = type,
|
|
||||||
};
|
|
||||||
TF_Respond_Multipart(comm, &msg);
|
|
||||||
TF_Multipart_Payload(comm, &priv->stream_serial, 1);
|
|
||||||
TF_Multipart_Payload(comm, (uint8_t *) (priv->dma_buffer + start), count * sizeof(uint16_t));
|
|
||||||
TF_Multipart_Close(comm);
|
|
||||||
|
|
||||||
// Clear the "busy" flags - those are checked in the DMA ISR to detect overrun
|
|
||||||
if (tc) priv->tc_pending = false;
|
|
||||||
else priv->ht_pending = false;
|
|
||||||
|
|
||||||
priv->stream_serial++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Async job to send the trigger header.
|
|
||||||
* The header includes info about the trigger + the pre-trigger buffer.
|
|
||||||
*
|
|
||||||
* data1 - index in the DMA buffer at which the captured data willl start
|
|
||||||
* data2 - edge type - 1 rise, 2 fall, 3 forced
|
|
||||||
* timestamp - event stamp
|
|
||||||
* unit - unit
|
|
||||||
*/
|
|
||||||
static void UADC_JobSendTriggerCaptureHeader(Job *job)
|
|
||||||
{
|
|
||||||
Unit *unit = job->unit;
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
EventReport er = {
|
|
||||||
.unit = unit,
|
|
||||||
.type = EVT_CAPT_START,
|
|
||||||
.timestamp = job->timestamp,
|
|
||||||
.length = (priv->pretrig_len + 1) * // see below why +1
|
|
||||||
priv->nb_channels *
|
|
||||||
sizeof(uint16_t) +
|
|
||||||
4 /*pretrig len*/ +
|
|
||||||
1 /*edge*/ +
|
|
||||||
1 /* seq */
|
|
||||||
};
|
|
||||||
|
|
||||||
uint32_t index_trigd = job->data1;
|
|
||||||
uint8_t edge = (uint8_t) job->data2;
|
|
||||||
|
|
||||||
EventReport_Start(&er);
|
|
||||||
priv->stream_frame_id = er.sent_msg_id;
|
|
||||||
{
|
|
||||||
// preamble
|
|
||||||
uint8_t buf[4];
|
|
||||||
PayloadBuilder pb = pb_start(buf, 4, NULL);
|
|
||||||
pb_u32(&pb, priv->pretrig_len);
|
|
||||||
pb_u8(&pb, edge);
|
|
||||||
pb_u8(&pb, priv->stream_serial++); // This is the serial counter for the first chunk
|
|
||||||
// (containing the pre-trigger, or empty if no pretrig configured)
|
|
||||||
EventReport_PB(&pb);
|
|
||||||
|
|
||||||
if (priv->pretrig_len > 0) {
|
|
||||||
// pretrig
|
|
||||||
|
|
||||||
// +1 because we want pretrig 0 to exactly start with the triggering sample
|
|
||||||
uint32_t pretrig_remain = (priv->pretrig_len + 1) * priv->nb_channels;
|
|
||||||
|
|
||||||
assert_param(index_trigd <= priv->buf_itemcount);
|
|
||||||
|
|
||||||
// this is one past the last entry of the triggering capture group
|
|
||||||
if (pretrig_remain > index_trigd) {
|
|
||||||
// used items in the wrap-around part of the buffer
|
|
||||||
uint32_t items_from_end = pretrig_remain - index_trigd;
|
|
||||||
assert_param(priv->buf_itemcount - items_from_end >= index_trigd);
|
|
||||||
|
|
||||||
EventReport_Data((uint8_t *) &priv->dma_buffer[priv->buf_itemcount - items_from_end],
|
|
||||||
items_from_end * sizeof(uint16_t));
|
|
||||||
|
|
||||||
assert_param(items_from_end <= pretrig_remain);
|
|
||||||
pretrig_remain -= items_from_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_param(pretrig_remain <= index_trigd);
|
|
||||||
EventReport_Data((uint8_t *) &priv->dma_buffer[index_trigd - pretrig_remain],
|
|
||||||
pretrig_remain * sizeof(uint16_t));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EventReport_End();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Async job to notify about end of stream
|
|
||||||
*/
|
|
||||||
static void UADC_JobSendEndOfStreamMsg(Job *job)
|
|
||||||
{
|
|
||||||
TF_Msg msg = {
|
|
||||||
.type = EVT_CAPT_DONE,
|
|
||||||
.frame_id = (TF_ID) job->data1
|
|
||||||
};
|
|
||||||
TF_Respond(comm, &msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedule sending a event report to the PC that the current stream has ended.
|
|
||||||
* The client library should handle this appropriately.
|
|
||||||
*/
|
|
||||||
void UADC_ReportEndOfStream(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
Job j = {
|
|
||||||
.unit = unit,
|
|
||||||
.data1 = priv->stream_frame_id, // copy the ID, it may be invalid by the time the cb gets executed
|
|
||||||
.cb = UADC_JobSendEndOfStreamMsg
|
|
||||||
};
|
|
||||||
scheduleJob(&j);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a helper function for the ADC DMA interrupt for handing the different interrupt types (half / full transfer).
|
|
||||||
* It sends the part of the buffer that was just captured via an async job, or aborts on overrun.
|
|
||||||
*
|
|
||||||
* It's split off here to allow calling it for the different flags without repeating code.
|
|
||||||
*
|
|
||||||
* @param unit
|
|
||||||
* @param tc - true if this is the TC interrupt, else HT
|
|
||||||
*/
|
|
||||||
static void handle_httc(Unit *unit, bool tc)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
uint32_t start = priv->stream_startpos;
|
|
||||||
uint32_t end;
|
|
||||||
const bool ht = !tc;
|
|
||||||
|
|
||||||
const bool m_trigd = priv->opmode == ADC_OPMODE_TRIGD;
|
|
||||||
const bool m_stream = priv->opmode == ADC_OPMODE_STREAM;
|
|
||||||
const bool m_fixcpt = priv->opmode == ADC_OPMODE_BLCAP;
|
|
||||||
|
|
||||||
if (ht) {
|
|
||||||
end = (priv->buf_itemcount / 2);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
end = priv->buf_itemcount;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start != end) { // this sometimes happened after a trigger, may be unnecessary now
|
|
||||||
if (end < start) {
|
|
||||||
// this was a trap for a bug with missed TC irq, it's hopefully fixed now
|
|
||||||
trap("end < start! %d < %d, tc %d", (int)end, (int)start, (int)tc);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t sgcount = (end - start) / priv->nb_channels;
|
|
||||||
|
|
||||||
if (m_trigd || m_fixcpt) {
|
|
||||||
sgcount = MIN(priv->trig_stream_remain, sgcount);
|
|
||||||
priv->trig_stream_remain -= sgcount;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for the closing condition
|
|
||||||
const bool close = !m_stream && priv->trig_stream_remain == 0;
|
|
||||||
|
|
||||||
if ((tc && priv->tc_pending) || (ht && priv->ht_pending)) {
|
|
||||||
dbg("(!) ADC DMA not handled in time, abort capture");
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_EMERGENCY_SHUTDOWN);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Here we set the tc/ht pending flags for detecting overrun
|
|
||||||
|
|
||||||
Job j = {
|
|
||||||
.unit = unit,
|
|
||||||
.data1 = start,
|
|
||||||
.data2 = sgcount * priv->nb_channels,
|
|
||||||
.data3 = (uint32_t) (close*0x80) | (tc*1), // bitfields to indicate what's happening
|
|
||||||
.cb = UADC_JobSendBlockChunk
|
|
||||||
};
|
|
||||||
|
|
||||||
if (tc)
|
|
||||||
priv->tc_pending = true;
|
|
||||||
else
|
|
||||||
priv->ht_pending = true;
|
|
||||||
|
|
||||||
if (!scheduleJob(&j)) {
|
|
||||||
// Abort if we can't queue - the stream would tear and we'd hog the system with error messages
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_EMERGENCY_SHUTDOWN);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (close) {
|
|
||||||
// If auto-arm is enabled, we need to re-arm again.
|
|
||||||
// However, EOS irq is disabled during the capture so the trigger edge detection would
|
|
||||||
// work on stale data from before this trigger. We have to wait for the next full
|
|
||||||
// conversion (EOS) before arming.
|
|
||||||
UADC_SwitchMode(unit, (priv->auto_rearm && m_trigd) ? ADC_OPMODE_REARM_PENDING : ADC_OPMODE_IDLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advance the starting position
|
|
||||||
if (tc) {
|
|
||||||
priv->stream_startpos = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
priv->stream_startpos = priv->buf_itemcount / 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IRQ handler for the DMA flags.
|
|
||||||
*
|
|
||||||
* We handle flags:
|
|
||||||
* TC - transfer complete
|
|
||||||
* HT - half transfer
|
|
||||||
* TE - transfer error (this should never happen unless there's a bug)
|
|
||||||
*
|
|
||||||
* The buffer works in a circular mode, so we always handle the previous half
|
|
||||||
* or what of it should be sent (if capture started somewhere inside).
|
|
||||||
*
|
|
||||||
* @param arg - the unit, passed via the irq dispatcher
|
|
||||||
*/
|
|
||||||
void UADC_DMA_Handler(void *arg)
|
|
||||||
{
|
|
||||||
Unit *unit = arg;
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
// First thing, grab the flags. They may change during the function.
|
|
||||||
// Working on the live register might cause race conditions.
|
|
||||||
const uint32_t isrsnapshot = priv->DMAx->ISR;
|
|
||||||
|
|
||||||
if (priv->opmode == ADC_OPMODE_UNINIT) {
|
|
||||||
// the IRQ occured while switching mode, clear flags and do nothing else
|
|
||||||
LL_DMA_ClearFlag_HT(priv->DMAx, priv->dma_chnum);
|
|
||||||
LL_DMA_ClearFlag_TC(priv->DMAx, priv->dma_chnum);
|
|
||||||
LL_DMA_ClearFlag_TE(priv->DMAx, priv->dma_chnum);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LL_DMA_IsActiveFlag_G(isrsnapshot, priv->dma_chnum)) {
|
|
||||||
// we have some flags set - check which
|
|
||||||
const bool tc = LL_DMA_IsActiveFlag_TC(isrsnapshot, priv->dma_chnum);
|
|
||||||
const bool ht = LL_DMA_IsActiveFlag_HT(isrsnapshot, priv->dma_chnum);
|
|
||||||
const bool te = LL_DMA_IsActiveFlag_TE(isrsnapshot, priv->dma_chnum);
|
|
||||||
|
|
||||||
if (ht) LL_DMA_ClearFlag_HT(priv->DMAx, priv->dma_chnum);
|
|
||||||
if (tc) LL_DMA_ClearFlag_TC(priv->DMAx, priv->dma_chnum);
|
|
||||||
|
|
||||||
if (te) {
|
|
||||||
// this shouldn't happen - error
|
|
||||||
adc_dbg("ADC DMA TE!");
|
|
||||||
LL_DMA_ClearFlag_TE(priv->DMAx, priv->dma_chnum);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check what mode we're in
|
|
||||||
const bool m_trigd = priv->opmode == ADC_OPMODE_TRIGD;
|
|
||||||
const bool m_stream = priv->opmode == ADC_OPMODE_STREAM;
|
|
||||||
const bool m_fixcpt = priv->opmode == ADC_OPMODE_BLCAP;
|
|
||||||
if (m_trigd || m_stream || m_fixcpt) {
|
|
||||||
const uint32_t half = (uint32_t) (priv->buf_itemcount / 2);
|
|
||||||
if (ht && tc) {
|
|
||||||
// dual event interrupt - may happen if we missed both and they were pending after
|
|
||||||
// interrupts became enabled again (this can happen due to the EOS or other higher prio irq's)
|
|
||||||
|
|
||||||
if (priv->stream_startpos > half) {
|
|
||||||
handle_httc(unit, true); // TC
|
|
||||||
handle_httc(unit, false); // HT
|
|
||||||
} else {
|
|
||||||
handle_httc(unit, false); // HT
|
|
||||||
handle_httc(unit, true); // TC
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ht && priv->stream_startpos > half) {
|
|
||||||
// We missed the TC interrupt while e.g. setting up the stream / interrupt. catch up!
|
|
||||||
// This fixes a bug with "negative size" for report.
|
|
||||||
handle_httc(unit, true); // TC
|
|
||||||
}
|
|
||||||
|
|
||||||
handle_httc(unit, tc);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// This shouldn't happen, the interrupt should be disabled in this opmode
|
|
||||||
dbg("(!) not streaming, ADC DMA IT should be disabled");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* End of measurement group interrupt handler.
|
|
||||||
* This interrupt records the measured values and checks for trigger.
|
|
||||||
*
|
|
||||||
* @param arg - unit, passed b y irq dispatcher
|
|
||||||
*/
|
|
||||||
void UADC_ADC_EOS_Handler(void *arg)
|
|
||||||
{
|
|
||||||
Unit *unit = arg;
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
// Normally
|
|
||||||
uint64_t timestamp = 0;
|
|
||||||
if (priv->opmode == ADC_OPMODE_ARMED) timestamp = PTIM_GetMicrotime();
|
|
||||||
|
|
||||||
LL_ADC_ClearFlag_EOS(priv->ADCx);
|
|
||||||
if (priv->opmode == ADC_OPMODE_UNINIT) return;
|
|
||||||
|
|
||||||
// Wait for the DMA to complete copying the last sample
|
|
||||||
uint32_t dmapos;
|
|
||||||
hw_wait_while((dmapos = DMA_POS(priv)) % priv->nb_channels != 0, 100); // XXX this could be changed to reading it from the DR instead
|
|
||||||
|
|
||||||
uint32_t sample_pos;
|
|
||||||
if (dmapos == 0) {
|
|
||||||
sample_pos = (uint32_t) (priv->buf_itemcount);
|
|
||||||
} else {
|
|
||||||
sample_pos = dmapos;
|
|
||||||
}
|
|
||||||
sample_pos -= priv->nb_channels;
|
|
||||||
|
|
||||||
int cnt = 0; // index of the sample within the group
|
|
||||||
|
|
||||||
const bool can_average = priv->real_frequency_int < UADC_MAX_FREQ_FOR_AVERAGING;
|
|
||||||
const uint32_t channels_mask = priv->channels_mask;
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < 18; i++) {
|
|
||||||
if (channels_mask & (1 << i)) {
|
|
||||||
const uint16_t val = priv->dma_buffer[sample_pos+cnt];
|
|
||||||
cnt++;
|
|
||||||
|
|
||||||
if (can_average) {
|
|
||||||
priv->averaging_bins[i] =
|
|
||||||
priv->averaging_bins[i] * (1.0f - priv->avg_factor_as_float) +
|
|
||||||
((float) val) * priv->avg_factor_as_float;
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->last_samples[i] = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->opmode == ADC_OPMODE_ARMED) {
|
|
||||||
const uint16_t val = priv->last_samples[priv->trigger_source];
|
|
||||||
|
|
||||||
if ((priv->trig_prev_level < priv->trig_level) && val >= priv->trig_level && (bool) (priv->trig_edge & 0b01)) {
|
|
||||||
// Rising edge
|
|
||||||
UADC_HandleTrigger(unit, 0b01, timestamp);
|
|
||||||
}
|
|
||||||
else if ((priv->trig_prev_level > priv->trig_level) && val <= priv->trig_level && (bool) (priv->trig_edge & 0b10)) {
|
|
||||||
// Falling edge
|
|
||||||
UADC_HandleTrigger(unit, 0b10, timestamp);
|
|
||||||
}
|
|
||||||
priv->trig_prev_level = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
// auto-rearm was waiting for the next sample
|
|
||||||
if (priv->opmode == ADC_OPMODE_REARM_PENDING) {
|
|
||||||
if (!priv->auto_rearm) {
|
|
||||||
// It looks like the flag was cleared by DISARM before we got a new sample.
|
|
||||||
// Let's just switch to IDLE
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
|
|
||||||
} else {
|
|
||||||
// Re-arming for a new trigger
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_ARMED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle a detected trigger - start capture if we're not in hold-off
|
|
||||||
*
|
|
||||||
* @param unit
|
|
||||||
* @param edge_type - edge type, is included in the report
|
|
||||||
* @param timestamp - event time
|
|
||||||
*/
|
|
||||||
void UADC_HandleTrigger(Unit *unit, uint8_t edge_type, uint64_t timestamp)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
if (priv->opmode == ADC_OPMODE_UNINIT) return;
|
|
||||||
|
|
||||||
if (priv->trig_holdoff != 0 && priv->trig_holdoff_remain > 0) {
|
|
||||||
// Trig discarded due to holdoff
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->trig_holdoff > 0) {
|
|
||||||
priv->trig_holdoff_remain = priv->trig_holdoff;
|
|
||||||
// Start the tick
|
|
||||||
unit->tick_interval = 1;
|
|
||||||
unit->_tick_cnt = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->stream_startpos = DMA_POS(priv);
|
|
||||||
priv->trig_stream_remain = priv->trig_len;
|
|
||||||
priv->stream_serial = 0;
|
|
||||||
|
|
||||||
// This func may be called from the EOS interrupt, so it's safer to send the header message asynchronously
|
|
||||||
Job j = {
|
|
||||||
.unit = unit,
|
|
||||||
.timestamp = timestamp,
|
|
||||||
.data1 = priv->stream_startpos,
|
|
||||||
.data2 = edge_type,
|
|
||||||
.cb = UADC_JobSendTriggerCaptureHeader
|
|
||||||
};
|
|
||||||
scheduleJob(&j);
|
|
||||||
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_TRIGD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abort ongoing capture.
|
|
||||||
*/
|
|
||||||
void UADC_AbortCapture(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
const enum uadc_opmode old_opmode = priv->opmode;
|
|
||||||
|
|
||||||
priv->auto_rearm = false;
|
|
||||||
|
|
||||||
if (old_opmode == ADC_OPMODE_BLCAP ||
|
|
||||||
old_opmode == ADC_OPMODE_STREAM ||
|
|
||||||
old_opmode == ADC_OPMODE_TRIGD) {
|
|
||||||
UADC_ReportEndOfStream(unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a manual block capture.
|
|
||||||
*
|
|
||||||
* @param unit
|
|
||||||
* @param len - number of samples (groups)
|
|
||||||
* @param frame_id - TF session to re-use for the report (client has a listener set up)
|
|
||||||
*/
|
|
||||||
void UADC_StartBlockCapture(Unit *unit, uint32_t len, TF_ID frame_id)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
if (priv->opmode == ADC_OPMODE_UNINIT) return;
|
|
||||||
|
|
||||||
priv->stream_frame_id = frame_id;
|
|
||||||
priv->stream_startpos = DMA_POS(priv);
|
|
||||||
priv->trig_stream_remain = len;
|
|
||||||
priv->stream_serial = 0;
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_BLCAP);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a stream
|
|
||||||
*
|
|
||||||
* @param frame_id - TF session to re-use for the frames (client has a listener set up)
|
|
||||||
*/
|
|
||||||
void UADC_StartStream(Unit *unit, TF_ID frame_id)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
if (priv->opmode == ADC_OPMODE_UNINIT) return;
|
|
||||||
|
|
||||||
priv->stream_frame_id = frame_id;
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_STREAM);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* End a stream by user request.
|
|
||||||
*/
|
|
||||||
void UADC_StopStream(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
if (priv->opmode == ADC_OPMODE_UNINIT) return;
|
|
||||||
|
|
||||||
UADC_ReportEndOfStream(unit);
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle unit update tick - expire the trigger hold-off.
|
|
||||||
* We also check for the emergency shutdown condition and clear it.
|
|
||||||
*/
|
|
||||||
void UADC_updateTick(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
// Recover from shutdown after a delay
|
|
||||||
if (priv->opmode == ADC_OPMODE_EMERGENCY_SHUTDOWN) {
|
|
||||||
adc_dbg("ADC recovering from emergency shutdown");
|
|
||||||
|
|
||||||
UADC_ReportEndOfStream(unit);
|
|
||||||
LL_TIM_EnableCounter(priv->TIMx);
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
|
|
||||||
unit->tick_interval = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->trig_holdoff_remain > 0) {
|
|
||||||
priv->trig_holdoff_remain--;
|
|
||||||
|
|
||||||
if (priv->trig_holdoff_remain == 0) {
|
|
||||||
unit->tick_interval = 0;
|
|
||||||
unit->_tick_cnt = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Switch the ADC operational mode.
|
|
||||||
*
|
|
||||||
* @param unit
|
|
||||||
* @param new_mode - mode to set
|
|
||||||
*/
|
|
||||||
void UADC_SwitchMode(Unit *unit, enum uadc_opmode new_mode)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
const enum uadc_opmode old_mode = priv->opmode;
|
|
||||||
if (new_mode == old_mode) return; // nothing to do
|
|
||||||
|
|
||||||
// if un-itied, can go only to IDLE
|
|
||||||
assert_param((old_mode != ADC_OPMODE_UNINIT) || (new_mode == ADC_OPMODE_IDLE));
|
|
||||||
|
|
||||||
priv->opmode = ADC_OPMODE_UNINIT;
|
|
||||||
|
|
||||||
if (new_mode == ADC_OPMODE_UNINIT) {
|
|
||||||
adc_dbg("ADC switch -> UNINIT");
|
|
||||||
// Stop the DMA, timer and disable ADC - this is called before tearing down the unit
|
|
||||||
LL_TIM_DisableCounter(priv->TIMx);
|
|
||||||
LL_ADC_ClearFlag_EOS(priv->ADCx);
|
|
||||||
LL_ADC_DisableIT_EOS(priv->ADCx);
|
|
||||||
|
|
||||||
// Switch off the ADC
|
|
||||||
if (LL_ADC_IsEnabled(priv->ADCx)) {
|
|
||||||
// Cancel ongoing conversion
|
|
||||||
if (LL_ADC_REG_IsConversionOngoing(priv->ADCx)) {
|
|
||||||
LL_ADC_REG_StopConversion(priv->ADCx);
|
|
||||||
hw_wait_while(LL_ADC_REG_IsStopConversionOngoing(priv->ADCx), 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
LL_ADC_Disable(priv->ADCx);
|
|
||||||
hw_wait_while(LL_ADC_IsDisableOngoing(priv->ADCx), 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
LL_DMA_DisableChannel(priv->DMAx, priv->dma_chnum);
|
|
||||||
LL_DMA_DisableIT_HT(priv->DMAx, priv->dma_chnum);
|
|
||||||
LL_DMA_DisableIT_TC(priv->DMAx, priv->dma_chnum);
|
|
||||||
LL_DMA_ClearFlag_HT(priv->DMAx, priv->dma_chnum);
|
|
||||||
LL_DMA_ClearFlag_TC(priv->DMAx, priv->dma_chnum);
|
|
||||||
}
|
|
||||||
else if (new_mode == ADC_OPMODE_IDLE || new_mode == ADC_OPMODE_REARM_PENDING) {
|
|
||||||
// IDLE and ARMED are identical with the exception that the trigger condition is not checked
|
|
||||||
// ARMED can be only entered from IDLE, thus we do the init only here.
|
|
||||||
|
|
||||||
priv->tc_pending = false;
|
|
||||||
priv->ht_pending = false;
|
|
||||||
|
|
||||||
// In IDLE, we don't need the DMA interrupts
|
|
||||||
LL_DMA_ClearFlag_HT(priv->DMAx, priv->dma_chnum);
|
|
||||||
LL_DMA_ClearFlag_TC(priv->DMAx, priv->dma_chnum);
|
|
||||||
LL_DMA_DisableIT_HT(priv->DMAx, priv->dma_chnum);
|
|
||||||
LL_DMA_DisableIT_TC(priv->DMAx, priv->dma_chnum);
|
|
||||||
|
|
||||||
// Use End Of Sequence to recover results for averaging from the DMA buffer and DR
|
|
||||||
LL_ADC_ClearFlag_EOS(priv->ADCx);
|
|
||||||
LL_ADC_EnableIT_EOS(priv->ADCx);
|
|
||||||
|
|
||||||
if (old_mode == ADC_OPMODE_UNINIT) {
|
|
||||||
// Nothing is started yet - this is the only way to leave UNINIT
|
|
||||||
LL_ADC_Enable(priv->ADCx);
|
|
||||||
LL_DMA_EnableChannel(priv->DMAx, priv->dma_chnum);
|
|
||||||
LL_TIM_EnableCounter(priv->TIMx);
|
|
||||||
|
|
||||||
LL_ADC_REG_StartConversion(priv->ADCx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (new_mode == ADC_OPMODE_EMERGENCY_SHUTDOWN) {
|
|
||||||
adc_dbg("ADC switch -> EMERGENCY_STOP");
|
|
||||||
// Emergency shutdown is used when the job queue overflows and the stream is torn
|
|
||||||
// This however doesn't help in the case when user sets such a high frequency
|
|
||||||
// that the whole app becomes unresponsive due to the completion ISR, need to verify the value manually.
|
|
||||||
|
|
||||||
LL_DMA_ClearFlag_HT(priv->DMAx, priv->dma_chnum);
|
|
||||||
LL_DMA_ClearFlag_TC(priv->DMAx, priv->dma_chnum);
|
|
||||||
LL_DMA_DisableIT_HT(priv->DMAx, priv->dma_chnum);
|
|
||||||
LL_DMA_DisableIT_TC(priv->DMAx, priv->dma_chnum);
|
|
||||||
|
|
||||||
LL_TIM_DisableCounter(priv->TIMx);
|
|
||||||
UADC_SetSampleRate(unit, 10000); // fallback to a known safe value
|
|
||||||
|
|
||||||
LL_ADC_ClearFlag_EOS(priv->ADCx);
|
|
||||||
LL_ADC_DisableIT_EOS(priv->ADCx);
|
|
||||||
|
|
||||||
unit->tick_interval = 0;
|
|
||||||
unit->_tick_cnt = 250; // 1-off
|
|
||||||
}
|
|
||||||
else if (new_mode == ADC_OPMODE_ARMED) {
|
|
||||||
adc_dbg("ADC switch -> ARMED");
|
|
||||||
assert_param(old_mode == ADC_OPMODE_IDLE || old_mode == ADC_OPMODE_REARM_PENDING);
|
|
||||||
|
|
||||||
// avoid firing immediately by the value jumping across the scale
|
|
||||||
priv->trig_prev_level = priv->last_samples[priv->trigger_source];
|
|
||||||
}
|
|
||||||
else if (new_mode == ADC_OPMODE_TRIGD || new_mode == ADC_OPMODE_STREAM || new_mode == ADC_OPMODE_BLCAP) {
|
|
||||||
adc_dbg("ADC switch -> CAPTURE");
|
|
||||||
|
|
||||||
assert_param(old_mode == ADC_OPMODE_ARMED || old_mode == ADC_OPMODE_IDLE);
|
|
||||||
|
|
||||||
// during the capture, we disallow direct readout and averaging to reduce overhead
|
|
||||||
LL_ADC_DisableIT_EOS(priv->ADCx);
|
|
||||||
|
|
||||||
// Enable the DMA buffer interrupts
|
|
||||||
|
|
||||||
// we must first clear the flags, otherwise it will cause WEIRD bugs in the handler
|
|
||||||
LL_DMA_ClearFlag_HT(priv->DMAx, priv->dma_chnum);
|
|
||||||
LL_DMA_ClearFlag_TC(priv->DMAx, priv->dma_chnum);
|
|
||||||
|
|
||||||
// those must be as close as possible to the enabling
|
|
||||||
// if not trig'd, we don't care for lost samples before (this could cause a DMA irq miss / ht/tc mismatch with the startpos)
|
|
||||||
if (new_mode != ADC_OPMODE_TRIGD) {
|
|
||||||
priv->stream_startpos = DMA_POS(priv);
|
|
||||||
priv->stream_serial = 0;
|
|
||||||
}
|
|
||||||
LL_DMA_EnableIT_HT(priv->DMAx, priv->dma_chnum);
|
|
||||||
LL_DMA_EnableIT_TC(priv->DMAx, priv->dma_chnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->opmode = new_mode;
|
|
||||||
}
|
|
||||||
@@ -1,264 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
// ADC unit init and de-init functions
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "unit_base.h"
|
|
||||||
|
|
||||||
#define ADC_INTERNAL
|
|
||||||
#include "_adc_internal.h"
|
|
||||||
|
|
||||||
/** Allocate data structure and set defaults */
|
|
||||||
error_t UADC_preInit(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
|
|
||||||
if (priv == NULL) return E_OUT_OF_MEM;
|
|
||||||
|
|
||||||
priv->cfg.channels = 1<<16; // Tsense by default - always available, easy testing
|
|
||||||
priv->cfg.sample_time = 0b010; // 13.5c - good enough and the default 0b00 value really is useless
|
|
||||||
priv->cfg.frequency = 1000;
|
|
||||||
priv->cfg.buffer_size = 256; // in half-words
|
|
||||||
priv->cfg.averaging_factor = 500; // 0.5
|
|
||||||
|
|
||||||
priv->opmode = ADC_OPMODE_UNINIT;
|
|
||||||
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Configure frequency */
|
|
||||||
error_t UADC_SetSampleRate(Unit *unit, uint32_t hertz)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
uint16_t presc;
|
|
||||||
uint32_t count;
|
|
||||||
if (!solve_timer(PLAT_APB1_HZ, hertz, true, &presc, &count, &priv->real_frequency)) {
|
|
||||||
dbg("Failed to resolve timer params.");
|
|
||||||
return E_BAD_VALUE;
|
|
||||||
}
|
|
||||||
adc_dbg("Frequency error %d ppm, presc %d, count %d",
|
|
||||||
(int) lrintf(1000000.0f * ((priv->real_frequency - hertz) / (float) hertz)),
|
|
||||||
(int) presc, (int) count);
|
|
||||||
|
|
||||||
LL_TIM_SetPrescaler(priv->TIMx, (uint32_t) (presc - 1));
|
|
||||||
LL_TIM_SetAutoReload(priv->TIMx, count - 1);
|
|
||||||
|
|
||||||
priv->real_frequency_int = hertz;
|
|
||||||
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up the ADC DMA.
|
|
||||||
* This is split to its own function because it's also called when the user adjusts the
|
|
||||||
* enabled channels and we need to re-configure it.
|
|
||||||
*
|
|
||||||
* @param unit
|
|
||||||
*/
|
|
||||||
void UADC_SetupDMA(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
adc_dbg("Setting up DMA");
|
|
||||||
{
|
|
||||||
uint32_t itemcount = priv->nb_channels * (priv->cfg.buffer_size / (priv->nb_channels));
|
|
||||||
if (itemcount % 2 == 1) itemcount -= priv->nb_channels; // ensure the count is even
|
|
||||||
priv->buf_itemcount = itemcount;
|
|
||||||
|
|
||||||
adc_dbg("DMA item count is %d (%d bytes), There are %d samples per group.",
|
|
||||||
(int)priv->buf_itemcount,
|
|
||||||
(int)(priv->buf_itemcount * sizeof(uint16_t)),
|
|
||||||
(int)priv->nb_channels);
|
|
||||||
|
|
||||||
{
|
|
||||||
LL_DMA_InitTypeDef init;
|
|
||||||
LL_DMA_StructInit(&init);
|
|
||||||
init.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
|
|
||||||
|
|
||||||
init.Mode = LL_DMA_MODE_CIRCULAR;
|
|
||||||
init.NbData = itemcount;
|
|
||||||
|
|
||||||
init.PeriphOrM2MSrcAddress = (uint32_t) &priv->ADCx->DR;
|
|
||||||
init.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD;
|
|
||||||
init.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
|
|
||||||
|
|
||||||
init.MemoryOrM2MDstAddress = (uint32_t) priv->dma_buffer;
|
|
||||||
init.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD;
|
|
||||||
init.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
|
|
||||||
|
|
||||||
assert_param(SUCCESS == LL_DMA_Init(priv->DMAx, priv->dma_chnum, &init));
|
|
||||||
}
|
|
||||||
|
|
||||||
// LL_DMA_EnableChannel(priv->DMAx, priv->dma_chnum); // this is done in the switch mode func now
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Finalize unit set-up */
|
|
||||||
error_t UADC_init(Unit *unit)
|
|
||||||
{
|
|
||||||
bool suc = true;
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
// Written for F072 which has only one ADC
|
|
||||||
|
|
||||||
TRY(rsc_claim(unit, R_ADC1));
|
|
||||||
TRY(rsc_claim(unit, R_DMA1_1));
|
|
||||||
TRY(rsc_claim(unit, R_TIM15));
|
|
||||||
|
|
||||||
priv->DMAx = DMA1;
|
|
||||||
priv->DMA_CHx = DMA1_Channel1;
|
|
||||||
priv->dma_chnum = 1;
|
|
||||||
priv->ADCx = ADC1;
|
|
||||||
priv->ADCx_Common = ADC1_COMMON;
|
|
||||||
priv->TIMx = TIM15;
|
|
||||||
|
|
||||||
// ----------------------- CONFIGURE PINS --------------------------
|
|
||||||
{
|
|
||||||
// Claim and configure all analog pins
|
|
||||||
priv->nb_channels = 0;
|
|
||||||
for (uint8_t i = 0; i <= UADC_MAX_CHANNEL; i++) {
|
|
||||||
if (priv->cfg.channels & (1 << i)) {
|
|
||||||
priv->nb_channels++;
|
|
||||||
|
|
||||||
char c;
|
|
||||||
uint8_t num;
|
|
||||||
if (i <= 7) {
|
|
||||||
c = 'A';
|
|
||||||
num = i;
|
|
||||||
}
|
|
||||||
else if (i <= 9) {
|
|
||||||
c = 'B';
|
|
||||||
num = (uint8_t) (i - 8);
|
|
||||||
}
|
|
||||||
else if (i <= 15) {
|
|
||||||
c = 'C';
|
|
||||||
num = (uint8_t) (i - 10);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRY(rsc_claim_pin(unit, c, num));
|
|
||||||
uint32_t ll_pin = hw_pin2ll(num, &suc);
|
|
||||||
GPIO_TypeDef *port = hw_port2periph(c, &suc);
|
|
||||||
assert_param(suc);
|
|
||||||
|
|
||||||
LL_GPIO_SetPinPull(port, ll_pin, LL_GPIO_PULL_NO);
|
|
||||||
LL_GPIO_SetPinMode(port, ll_pin, LL_GPIO_MODE_ANALOG);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->nb_channels == 0) {
|
|
||||||
dbg("Need at least 1 channel");
|
|
||||||
return E_BAD_CONFIG;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure some minimal space is available
|
|
||||||
if (priv->cfg.buffer_size < priv->nb_channels * 2) {
|
|
||||||
dbg("Insufficient buf size");
|
|
||||||
return E_BAD_CONFIG;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------- Alloc the buffer ----------------------
|
|
||||||
adc_dbg("Allocating buffer of size %d half-words", (int)priv->cfg.buffer_size);
|
|
||||||
priv->dma_buffer = calloc_ck(priv->cfg.buffer_size, sizeof(uint16_t));
|
|
||||||
if (NULL == priv->dma_buffer) return E_OUT_OF_MEM;
|
|
||||||
assert_param(((uint32_t) priv->dma_buffer & 3) == 0); // must be aligned
|
|
||||||
|
|
||||||
// ------------------- ENABLE CLOCKS --------------------------
|
|
||||||
{
|
|
||||||
// enable peripherals clock
|
|
||||||
hw_periph_clock_enable(priv->ADCx);
|
|
||||||
hw_periph_clock_enable(priv->TIMx);
|
|
||||||
// DMA and GPIO clocks are enabled on startup automatically
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------- CONFIGURE THE TIMER --------------------------
|
|
||||||
adc_dbg("Setting up TIMER");
|
|
||||||
{
|
|
||||||
TRY(UADC_SetSampleRate(unit, priv->cfg.frequency));
|
|
||||||
|
|
||||||
LL_TIM_EnableARRPreload(priv->TIMx);
|
|
||||||
LL_TIM_EnableUpdateEvent(priv->TIMx);
|
|
||||||
LL_TIM_SetTriggerOutput(priv->TIMx, LL_TIM_TRGO_UPDATE);
|
|
||||||
LL_TIM_GenerateEvent_UPDATE(priv->TIMx); // load the prescaller value
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------- CONFIGURE THE ADC ---------------------------
|
|
||||||
adc_dbg("Setting up ADC");
|
|
||||||
{
|
|
||||||
// Calibrate the ADC
|
|
||||||
adc_dbg("Wait for calib");
|
|
||||||
LL_ADC_StartCalibration(priv->ADCx);
|
|
||||||
while (LL_ADC_IsCalibrationOnGoing(priv->ADCx)) {}
|
|
||||||
adc_dbg("ADC calibrated.");
|
|
||||||
|
|
||||||
// Let's just enable the internal channels always - makes toggling them on-line easier
|
|
||||||
LL_ADC_SetCommonPathInternalCh(priv->ADCx_Common, LL_ADC_PATH_INTERNAL_VREFINT | LL_ADC_PATH_INTERNAL_TEMPSENSOR);
|
|
||||||
|
|
||||||
LL_ADC_SetDataAlignment(priv->ADCx, LL_ADC_DATA_ALIGN_RIGHT);
|
|
||||||
LL_ADC_SetResolution(priv->ADCx, LL_ADC_RESOLUTION_12B);
|
|
||||||
LL_ADC_REG_SetDMATransfer(priv->ADCx, LL_ADC_REG_DMA_TRANSFER_UNLIMITED);
|
|
||||||
|
|
||||||
// configure channels
|
|
||||||
priv->channels_mask = priv->cfg.channels;
|
|
||||||
|
|
||||||
priv->ADCx->CHSELR = priv->channels_mask;
|
|
||||||
|
|
||||||
LL_ADC_REG_SetTriggerSource(priv->ADCx, LL_ADC_REG_TRIG_EXT_TIM15_TRGO);
|
|
||||||
|
|
||||||
LL_ADC_SetSamplingTimeCommonChannels(priv->ADCx, LL_ADC_SAMPLETIMES[priv->cfg.sample_time]);
|
|
||||||
|
|
||||||
// will be enabled when switching to INIT mode
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------- CONFIGURE DMA -------------------------------
|
|
||||||
UADC_SetupDMA(unit);
|
|
||||||
|
|
||||||
// prepare the avg factor float for the ISR
|
|
||||||
if (priv->cfg.averaging_factor > 1000) priv->cfg.averaging_factor = 1000; // normalize
|
|
||||||
priv->avg_factor_as_float = priv->cfg.averaging_factor/1000.0f;
|
|
||||||
|
|
||||||
adc_dbg("ADC peripherals configured.");
|
|
||||||
|
|
||||||
irqd_attach(priv->DMA_CHx, UADC_DMA_Handler, unit);
|
|
||||||
irqd_attach(priv->ADCx, UADC_ADC_EOS_Handler, unit);
|
|
||||||
adc_dbg("irqs attached");
|
|
||||||
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
|
|
||||||
adc_dbg("ADC done");
|
|
||||||
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Tear down the unit */
|
|
||||||
void UADC_deInit(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
// de-init peripherals
|
|
||||||
if (unit->status == E_SUCCESS ) {
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_UNINIT);
|
|
||||||
|
|
||||||
//LL_ADC_DeInit(priv->ADCx);
|
|
||||||
LL_ADC_CommonDeInit(priv->ADCx_Common);
|
|
||||||
LL_TIM_DeInit(priv->TIMx);
|
|
||||||
|
|
||||||
irqd_detach(priv->DMA_CHx, UADC_DMA_Handler);
|
|
||||||
irqd_detach(priv->ADCx, UADC_ADC_EOS_Handler);
|
|
||||||
|
|
||||||
LL_DMA_DeInit(priv->DMAx, priv->dma_chnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
// free buffer if not NULL
|
|
||||||
free_ck(priv->dma_buffer);
|
|
||||||
|
|
||||||
// Release all resources, deinit pins
|
|
||||||
rsc_teardown(unit);
|
|
||||||
|
|
||||||
// Free memory
|
|
||||||
free_ck(unit->data);
|
|
||||||
}
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
// Defines and prototypes used internally by the ADC unit.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef GEX_F072_ADC_INTERNAL_H
|
|
||||||
#define GEX_F072_ADC_INTERNAL_H
|
|
||||||
|
|
||||||
#ifndef ADC_INTERNAL
|
|
||||||
#error bad include!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "unit_base.h"
|
|
||||||
|
|
||||||
//#define adc_dbg dbg
|
|
||||||
#define adc_dbg(...) do {} while(0)
|
|
||||||
|
|
||||||
#define UADC_MAX_FREQ_FOR_AVERAGING 20000
|
|
||||||
|
|
||||||
#define UADC_MAX_CHANNEL 17
|
|
||||||
|
|
||||||
enum uadc_opmode {
|
|
||||||
ADC_OPMODE_UNINIT, //!< Not yet switched to any mode
|
|
||||||
ADC_OPMODE_IDLE, //!< Idle. Allows immediate value readout and averaging.
|
|
||||||
ADC_OPMODE_REARM_PENDING, //!< Idle, waiting for the next sample to re-arm (auto trigger).
|
|
||||||
ADC_OPMODE_ARMED, //!< Armed for a trigger. Direct access and averaging are disabled.
|
|
||||||
ADC_OPMODE_TRIGD, //!< Triggered, sending pre-trigger and streaming captured data.
|
|
||||||
ADC_OPMODE_BLCAP, //!< Capture of fixed length without a trigger
|
|
||||||
ADC_OPMODE_STREAM, //!< Unlimited capture
|
|
||||||
ADC_OPMODE_EMERGENCY_SHUTDOWN, //!< Used when the buffers overrun to safely transition to IDLE after a delay
|
|
||||||
};
|
|
||||||
|
|
||||||
enum uadc_event {
|
|
||||||
EVT_CAPT_START = 50, //!< Capture start (used in event in the first frame when trigger is detected)
|
|
||||||
EVT_CAPT_MORE = 51, //!< Capture data payload (used as TYPE for all capture types)
|
|
||||||
EVT_CAPT_DONE = 52, //!< End of trig'd or block capture payload (last frame with data),
|
|
||||||
//!< or a farewell message after closing stream using abort(), in this case without data.
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Private data structure */
|
|
||||||
struct priv {
|
|
||||||
struct {
|
|
||||||
uint32_t channels; //!< bit flags (will be recorded in order 0-15)
|
|
||||||
uint8_t sample_time; //!< 0-7 (corresponds to 1.5-239.5 cycles) - time for the sampling capacitor to charge
|
|
||||||
uint32_t frequency; //!< Timer frequency in Hz. Note: not all frequencies can be achieved accurately
|
|
||||||
uint32_t buffer_size; //!< Buffer size in bytes (count 2 bytes per channel per measurement) - faster sampling freq needs bigger buffer
|
|
||||||
uint16_t averaging_factor; //!< Exponential averaging factor 0-1000
|
|
||||||
} cfg;
|
|
||||||
|
|
||||||
// Peripherals
|
|
||||||
ADC_TypeDef *ADCx; //!< The ADC peripheral used
|
|
||||||
ADC_Common_TypeDef *ADCx_Common; //!< The ADC common control block
|
|
||||||
TIM_TypeDef *TIMx; //!< ADC timing timer instance
|
|
||||||
DMA_TypeDef *DMAx; //!< DMA isnatnce used
|
|
||||||
uint8_t dma_chnum; //!< DMA channel number
|
|
||||||
DMA_Channel_TypeDef *DMA_CHx; //!< DMA channel instance
|
|
||||||
|
|
||||||
// Live config
|
|
||||||
float real_frequency;
|
|
||||||
uint32_t real_frequency_int;
|
|
||||||
uint32_t channels_mask; //!< channels bitfield including tsense and vref
|
|
||||||
float avg_factor_as_float;
|
|
||||||
|
|
||||||
uint16_t *dma_buffer; //!< malloc'd buffer for the samples
|
|
||||||
uint8_t nb_channels; //!< nbr of enabled adc channels
|
|
||||||
uint32_t buf_itemcount; //!< real size of the buffer in samples (adjusted to fit 2x whole multiple of sample group)
|
|
||||||
|
|
||||||
// Trigger state
|
|
||||||
uint32_t trig_stream_remain; //!< Counter of samples remaining to be sent in the post-trigger stream
|
|
||||||
uint16_t trig_holdoff_remain; //!< Tmp counter for the currently active hold-off
|
|
||||||
uint16_t trig_prev_level; //!< Value of the previous sample, used to detect trigger edge
|
|
||||||
uint32_t stream_startpos; //!< Byte offset in the DMA buffer where the next capture for a stream should start.
|
|
||||||
//!< Updated in TH/TC and on trigger (after the preceding data is sent as a pretrig buffer)
|
|
||||||
|
|
||||||
enum uadc_opmode opmode; //!< OpMode (state machine state)
|
|
||||||
float averaging_bins[18]; //!< Averaging buffers, enough space to accommodate all channels (16 external + 2 internal)
|
|
||||||
uint16_t last_samples[18]; //!< If averaging is disabled, the last captured sample is stored here.
|
|
||||||
|
|
||||||
// Trigger config
|
|
||||||
uint8_t trigger_source; //!< number of the pin selected as a trigger source
|
|
||||||
uint32_t pretrig_len; //!< Pre-trigger length, nbr of historical samples to report when trigger occurs
|
|
||||||
uint32_t trig_len; //!< Trigger length, nbr of samples to report AFTER a trigger occurs
|
|
||||||
uint16_t trig_level; //!< Triggering level in LSB
|
|
||||||
uint8_t trig_edge; //!< Which edge we want to trigger on. 1-rising, 2-falling, 3-both
|
|
||||||
bool auto_rearm; //!< Flag that the trigger should be re-armed after the stream finishes
|
|
||||||
uint16_t trig_holdoff; //!< Trigger hold-off time, set when configuring the trigger
|
|
||||||
TF_ID stream_frame_id; //!< Session ID for multi-part stream (response or report)
|
|
||||||
uint8_t stream_serial; //!< Serial nr of a stream frame
|
|
||||||
|
|
||||||
bool tc_pending;
|
|
||||||
bool ht_pending;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Allocate data structure and set defaults */
|
|
||||||
error_t UADC_preInit(Unit *unit);
|
|
||||||
|
|
||||||
/** Load from a binary buffer stored in Flash */
|
|
||||||
void UADC_loadBinary(Unit *unit, PayloadParser *pp);
|
|
||||||
|
|
||||||
/** Write to a binary buffer for storing in Flash */
|
|
||||||
void UADC_writeBinary(Unit *unit, PayloadBuilder *pb);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Parse a key-value pair from the INI file */
|
|
||||||
error_t UADC_loadIni(Unit *unit, const char *key, const char *value);
|
|
||||||
|
|
||||||
/** Generate INI file section for the unit */
|
|
||||||
void UADC_writeIni(Unit *unit, IniWriter *iw);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Finalize unit set-up */
|
|
||||||
error_t UADC_init(Unit *unit);
|
|
||||||
|
|
||||||
/** Tear down the unit */
|
|
||||||
void UADC_deInit(Unit *unit);
|
|
||||||
|
|
||||||
/** Configure DMA (buffer count etc) */
|
|
||||||
void UADC_SetupDMA(Unit *unit);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** DMA half/complete handler */
|
|
||||||
void UADC_DMA_Handler(void *arg);
|
|
||||||
|
|
||||||
/** ADC eod of sequence handler */
|
|
||||||
void UADC_ADC_EOS_Handler(void *arg);
|
|
||||||
|
|
||||||
/** Switch to a different opmode */
|
|
||||||
void UADC_SwitchMode(Unit *unit, enum uadc_opmode new_mode);
|
|
||||||
|
|
||||||
/** Handle trigger - process pre-trigger and start streaming the requested number of samples */
|
|
||||||
void UADC_HandleTrigger(Unit *unit, uint8_t edge_type, uint64_t timestamp);
|
|
||||||
|
|
||||||
/** Handle a periodic tick - expiring the hold-off */
|
|
||||||
void UADC_updateTick(Unit *unit);
|
|
||||||
|
|
||||||
/** Send a end-of-stream message to PC's stream listener so it can shut down. */
|
|
||||||
void UADC_ReportEndOfStream(Unit *unit);
|
|
||||||
|
|
||||||
/** Start a block capture */
|
|
||||||
void UADC_StartBlockCapture(Unit *unit, uint32_t len, TF_ID frame_id);
|
|
||||||
|
|
||||||
/** Start stream */
|
|
||||||
void UADC_StartStream(Unit *unit, TF_ID frame_id);
|
|
||||||
|
|
||||||
/** End stream */
|
|
||||||
void UADC_StopStream(Unit *unit);
|
|
||||||
|
|
||||||
/** Configure frequency */
|
|
||||||
error_t UADC_SetSampleRate(Unit *unit, uint32_t hertz);
|
|
||||||
|
|
||||||
/** Abort capture */
|
|
||||||
void UADC_AbortCapture(Unit *unit);
|
|
||||||
|
|
||||||
#endif //GEX_F072_ADC_INTERNAL_H
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
// ADC unit settings reading / parsing
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "unit_base.h"
|
|
||||||
|
|
||||||
#define ADC_INTERNAL
|
|
||||||
#include "_adc_internal.h"
|
|
||||||
|
|
||||||
/** Load from a binary buffer stored in Flash */
|
|
||||||
void UADC_loadBinary(Unit *unit, PayloadParser *pp)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
uint8_t version = pp_u8(pp);
|
|
||||||
(void)version;
|
|
||||||
|
|
||||||
priv->cfg.channels = pp_u32(pp);
|
|
||||||
priv->cfg.sample_time = pp_u8(pp);
|
|
||||||
priv->cfg.frequency = pp_u32(pp);
|
|
||||||
priv->cfg.buffer_size = pp_u32(pp);
|
|
||||||
priv->cfg.averaging_factor = pp_u16(pp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Write to a binary buffer for storing in Flash */
|
|
||||||
void UADC_writeBinary(Unit *unit, PayloadBuilder *pb)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
pb_u8(pb, 0); // version
|
|
||||||
|
|
||||||
pb_u32(pb, priv->cfg.channels);
|
|
||||||
pb_u8(pb, priv->cfg.sample_time);
|
|
||||||
pb_u32(pb, priv->cfg.frequency);
|
|
||||||
pb_u32(pb, priv->cfg.buffer_size);
|
|
||||||
pb_u16(pb, priv->cfg.averaging_factor);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Parse a key-value pair from the INI file */
|
|
||||||
error_t UADC_loadIni(Unit *unit, const char *key, const char *value)
|
|
||||||
{
|
|
||||||
bool suc = true;
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
if (streq(key, "channels")) {
|
|
||||||
priv->cfg.channels = parse_pinmask(value, &suc);
|
|
||||||
}
|
|
||||||
else if (streq(key, "sample_time")) {
|
|
||||||
priv->cfg.sample_time = (uint8_t) avr_atoi(value);
|
|
||||||
if (priv->cfg.sample_time > 7) return E_BAD_VALUE;
|
|
||||||
}
|
|
||||||
else if (streq(key, "frequency")) {
|
|
||||||
priv->cfg.frequency = (uint32_t) avr_atoi(value);
|
|
||||||
}
|
|
||||||
else if (streq(key, "buffer_size")) {
|
|
||||||
priv->cfg.buffer_size = (uint32_t) avr_atoi(value);
|
|
||||||
}
|
|
||||||
else if (streq(key, "avg_factor")) {
|
|
||||||
priv->cfg.averaging_factor = (uint16_t) avr_atoi(value);
|
|
||||||
if (priv->cfg.averaging_factor > 1000) return E_BAD_VALUE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return E_BAD_KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!suc) return E_BAD_VALUE;
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Generate INI file section for the unit */
|
|
||||||
void UADC_writeIni(Unit *unit, IniWriter *iw)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
iw_comment(iw, "Enabled channels, comma separated");
|
|
||||||
iw_comment(iw, " 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17");
|
|
||||||
iw_comment(iw, "A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 C0 C1 C2 C3 C4 C5 Tsens Vref");
|
|
||||||
iw_entry(iw, "channels", "%s", pinmask2str_up(priv->cfg.channels, unit_tmp512));
|
|
||||||
|
|
||||||
iw_cmt_newline(iw);
|
|
||||||
iw_comment(iw, "Sampling time (0-7)");
|
|
||||||
iw_entry(iw, "sample_time", "%d", (int)priv->cfg.sample_time);
|
|
||||||
|
|
||||||
iw_comment(iw, "Sampling frequency (Hz)");
|
|
||||||
iw_entry(iw, "frequency", "%d", (int)priv->cfg.frequency);
|
|
||||||
|
|
||||||
iw_cmt_newline(iw);
|
|
||||||
iw_comment(iw, "Sample buffer size");
|
|
||||||
iw_comment(iw, "- shared by all enabled channels");
|
|
||||||
iw_comment(iw, "- defines the maximum pre-trigger size (divide by # of channels)");
|
|
||||||
iw_comment(iw, "- captured data is sent in half-buffer chunks");
|
|
||||||
iw_comment(iw, "- buffer overrun aborts the data capture");
|
|
||||||
iw_entry(iw, "buffer_size", "%d", (int)priv->cfg.buffer_size);
|
|
||||||
|
|
||||||
iw_cmt_newline(iw);
|
|
||||||
iw_comment(iw, "Exponential averaging coefficient (permil, range 0-1000 ~ 0.000-1.000)");
|
|
||||||
iw_comment(iw, "- used formula: y[t]=(1-k)*y[t-1]+k*u[t]");
|
|
||||||
iw_comment(iw, "- not available when a capture is running");
|
|
||||||
iw_entry(iw, "avg_factor", "%d", priv->cfg.averaging_factor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,405 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2017/11/25.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "unit_base.h"
|
|
||||||
#include "unit_adc.h"
|
|
||||||
|
|
||||||
#define ADC_INTERNAL
|
|
||||||
#include "_adc_internal.h"
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
enum AdcCmd_ {
|
|
||||||
CMD_READ_RAW = 0,
|
|
||||||
CMD_READ_SMOOTHED = 1,
|
|
||||||
|
|
||||||
CMD_GET_ENABLED_CHANNELS = 10,
|
|
||||||
CMD_GET_SAMPLE_RATE = 11,
|
|
||||||
|
|
||||||
CMD_SETUP_TRIGGER = 20,
|
|
||||||
CMD_ARM = 21,
|
|
||||||
CMD_DISARM = 22,
|
|
||||||
CMD_ABORT = 23, // abort any ongoing capture or stream
|
|
||||||
CMD_FORCE_TRIGGER = 24,
|
|
||||||
CMD_BLOCK_CAPTURE = 25,
|
|
||||||
CMD_STREAM_START = 26,
|
|
||||||
CMD_STREAM_STOP = 27,
|
|
||||||
CMD_SET_SMOOTHING_FACTOR = 28,
|
|
||||||
CMD_SET_SAMPLE_RATE = 29,
|
|
||||||
CMD_ENABLE_CHANNELS = 30,
|
|
||||||
CMD_SET_SAMPLE_TIME = 31,
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Handle a request message */
|
|
||||||
static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL);
|
|
||||||
|
|
||||||
switch (command) {
|
|
||||||
/**
|
|
||||||
* Get enabled channels.
|
|
||||||
* Response: bytes with indices of enabled channels, ascending order.
|
|
||||||
*/
|
|
||||||
case CMD_GET_ENABLED_CHANNELS:
|
|
||||||
for (uint8_t i = 0; i < 18; i++) {
|
|
||||||
if (priv->channels_mask & (1 << i)) {
|
|
||||||
pb_u8(&pb, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the sample rate in Hz
|
|
||||||
* plad: hz:u32
|
|
||||||
*/
|
|
||||||
case CMD_SET_SAMPLE_RATE:
|
|
||||||
{
|
|
||||||
uint32_t freq = pp_u32(pp);
|
|
||||||
if (freq == 0) return E_BAD_VALUE;
|
|
||||||
|
|
||||||
TRY(UADC_SetSampleRate(unit, freq));
|
|
||||||
}
|
|
||||||
// Pass through - send back the obtained sample rate
|
|
||||||
/**
|
|
||||||
* Read the real used frequency, expressed as float.
|
|
||||||
* May differ from the configured or requested value due to prescaller limitations.
|
|
||||||
*/
|
|
||||||
case CMD_GET_SAMPLE_RATE:
|
|
||||||
pb_u32(&pb, priv->real_frequency_int);
|
|
||||||
pb_float(&pb, priv->real_frequency);
|
|
||||||
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set smoothing factor 0-1000.
|
|
||||||
* pld: u16:factor
|
|
||||||
*/
|
|
||||||
case CMD_SET_SMOOTHING_FACTOR:
|
|
||||||
{
|
|
||||||
uint16_t fac = pp_u16(pp);
|
|
||||||
if (fac > 1000) return E_BAD_VALUE;
|
|
||||||
priv->avg_factor_as_float = fac / 1000.0f;
|
|
||||||
}
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set sample time
|
|
||||||
* pld: u8:0-7
|
|
||||||
*/
|
|
||||||
case CMD_SET_SAMPLE_TIME:
|
|
||||||
{
|
|
||||||
uint8_t tim = pp_u8(pp);
|
|
||||||
if (tim > 7) return E_BAD_VALUE;
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_UNINIT);
|
|
||||||
{
|
|
||||||
LL_ADC_SetSamplingTimeCommonChannels(priv->ADCx, LL_ADC_SAMPLETIMES[tim]);
|
|
||||||
}
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
|
|
||||||
}
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable channels. The channels must've been configured in the settings (except ch 16 and 17 which are available always)
|
|
||||||
* pld: u32: bitmap of channels
|
|
||||||
*/
|
|
||||||
case CMD_ENABLE_CHANNELS:
|
|
||||||
{
|
|
||||||
uint32_t new_channels = pp_u32(pp);
|
|
||||||
|
|
||||||
// this tears down the peripherals sufficiently so we can re-configure them. Going back to IDLE re-inits this
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_UNINIT);
|
|
||||||
|
|
||||||
uint32_t illegal_channels = new_channels & ~(priv->cfg.channels | (1<<16) | (1<<17)); // 16 and 17 may be enabled always
|
|
||||||
if (illegal_channels != 0) {
|
|
||||||
com_respond_str(MSG_ERROR, frame_id, "Some requested channels not available");
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
|
|
||||||
return E_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t nb_channels = 0;
|
|
||||||
// count the enabled channels
|
|
||||||
for(int i = 0; i < 32; i++) {
|
|
||||||
if (new_channels & (1<<i)) {
|
|
||||||
nb_channels++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nb_channels == 0) {
|
|
||||||
com_respond_str(MSG_ERROR, frame_id, "Need at least 1 channel");
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
|
|
||||||
return E_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->cfg.buffer_size < nb_channels * 2) {
|
|
||||||
com_respond_str(MSG_ERROR, frame_id, "Insufficient buf size");
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
|
|
||||||
return E_BAD_CONFIG;
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->nb_channels = nb_channels;
|
|
||||||
priv->ADCx->CHSELR = new_channels; // apply it to the ADC
|
|
||||||
priv->channels_mask = new_channels;
|
|
||||||
|
|
||||||
UADC_SetupDMA(unit);
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
|
|
||||||
}
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read raw values from the last measurement.
|
|
||||||
* Response: interleaved (u8:channel, u16:value) for all channels
|
|
||||||
*/
|
|
||||||
case CMD_READ_RAW:
|
|
||||||
if(priv->opmode != ADC_OPMODE_IDLE && priv->opmode != ADC_OPMODE_ARMED) {
|
|
||||||
return E_BUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < 18; i++) {
|
|
||||||
if (priv->channels_mask & (1 << i)) {
|
|
||||||
pb_u16(&pb, priv->last_samples[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read smoothed values.
|
|
||||||
* Response: interleaved (u8:channel, f32:value) for all channels
|
|
||||||
*/
|
|
||||||
case CMD_READ_SMOOTHED:
|
|
||||||
if(priv->opmode != ADC_OPMODE_IDLE && priv->opmode != ADC_OPMODE_ARMED) {
|
|
||||||
return E_BUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->real_frequency_int > UADC_MAX_FREQ_FOR_AVERAGING) {
|
|
||||||
com_respond_str(MSG_ERROR, frame_id, "Too fast for smoothing");
|
|
||||||
return E_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < 18; i++) {
|
|
||||||
if (priv->channels_mask & (1 << i)) {
|
|
||||||
pb_float(&pb, priv->averaging_bins[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure a trigger. This is legal only if the current state is IDLE or ARMED (will re-arm).
|
|
||||||
*
|
|
||||||
* Payload:
|
|
||||||
* u8 - source channel
|
|
||||||
* u16 - triggering level
|
|
||||||
* u8 - edge to trigger on: 1-rising, 2-falling, 3-both
|
|
||||||
* u16 - pre-trigger samples count
|
|
||||||
* u32 - post-trigger samples count
|
|
||||||
* u16 - trigger hold-off in ms (dead time after firing, before it cna fire again if armed)
|
|
||||||
* u8(bool) - auto re-arm after firing and completing the capture
|
|
||||||
*/
|
|
||||||
case CMD_SETUP_TRIGGER:
|
|
||||||
adc_dbg("> Setup trigger");
|
|
||||||
if (priv->opmode != ADC_OPMODE_IDLE &&
|
|
||||||
priv->opmode != ADC_OPMODE_ARMED &&
|
|
||||||
priv->opmode != ADC_OPMODE_REARM_PENDING) {
|
|
||||||
return E_BUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
const uint8_t source = pp_u8(pp);
|
|
||||||
const uint16_t level = pp_u16(pp);
|
|
||||||
const uint8_t edge = pp_u8(pp);
|
|
||||||
const uint32_t pretrig = pp_u32(pp);
|
|
||||||
const uint32_t count = pp_u32(pp);
|
|
||||||
const uint16_t holdoff = pp_u16(pp);
|
|
||||||
const bool auto_rearm = pp_bool(pp);
|
|
||||||
|
|
||||||
if (source > UADC_MAX_CHANNEL) {
|
|
||||||
com_respond_str(MSG_ERROR, frame_id, "Invalid trig source");
|
|
||||||
return E_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 == (priv->channels_mask & (1 << source))) {
|
|
||||||
com_respond_str(MSG_ERROR, frame_id, "Channel not enabled");
|
|
||||||
return E_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (level > 4095) {
|
|
||||||
com_respond_str(MSG_ERROR, frame_id, "Level out of range (0-4095)");
|
|
||||||
return E_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (edge == 0 || edge > 3) {
|
|
||||||
com_respond_str(MSG_ERROR, frame_id, "Bad edge");
|
|
||||||
return E_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX the max size may be too much
|
|
||||||
const uint32_t max_pretrig = (priv->buf_itemcount / priv->nb_channels);
|
|
||||||
if (pretrig > max_pretrig) {
|
|
||||||
com_respond_snprintf(frame_id, MSG_ERROR,
|
|
||||||
"Pretrig too large (max %d)", (int) max_pretrig);
|
|
||||||
return E_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->trigger_source = source;
|
|
||||||
priv->trig_level = level;
|
|
||||||
priv->trig_prev_level = priv->last_samples[source];
|
|
||||||
priv->trig_edge = edge;
|
|
||||||
priv->pretrig_len = pretrig;
|
|
||||||
priv->trig_len = count;
|
|
||||||
priv->trig_holdoff = holdoff;
|
|
||||||
priv->auto_rearm = auto_rearm;
|
|
||||||
}
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Arm (permissible only if idle and the trigger is configured)
|
|
||||||
*/
|
|
||||||
case CMD_ARM:
|
|
||||||
adc_dbg("> Arm");
|
|
||||||
uint8_t sticky = pp_u8(pp);
|
|
||||||
|
|
||||||
if(priv->opmode == ADC_OPMODE_ARMED || priv->opmode == ADC_OPMODE_REARM_PENDING) {
|
|
||||||
// We are armed or will re-arm promptly, act like the call succeeded
|
|
||||||
// The auto flag is set regardless
|
|
||||||
} else {
|
|
||||||
if (priv->opmode != ADC_OPMODE_IDLE) {
|
|
||||||
return E_BUSY; // capture in progress
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->trig_len == 0) {
|
|
||||||
com_respond_str(MSG_ERROR, frame_id, "Trigger not configured.");
|
|
||||||
return E_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_ARMED);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sticky != 255) {
|
|
||||||
priv->auto_rearm = (bool)sticky;
|
|
||||||
}
|
|
||||||
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dis-arm. Permissible only when idle or armed.
|
|
||||||
* Switches to idle.
|
|
||||||
*/
|
|
||||||
case CMD_DISARM:
|
|
||||||
adc_dbg("> Disarm");
|
|
||||||
|
|
||||||
priv->auto_rearm = false;
|
|
||||||
|
|
||||||
if(priv->opmode == ADC_OPMODE_IDLE) {
|
|
||||||
return E_SUCCESS; // already idle, success - no work to do
|
|
||||||
}
|
|
||||||
|
|
||||||
// capture in progress
|
|
||||||
if (priv->opmode != ADC_OPMODE_ARMED &&
|
|
||||||
priv->opmode != ADC_OPMODE_REARM_PENDING) {
|
|
||||||
// Capture in progress, we already cleared auto rearm, so we're done for now
|
|
||||||
// auto_rearm is checked in the EOS isr and if cleared, does not re-arm.
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abort any ongoing capture and dis-arm.
|
|
||||||
*/
|
|
||||||
case CMD_ABORT:;
|
|
||||||
adc_dbg("> Abort capture");
|
|
||||||
UADC_AbortCapture(unit);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Force a trigger (complete with pre-trigger capture and hold-off)
|
|
||||||
* The reported edge will be 0b11, here meaning "manual trigger"
|
|
||||||
*/
|
|
||||||
case CMD_FORCE_TRIGGER:
|
|
||||||
adc_dbg("> Force trigger");
|
|
||||||
// This is similar to block capture, but includes the pre-trig buffer and has fixed size based on trigger config
|
|
||||||
// FORCE is useful for checking if the trigger is set up correctly
|
|
||||||
if (priv->opmode != ADC_OPMODE_ARMED &&
|
|
||||||
priv->opmode != ADC_OPMODE_IDLE &&
|
|
||||||
priv->opmode != ADC_OPMODE_REARM_PENDING) return E_BUSY;
|
|
||||||
|
|
||||||
if (priv->trig_len == 0) {
|
|
||||||
com_respond_str(MSG_ERROR, frame_id, "Trigger not configured.");
|
|
||||||
return E_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
UADC_HandleTrigger(unit, 0b11, PTIM_GetMicrotime());
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a block capture (like manual trigger, but without pre-trigger and arming)
|
|
||||||
*
|
|
||||||
* Payload:
|
|
||||||
* u32 - sample count (for each channel)
|
|
||||||
*/
|
|
||||||
case CMD_BLOCK_CAPTURE:
|
|
||||||
adc_dbg("> Block cpt");
|
|
||||||
if (priv->opmode != ADC_OPMODE_ARMED &&
|
|
||||||
priv->opmode != ADC_OPMODE_REARM_PENDING &&
|
|
||||||
priv->opmode != ADC_OPMODE_IDLE) return E_BUSY;
|
|
||||||
|
|
||||||
uint32_t count = pp_u32(pp);
|
|
||||||
|
|
||||||
UADC_StartBlockCapture(unit, count, frame_id);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start streaming (like block capture, but unlimited)
|
|
||||||
* The stream can be terminated by the stop command.
|
|
||||||
*/
|
|
||||||
case CMD_STREAM_START:
|
|
||||||
adc_dbg("> Stream ON");
|
|
||||||
if (priv->opmode != ADC_OPMODE_ARMED &&
|
|
||||||
priv->opmode != ADC_OPMODE_REARM_PENDING &&
|
|
||||||
priv->opmode != ADC_OPMODE_IDLE) return E_BUSY;
|
|
||||||
|
|
||||||
UADC_StartStream(unit, frame_id);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop a stream.
|
|
||||||
*/
|
|
||||||
case CMD_STREAM_STOP:
|
|
||||||
adc_dbg("> Stream OFF");
|
|
||||||
if (priv->opmode != ADC_OPMODE_STREAM) {
|
|
||||||
com_respond_str(MSG_ERROR, frame_id, "Not streaming");
|
|
||||||
return E_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
UADC_StopStream(unit);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return E_UNKNOWN_COMMAND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Unit template */
|
|
||||||
const UnitDriver UNIT_ADC = {
|
|
||||||
.name = "ADC",
|
|
||||||
.description = "Analog/digital converter",
|
|
||||||
// Settings
|
|
||||||
.preInit = UADC_preInit,
|
|
||||||
.cfgLoadBinary = UADC_loadBinary,
|
|
||||||
.cfgWriteBinary = UADC_writeBinary,
|
|
||||||
.cfgLoadIni = UADC_loadIni,
|
|
||||||
.cfgWriteIni = UADC_writeIni,
|
|
||||||
// Init
|
|
||||||
.init = UADC_init,
|
|
||||||
.deInit = UADC_deInit,
|
|
||||||
// Function
|
|
||||||
.handleRequest = UADC_handleRequest,
|
|
||||||
.updateTick = UADC_updateTick,
|
|
||||||
};
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2017/11/25.
|
|
||||||
//
|
|
||||||
// ADC unit with several DSO-like features, like triggering, pre-trigger, block capture,
|
|
||||||
// streaming, smoothing...
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef U_TPL_H
|
|
||||||
#define U_TPL_H
|
|
||||||
|
|
||||||
#include "unit.h"
|
|
||||||
|
|
||||||
extern const UnitDriver UNIT_ADC;
|
|
||||||
|
|
||||||
#endif //U_TPL_H
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "unit_base.h"
|
|
||||||
#include "unit_din.h"
|
|
||||||
|
|
||||||
#define DIN_INTERNAL
|
|
||||||
|
|
||||||
#include "_din_internal.h"
|
|
||||||
|
|
||||||
/** Read request */
|
|
||||||
error_t UU_DIn_Read(Unit *unit, uint16_t *packed)
|
|
||||||
{
|
|
||||||
CHECK_TYPE(unit, &UNIT_DIN);
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
*packed = pinmask_pack((uint16_t) priv->port->IDR, priv->pins);
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Arm pins */
|
|
||||||
error_t UU_DIn_Arm(Unit *unit, uint16_t arm_single_packed, uint16_t arm_auto_packed)
|
|
||||||
{
|
|
||||||
CHECK_TYPE(unit, &UNIT_DIN);
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
uint16_t arm_single = pinmask_spread(arm_single_packed, priv->pins);
|
|
||||||
uint16_t arm_auto = pinmask_spread(arm_auto_packed, priv->pins);
|
|
||||||
|
|
||||||
// abort if user tries to arm pin that doesn't have a trigger configured
|
|
||||||
if (0 != ((arm_single | arm_auto) & ~(priv->trig_fall | priv->trig_rise))) {
|
|
||||||
return E_BAD_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// arm and reset hold-offs
|
|
||||||
// we use critical section to avoid irq between the two steps
|
|
||||||
vPortEnterCritical();
|
|
||||||
{
|
|
||||||
priv->arm_auto |= arm_single;
|
|
||||||
priv->arm_single |= arm_auto;
|
|
||||||
const uint16_t combined = arm_single | arm_auto;
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
if (combined & (1 << i)) {
|
|
||||||
priv->holdoff_countdowns[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vPortExitCritical();
|
|
||||||
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** DisArm pins */
|
|
||||||
error_t UU_DIn_DisArm(Unit *unit, uint16_t disarm_packed)
|
|
||||||
{
|
|
||||||
CHECK_TYPE(unit, &UNIT_DIN);
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
uint16_t disarm = pinmask_spread(disarm_packed, priv->pins);
|
|
||||||
|
|
||||||
// abort if user tries to disarm pin that doesn't have a trigger configured
|
|
||||||
if (0 != ((disarm) & ~(priv->trig_fall | priv->trig_rise))) {
|
|
||||||
return E_BAD_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->arm_auto &= ~disarm;
|
|
||||||
priv->arm_single &= ~disarm;
|
|
||||||
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "unit_base.h"
|
|
||||||
|
|
||||||
#define DIN_INTERNAL
|
|
||||||
|
|
||||||
#include "_din_internal.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a trigger event to master (called on the message queue thread).
|
|
||||||
*
|
|
||||||
* unit - unit
|
|
||||||
* timestamp - timestamp
|
|
||||||
* data1 - packed, triggering pin
|
|
||||||
* data2 - snapshot
|
|
||||||
*/
|
|
||||||
static void DIn_SendTriggerReportToMaster(Job *job)
|
|
||||||
{
|
|
||||||
PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL);
|
|
||||||
pb_u16(&pb, (uint16_t) job->data1); // packed, 1 on the triggering pin
|
|
||||||
pb_u16(&pb, (uint16_t) job->data2); // packed, snapshot
|
|
||||||
assert_param(pb.ok);
|
|
||||||
|
|
||||||
EventReport event = {
|
|
||||||
.unit = job->unit,
|
|
||||||
.timestamp = job->timestamp,
|
|
||||||
.data = pb.start,
|
|
||||||
.length = (uint16_t) pb_length(&pb),
|
|
||||||
};
|
|
||||||
|
|
||||||
EventReport_Send(&event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* EXTI callback for pin change interrupts
|
|
||||||
*
|
|
||||||
* @param arg - the unit is passed here
|
|
||||||
*/
|
|
||||||
void DIn_handleExti(void *arg)
|
|
||||||
{
|
|
||||||
const uint64_t ts = PTIM_GetMicrotime();
|
|
||||||
|
|
||||||
Unit *unit = arg;
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
const uint16_t snapshot = (uint16_t) priv->port->IDR;
|
|
||||||
|
|
||||||
uint16_t trigger_map = 0;
|
|
||||||
|
|
||||||
uint16_t mask = 1;
|
|
||||||
const uint16_t armed_pins = priv->arm_single | priv->arm_auto;
|
|
||||||
for (int i = 0; i < 16; i++, mask <<= 1) {
|
|
||||||
if (!LL_EXTI_ReadFlag_0_31(LL_EXTI_LINES[i])) continue;
|
|
||||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINES[i]);
|
|
||||||
|
|
||||||
// Armed and ready
|
|
||||||
if ((armed_pins & mask) && (priv->holdoff_countdowns[i] == 0)) {
|
|
||||||
// Mark as captured
|
|
||||||
trigger_map |= (1 << i);
|
|
||||||
// Start hold-off (no-op if zero hold-off)
|
|
||||||
priv->holdoff_countdowns[i] = priv->trig_holdoff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disarm all possibly used single triggers
|
|
||||||
priv->arm_single &= ~trigger_map;
|
|
||||||
|
|
||||||
if (trigger_map != 0) {
|
|
||||||
Job j = {
|
|
||||||
.unit = unit,
|
|
||||||
.timestamp = ts,
|
|
||||||
.data1 = pinmask_pack(trigger_map, priv->pins),
|
|
||||||
.data2 = pinmask_pack(snapshot, priv->pins),
|
|
||||||
.cb = DIn_SendTriggerReportToMaster
|
|
||||||
};
|
|
||||||
scheduleJob(&j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "unit_base.h"
|
|
||||||
|
|
||||||
#define DIN_INTERNAL
|
|
||||||
#include "_din_internal.h"
|
|
||||||
|
|
||||||
/** Allocate data structure and set defaults */
|
|
||||||
error_t DIn_preInit(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
|
|
||||||
if (priv == NULL) return E_OUT_OF_MEM;
|
|
||||||
|
|
||||||
// some defaults
|
|
||||||
priv->port_name = 'A';
|
|
||||||
priv->pins = 0x0001;
|
|
||||||
priv->pulldown = 0x0000;
|
|
||||||
priv->pullup = 0x0000;
|
|
||||||
|
|
||||||
priv->trig_rise = 0x0000;
|
|
||||||
priv->trig_fall = 0x0000;
|
|
||||||
priv->trig_holdoff = 100;
|
|
||||||
priv->def_auto = 0x0000;
|
|
||||||
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Finalize unit set-up */
|
|
||||||
error_t DIn_init(Unit *unit)
|
|
||||||
{
|
|
||||||
bool suc = true;
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
priv->pulldown &= priv->pins;
|
|
||||||
priv->pullup &= priv->pins;
|
|
||||||
priv->trig_rise &= priv->pins;
|
|
||||||
priv->trig_fall &= priv->pins;
|
|
||||||
priv->def_auto &= (priv->trig_rise|priv->trig_fall);
|
|
||||||
|
|
||||||
// copy auto-arm defaults to the auto-arm register (the register may be manipulated by commands)
|
|
||||||
priv->arm_auto = priv->def_auto;
|
|
||||||
priv->arm_single = 0;
|
|
||||||
|
|
||||||
// clear countdowns
|
|
||||||
memset(priv->holdoff_countdowns, 0, sizeof(priv->holdoff_countdowns));
|
|
||||||
|
|
||||||
// --- Parse config ---
|
|
||||||
priv->port = hw_port2periph(priv->port_name, &suc);
|
|
||||||
if (!suc) return E_BAD_CONFIG;
|
|
||||||
|
|
||||||
// Claim all needed pins
|
|
||||||
TRY(rsc_claim_gpios(unit, priv->port_name, priv->pins));
|
|
||||||
|
|
||||||
uint16_t mask = 1;
|
|
||||||
for (int i = 0; i < 16; i++, mask <<= 1) {
|
|
||||||
if (priv->pins & mask) {
|
|
||||||
uint32_t ll_pin = hw_pin2ll((uint8_t) i, &suc);
|
|
||||||
|
|
||||||
// --- Init hardware ---
|
|
||||||
LL_GPIO_SetPinMode(priv->port, ll_pin, LL_GPIO_MODE_INPUT);
|
|
||||||
|
|
||||||
uint32_t pull = 0;
|
|
||||||
|
|
||||||
#if PLAT_NO_FLOATING_INPUTS
|
|
||||||
pull = LL_GPIO_PULL_UP;
|
|
||||||
#else
|
|
||||||
pull = LL_GPIO_PULL_NO;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (priv->pulldown & mask) pull = LL_GPIO_PULL_DOWN;
|
|
||||||
if (priv->pullup & mask) pull = LL_GPIO_PULL_UP;
|
|
||||||
LL_GPIO_SetPinPull(priv->port, ll_pin, pull);
|
|
||||||
|
|
||||||
if ((priv->trig_rise|priv->trig_fall) & mask) {
|
|
||||||
LL_EXTI_EnableIT_0_31(LL_EXTI_LINES[i]);
|
|
||||||
|
|
||||||
if (priv->trig_rise & mask) {
|
|
||||||
LL_EXTI_EnableRisingTrig_0_31(LL_EXTI_LINES[i]);
|
|
||||||
}
|
|
||||||
if (priv->trig_fall & mask) {
|
|
||||||
LL_EXTI_EnableFallingTrig_0_31(LL_EXTI_LINES[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
LL_SYSCFG_SetEXTISource(LL_SYSCFG_EXTI_PORTS[priv->port_name-'A'], LL_SYSCFG_EXTI_LINES[i]);
|
|
||||||
|
|
||||||
irqd_attach(EXTIS[i], DIn_handleExti, unit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// request ticks if we have triggers and any hold-offs configured
|
|
||||||
if ((priv->trig_rise|priv->trig_fall) && priv->trig_holdoff > 0) {
|
|
||||||
unit->tick_interval = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Tear down the unit */
|
|
||||||
void DIn_deInit(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
// pins are de-inited during teardown
|
|
||||||
|
|
||||||
// Detach EXTI handlers and disable interrupts
|
|
||||||
const uint16_t triggs = priv->trig_rise | priv->trig_fall;
|
|
||||||
if (unit->status == E_SUCCESS && triggs) {
|
|
||||||
uint16_t mask = 1;
|
|
||||||
for (int i = 0; i < 16; i++, mask <<= 1) {
|
|
||||||
if (triggs & mask) {
|
|
||||||
LL_EXTI_DisableIT_0_31(LL_EXTI_LINES[i]);
|
|
||||||
irqd_detach(EXTIS[i], DIn_handleExti);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release all resources
|
|
||||||
rsc_teardown(unit);
|
|
||||||
|
|
||||||
// Free memory
|
|
||||||
free_ck(unit->data);
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef GEX_F072_DIN_INTERNAL_H
|
|
||||||
#define GEX_F072_DIN_INTERNAL_H
|
|
||||||
|
|
||||||
#ifndef DIN_INTERNAL
|
|
||||||
#error bad include!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "unit_base.h"
|
|
||||||
|
|
||||||
/** Private data structure */
|
|
||||||
struct priv {
|
|
||||||
char port_name;
|
|
||||||
uint16_t pins; // pin mask
|
|
||||||
uint16_t pulldown; // pull-downs (default is pull-up)
|
|
||||||
uint16_t pullup; // pull-ups
|
|
||||||
uint16_t trig_rise; // pins generating events on rising edge
|
|
||||||
uint16_t trig_fall; // pins generating events on falling edge
|
|
||||||
uint16_t trig_holdoff; // ms
|
|
||||||
uint16_t def_auto; // initial auto triggers
|
|
||||||
|
|
||||||
uint16_t arm_auto; // pins armed for auto reporting
|
|
||||||
uint16_t arm_single; // pins armed for single event
|
|
||||||
uint16_t holdoff_countdowns[16]; // countdowns to arm for each pin in the bit map
|
|
||||||
GPIO_TypeDef *port;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Allocate data structure and set defaults */
|
|
||||||
error_t DIn_preInit(Unit *unit);
|
|
||||||
|
|
||||||
/** Load from a binary buffer stored in Flash */
|
|
||||||
void DIn_loadBinary(Unit *unit, PayloadParser *pp);
|
|
||||||
|
|
||||||
/** Write to a binary buffer for storing in Flash */
|
|
||||||
void DIn_writeBinary(Unit *unit, PayloadBuilder *pb);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Parse a key-value pair from the INI file */
|
|
||||||
error_t DIn_loadIni(Unit *unit, const char *key, const char *value);
|
|
||||||
|
|
||||||
/** Generate INI file section for the unit */
|
|
||||||
void DIn_writeIni(Unit *unit, IniWriter *iw);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Finalize unit set-up */
|
|
||||||
error_t DIn_init(Unit *unit);
|
|
||||||
|
|
||||||
/** Tear down the unit */
|
|
||||||
void DIn_deInit(Unit *unit);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* EXTI callback for pin change interrupts
|
|
||||||
*
|
|
||||||
* @param arg - the unit is passed here
|
|
||||||
*/
|
|
||||||
void DIn_handleExti(void *arg);
|
|
||||||
|
|
||||||
#endif //GEX_F072_DIN_INTERNAL_H
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "unit_base.h"
|
|
||||||
|
|
||||||
#define DIN_INTERNAL
|
|
||||||
#include "_din_internal.h"
|
|
||||||
|
|
||||||
/** Load from a binary buffer stored in Flash */
|
|
||||||
void DIn_loadBinary(Unit *unit, PayloadParser *pp)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
uint8_t version = pp_u8(pp);
|
|
||||||
(void)version;
|
|
||||||
|
|
||||||
priv->port_name = pp_char(pp);
|
|
||||||
priv->pins = pp_u16(pp);
|
|
||||||
priv->pulldown = pp_u16(pp);
|
|
||||||
priv->pullup = pp_u16(pp);
|
|
||||||
|
|
||||||
if (version >= 1) {
|
|
||||||
priv->trig_rise = pp_u16(pp);
|
|
||||||
priv->trig_fall = pp_u16(pp);
|
|
||||||
priv->trig_holdoff = pp_u16(pp);
|
|
||||||
}
|
|
||||||
if (version >= 2) {
|
|
||||||
priv->def_auto = pp_u16(pp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Write to a binary buffer for storing in Flash */
|
|
||||||
void DIn_writeBinary(Unit *unit, PayloadBuilder *pb)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
pb_u8(pb, 2); // version
|
|
||||||
|
|
||||||
pb_char(pb, priv->port_name);
|
|
||||||
pb_u16(pb, priv->pins);
|
|
||||||
pb_u16(pb, priv->pulldown);
|
|
||||||
pb_u16(pb, priv->pullup);
|
|
||||||
pb_u16(pb, priv->trig_rise);
|
|
||||||
pb_u16(pb, priv->trig_fall);
|
|
||||||
pb_u16(pb, priv->trig_holdoff);
|
|
||||||
pb_u16(pb, priv->def_auto);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Parse a key-value pair from the INI file */
|
|
||||||
error_t DIn_loadIni(Unit *unit, const char *key, const char *value)
|
|
||||||
{
|
|
||||||
bool suc = true;
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
if (streq(key, "port")) {
|
|
||||||
suc = parse_port_name(value, &priv->port_name);
|
|
||||||
}
|
|
||||||
else if (streq(key, "pins")) {
|
|
||||||
priv->pins = parse_pinmask(value, &suc);
|
|
||||||
}
|
|
||||||
else if (streq(key, "pull-up")) {
|
|
||||||
priv->pullup = parse_pinmask(value, &suc);
|
|
||||||
}
|
|
||||||
else if (streq(key, "pull-down")) {
|
|
||||||
priv->pulldown = parse_pinmask(value, &suc);
|
|
||||||
}
|
|
||||||
else if (streq(key, "trig-rise")) {
|
|
||||||
priv->trig_rise = parse_pinmask(value, &suc);
|
|
||||||
}
|
|
||||||
else if (streq(key, "trig-fall")) {
|
|
||||||
priv->trig_fall = parse_pinmask(value, &suc);
|
|
||||||
}
|
|
||||||
else if (streq(key, "auto-trigger")) {
|
|
||||||
priv->def_auto = parse_pinmask(value, &suc);
|
|
||||||
}
|
|
||||||
else if (streq(key, "hold-off")) {
|
|
||||||
priv->trig_holdoff = (uint16_t) avr_atoi(value);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return E_BAD_KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!suc) return E_BAD_VALUE;
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Generate INI file section for the unit */
|
|
||||||
void DIn_writeIni(Unit *unit, IniWriter *iw)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
iw_comment(iw, "Port name");
|
|
||||||
iw_entry(iw, "port", "%c", priv->port_name);
|
|
||||||
|
|
||||||
iw_comment(iw, "Pins (comma separated, supports ranges)");
|
|
||||||
iw_entry(iw, "pins", "%s", pinmask2str(priv->pins, unit_tmp512));
|
|
||||||
|
|
||||||
iw_comment(iw, "Pins with pull-up");
|
|
||||||
iw_entry(iw, "pull-up", "%s", pinmask2str(priv->pullup, unit_tmp512));
|
|
||||||
|
|
||||||
iw_comment(iw, "Pins with pull-down");
|
|
||||||
iw_entry(iw, "pull-down", "%s", pinmask2str(priv->pulldown, unit_tmp512));
|
|
||||||
|
|
||||||
iw_cmt_newline(iw);
|
|
||||||
iw_comment(iw, "Trigger pins activated by rising/falling edge");
|
|
||||||
iw_entry(iw, "trig-rise", "%s", pinmask2str(priv->trig_rise, unit_tmp512));
|
|
||||||
iw_entry(iw, "trig-fall", "%s", pinmask2str(priv->trig_fall, unit_tmp512));
|
|
||||||
|
|
||||||
iw_comment(iw, "Trigger pins auto-armed by default");
|
|
||||||
iw_entry(iw, "auto-trigger", "%s", pinmask2str(priv->def_auto, unit_tmp512));
|
|
||||||
|
|
||||||
iw_comment(iw, "Triggers hold-off time (ms)");
|
|
||||||
iw_entry(iw, "hold-off", "%d", (int)priv->trig_holdoff);
|
|
||||||
|
|
||||||
#if PLAT_NO_FLOATING_INPUTS
|
|
||||||
iw_comment(iw, "NOTE: Pins use pull-up by default.\r\n");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2017/11/25.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "unit_base.h"
|
|
||||||
#include "unit_din.h"
|
|
||||||
|
|
||||||
#define DIN_INTERNAL
|
|
||||||
#include "_din_internal.h"
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
enum PinCmd_ {
|
|
||||||
CMD_READ = 0,
|
|
||||||
CMD_ARM_SINGLE = 1,
|
|
||||||
CMD_ARM_AUTO = 2,
|
|
||||||
CMD_DISARM = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Handle a request message */
|
|
||||||
static error_t DIn_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
|
|
||||||
{
|
|
||||||
uint16_t pins = 0;
|
|
||||||
|
|
||||||
switch (command) {
|
|
||||||
case CMD_READ:;
|
|
||||||
TRY(UU_DIn_Read(unit, &pins));
|
|
||||||
|
|
||||||
PayloadBuilder pb = pb_start((uint8_t*)unit_tmp512, UNIT_TMP_LEN, NULL);
|
|
||||||
pb_u16(&pb, pins); // packed input pins
|
|
||||||
com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, pb_length(&pb));
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
case CMD_ARM_SINGLE:;
|
|
||||||
pins = pp_u16(pp);
|
|
||||||
if (!pp->ok) return E_MALFORMED_COMMAND;
|
|
||||||
|
|
||||||
TRY(UU_DIn_Arm(unit, pins, 0));
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
case CMD_ARM_AUTO:;
|
|
||||||
pins = pp_u16(pp);
|
|
||||||
if (!pp->ok) return E_MALFORMED_COMMAND;
|
|
||||||
|
|
||||||
TRY(UU_DIn_Arm(unit, 0, pins));
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
case CMD_DISARM:;
|
|
||||||
pins = pp_u16(pp);
|
|
||||||
if (!pp->ok) return E_MALFORMED_COMMAND;
|
|
||||||
|
|
||||||
TRY(UU_DIn_DisArm(unit, pins));
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return E_UNKNOWN_COMMAND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decrement all the hold-off timers on tick
|
|
||||||
*
|
|
||||||
* @param unit
|
|
||||||
*/
|
|
||||||
static void DIn_updateTick(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
if (priv->holdoff_countdowns[i] > 0) {
|
|
||||||
priv->holdoff_countdowns[i]--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Unit template */
|
|
||||||
const UnitDriver UNIT_DIN = {
|
|
||||||
.name = "DI",
|
|
||||||
.description = "Digital input with triggers",
|
|
||||||
// Settings
|
|
||||||
.preInit = DIn_preInit,
|
|
||||||
.cfgLoadBinary = DIn_loadBinary,
|
|
||||||
.cfgWriteBinary = DIn_writeBinary,
|
|
||||||
.cfgLoadIni = DIn_loadIni,
|
|
||||||
.cfgWriteIni = DIn_writeIni,
|
|
||||||
// Init
|
|
||||||
.init = DIn_init,
|
|
||||||
.deInit = DIn_deInit,
|
|
||||||
// Function
|
|
||||||
.handleRequest = DIn_handleRequest,
|
|
||||||
.updateTick = DIn_updateTick,
|
|
||||||
};
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user