Merge branch 'ofw_dev' into nfcrefactoring

This commit is contained in:
MX
2023-10-24 14:42:49 +03:00
512 changed files with 41484 additions and 68283 deletions
-1
View File
@@ -2,7 +2,6 @@
- `FreeRTOS-Kernel` - FreeRTOS kernel source code
- `FreeRTOS-glue` - Extra glue to hold together FreeRTOS kernel and flipper firmware
- `ST25RFAL002` - ST25R3916 Driver and protocol stack
- `app-scened-template` - C++ app library
- `callback-connector` - Callback connector library
- `cmsis_core` - CMSIS Core package, contain cortex-m core headers
+2 -2
View File
@@ -5,11 +5,11 @@ env.Append(
Dir("app-scened-template"),
Dir("digital_signal"),
Dir("pulse_reader"),
Dir("signal_reader"),
Dir("drivers"),
Dir("flipper_format"),
Dir("infrared"),
Dir("nfc"),
Dir("ST25RFAL002"),
Dir("subghz"),
Dir("toolbox"),
Dir("u8g2"),
@@ -83,7 +83,6 @@ libs = env.BuildModules(
"print",
"microtar",
"toolbox",
"ST25RFAL002",
"libusb_stm32",
"drivers",
"fatfs",
@@ -97,6 +96,7 @@ libs = env.BuildModules(
"nfc",
"digital_signal",
"pulse_reader",
"signal_reader",
"appframe",
"misc",
"lfrfid",
-19
View File
@@ -1,19 +0,0 @@
Import("env")
env.Append(
CPPPATH=[
"#/lib/ST25RFAL002",
"#/lib/ST25RFAL002/include",
"#/lib/ST25RFAL002/source/st25r3916",
],
)
libenv = env.Clone(FW_LIB_NAME="st25rfal002")
libenv.ApplyLibFlags()
sources = libenv.GlobRecursive("*.c")
lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources)
libenv.Install("${LIB_DIST_DIR}", lib)
Return("lib")
-354
View File
@@ -1,354 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-html40"><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<link rel="File-List" href="Library_files/filelist.xml">
<link rel="Edit-Time-Data" href="Library_files/editdata.mso">
<!--[if !mso]> <style> v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VML);} .shape {behavior:url(#default#VML);} </style> <![endif]-->
<title>Release Notes for RFAL Library</title>
<!--[if gte mso 9]><xml> <o:DocumentProperties> <o:Author>STMicroelectronics</o:Author> <o:LastAuthor>STMicroelectronics</o:LastAuthor> <o:Revision>37</o:Revision> <o:TotalTime>136</o:TotalTime> <o:Created>2009-02-27T19:26:00Z</o:Created> <o:LastSaved>2009-03-01T17:56:00Z</o:LastSaved> <o:Pages>1</o:Pages> <o:Words>522</o:Words> <o:Characters>2977</o:Characters> <o:Company>STMicroelectronics</o:Company> <o:Lines>24</o:Lines> <o:Paragraphs>6</o:Paragraphs> <o:CharactersWithSpaces>3493</o:CharactersWithSpaces> <o:Version>11.6568</o:Version> </o:DocumentProperties> </xml><![endif]--><!--[if gte mso 9]><xml> <w:WordDocument> <w:Zoom>110</w:Zoom> <w:ValidateAgainstSchemas/> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel> </w:WordDocument> </xml><![endif]--><!--[if gte mso 9]><xml> <w:LatentStyles DefLockedState="false" LatentStyleCount="156"> </w:LatentStyles> </xml><![endif]-->
<style>
<!--
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-parent:"";
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";}
h2
{mso-style-next:Normal;
margin-top:12.0pt;
margin-right:0in;
margin-bottom:3.0pt;
margin-left:0in;
mso-pagination:widow-orphan;
page-break-after:avoid;
mso-outline-level:2;
font-size:14.0pt;
font-family:Arial;
font-weight:bold;
font-style:italic;}
a:link, span.MsoHyperlink
{color:blue;
text-decoration:underline;
text-underline:single;}
a:visited, span.MsoHyperlinkFollowed
{color:blue;
text-decoration:underline;
text-underline:single;}
p
{mso-margin-top-alt:auto;
margin-right:0in;
mso-margin-bottom-alt:auto;
margin-left:0in;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";}
@page Section1
{size:8.5in 11.0in;
margin:1.0in 1.25in 1.0in 1.25in;
mso-header-margin:.5in;
mso-footer-margin:.5in;
mso-paper-source:0;}
div.Section1
{page:Section1;}
-->
</style><!--[if gte mso 10]> <style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin:0in; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;} </style> <![endif]--><!--[if gte mso 9]><xml> <o:shapedefaults v:ext="edit" spidmax="5122"/> </xml><![endif]--><!--[if gte mso 9]><xml> <o:shapelayout v:ext="edit"> <o:idmap v:ext="edit" data="1"/> </o:shapelayout></xml><![endif]-->
<meta content="MCD Application Team" name="author">
</head><body link="blue" vlink="blue">
<div class="Section1">
<p class="MsoNormal"><span style="font-family: Arial;"><o:p><br>
</o:p></span></p>
<div align="center">
<table class="MsoNormalTable" style="width: 675pt;" border="0" cellpadding="0" cellspacing="0" width="900">
<tbody>
<tr>
<td style="padding: 0cm;" valign="top">
<table class="MsoNormalTable" style="width: 675pt;" border="0" cellpadding="0" cellspacing="0" width="900">
<tbody>
<tr>
<td style="vertical-align: top;"> <br>
</td>
</tr>
<tr style="">
<td style="padding: 1.5pt;">
<h1 style="margin-bottom: 18pt; text-align: center;" align="center"><span style="font-size: 20pt; font-family: Verdana; color: rgb(51, 102, 255);">Release
Notes for RFAL software Library</span><span style="font-size: 20pt; font-family: Verdana;"><o:p></o:p></span></h1>
<p class="MsoNormal" style="text-align: center;" align="center"><span style="font-size: 10pt; font-family: Arial; color: black;">Copyright
2019 STMicroelectronics</span><span style="color: black;"><u1:p></u1:p><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: center;" align="center"><span style="font-size: 10pt; font-family: Arial; color: black;"><img style="border: 0px solid ; width: 104px; height: 77px;" alt="" id="_x0000_i1025" src="_htmresc/st_logo.png"></span><span style="font-size: 10pt;"><o:p></o:p></span></p>
</td>
</tr>
</tbody>
</table>
<p class="MsoNormal"><span style="font-family: Arial; display: none;"><o:p>&nbsp;</o:p></span></p>
<table class="MsoNormalTable" style="width: 675pt;" border="0" cellpadding="0" width="900">
<tbody>
<tr>
<td class="MsoNormal" style="padding: 0cm;" valign="top"><br>
<div style="margin-left: 40px;"><span style="font-size: 10pt; font-family: Verdana;">The <span style="font-weight: bold; font-style: italic;">RFAL Library</span>
(RF Abstraction Layer) provides several functionalities required to perform RF/NFC communications.</span><span style="font-size: 10pt; font-family: Verdana;">
The RFAL encapsulates the different RF ICs (ST25R3911, ST25R3916, ST25R95 and future ST25R devices) into a common and easy to use interface.</span><br>
<span style="font-size: 10pt; font-family: Verdana;"> </span><br>
<span style="font-size: 10pt; font-family: Verdana;"> </span><span style="font-size: 10pt; font-family: Verdana;">The technologies currently supported by RFAL are:
<ul>
<li> NFC-A \ ISO14443A (T1T, T2T, T4TA) </li>
<li> NFC-B \ ISO14443B (T4TB) </li>
<li> NFC-F \ FeliCa (T3T) </li>
<li> NFC-V \ ISO15693 (T5T) </li>
<li> P2P \ ISO18092 (NFCIP1, Passive-Active P2P) </li>
<li> ST25TB (ISO14443-2 Type B with Proprietary Protocol) </li>
<li> PicoPass \ iClass </li>
<li> B' \ Calypso </li>
<li> CTS \ CTM </li>
</ul>
</span><br>
<span style="font-size: 10pt; font-family: Verdana;"> </span><span style="font-size: 10pt; font-family: Verdana;">The protocols provided by RFAL are:
<ul>
<li> ISO-DEP (ISO14443-4) </li>
<li> NFC-DEP (ISO18092) </li>
</ul>
<br>
</span></div>
<ol style="margin-top: 0cm;" start="1" type="1">
</ol>
<span style="font-family: &quot;Times New Roman&quot;;"> </span>
<h2 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"><a name="History"></a><span style="font-size: 12pt; color: white;">Update History</span></h2>
<br>
<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 186px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V2.2.0 / 22-May-2020</span></h3>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;"></span></u></b></p>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main Changes<o:p></o:p></span></u></b></p>
<ul style="margin-top: 0cm;" type="square">
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Better alignment to NFC Forum latest requirements (CR12) <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Extended NFC-V module with non-addressed mode support and improved aticollision <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Feature Switches changed to be not mandatory. Modules disabled by default <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Aligned APIs on platform.h <i>(breaks compatibility with previous versions, see example in rfal.chm)</i> <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Added API for release/deletion of timers <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">ST25R3916 default analog table modified to X-NUCLEO-NFC06A1 board <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Improved AP2P operation <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Fixed issues introduced on previous release linked to SFGT and anticollision retries <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Introduced Low-Power mode <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Several driver improvements <span style="font-weight: bold; font-style: italic;"></span></span></li>
</ul>
<br>
<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 186px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V2.1.2 / 27-Jan-2020</span></h3>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;"></span></u></b></p>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main Changes<o:p></o:p></span></u></b></p>
<ul style="margin-top: 0cm;" type="square">
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Extended ISO-DEP and NFC-A module to support non-blocking activation interfaces <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Extended NFC/HL module to make use of the new APIs further splitting the execution of the worker during the different activities<span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Modified NFC-A anticollision to strictly comply to NFC Forum DP. A separate proprietary method is now available. <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">NFC-V changed to use OOK (100% AM) by default <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Fixed FWT used by NFC-V Sleep <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Fixed NFC-F FDT Poll value <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Fixed incorrect register access on ST25R3911B RFO Get/Set method <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">SPI driver modified to clear Rx buffer prior to operation <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Added further code size optimizations based on enabled features <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Updated ST25R3916 driver to DS Rev2 <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Updated SW Tag Detection as describded in AN Rev3 <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Several driver improvements <span style="font-weight: bold; font-style: italic;"></span></span></li>
</ul>
<br>
<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 186px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V2.1.0 / 30-Sep-2019</span></h3>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;"></span></u></b></p>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main Changes<o:p></o:p></span></u></b></p>
<ul style="margin-top: 0cm;" type="square">
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Extended RFAL NFC Higher Layer for increased functionality and configurations <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Several improvements on the ISO-DEP protocol layer <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Protocol buffer sizes made fully configurable for increased memory management <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Introduced option for Collision Avoidance with Automatic Gain Control <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Several driver improvements <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">ST25R3916 overheat protection disabled <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">RF Transceive modified for transmission errors to precede other errors <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Analog Configs extended to support different DPO power levels <span style="font-weight: bold; font-style: italic;"></span></span></li>
</ul>
<br>
<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 186px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V2.0.10 / 25-Jun-2019</span></h3>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;"></span></u></b></p>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main Changes<o:p></o:p></span></u></b></p>
<ul style="margin-top: 0cm;" type="square">
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Various improvements on RFAL NFC Higher layer <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Added alternative NFC-V anticollision method (non NFC Forum compliant) <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Several minor improvements and fixes <span style="font-weight: bold; font-style: italic;"></span></span></li>
</ul>
<br>
<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 186px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V2.0.6 / 10-Apr-2019</span></h3>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;"></span></u></b></p>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main Changes<o:p></o:p></span></u></b></p>
<ul style="margin-top: 0cm;" type="square">
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Several NFC-V interoperability improvements <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Extended support for specific features of ST's ISO15693 Tags. New ST25Dx module added<span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Interrupt handling changed and further protection added <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">RFAL feature switches have been modified and features are now disabled if omitted <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">ST25R3916 AAT (Automatic Antenna Tuning) module added <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">RFAL NFC Higher layer added <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Several driver improvements <span style="font-weight: bold; font-style: italic;"></span></span></li>
</ul>
<br>
<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 186px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V2.0.4 / 06-Fev-2019</span></h3>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Provided with ST25R3916 DISCO v1.0.0 / EMVCo v1.2.0<o:p></o:p></span></u></b></p>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main Changes<o:p></o:p></span></u></b></p>
<ul style="margin-top: 0cm;" type="square">
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Minor improvements on NFC-F module <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Several improvements on NFC-V module including support for ST proprietary features<span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Fixed issue with Delta RWT calculation <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Fixed incorrect usage of NFCB dTbPoll / DdFWT <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Added compile switch for Listen Mode <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Low power Listen Mode support added <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Listen Mode aligned to NFC Forum Digital 2.1 <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Added handling for EMVCo 3.0 static FDTListen <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Introduced SW Tag Detection <span style="font-weight: bold; font-style: italic;"></span></span></li>
</ul>
<br>
<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 186px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V2.0.2 / 31-Oct-2018</span></h3>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Provided with ST25R3916 DISCO v0.9.4 (binary only)<o:p></o:p></span></u></b></p>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main Changes<o:p></o:p></span></u></b></p>
<ul style="margin-top: 0cm;" type="square">
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">New T4T module added <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Added support for T3T Check and Update commands <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Improved NFC-V module and added Write Multiple Blocks support <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">New rfalWorker protection added for improved control in multi-thread environments <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Added support for user defined Analog Config tables <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Several driver improvements and protections added <span style="font-weight: bold; font-style: italic;"></span></span></li>
</ul>
<br>
<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 186px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V2.0.0 / 28-Aug-2018</span></h3>
<!-- <p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Provided with STM8-NFC05A1 <o:p></o:p></span></u></b></p> -->
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main Changes<o:p></o:p></span></u></b></p>
<ul style="margin-top: 0cm;" type="square">
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">MISRA C 2012 compliant <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">ST25R3916 support added <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">ST25R95 support added <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Fix unwanted Field Detector disable when entering Wake-up mode <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Extended Analog Config to have specific events <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Fixed NFC-DEP potential issue if DID used <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Extended NFC-V commands <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">T2T module added <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Improved initial Listen mode handling <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Extended Wake-Up mode to support Capacitive measurement <span style="font-weight: bold; font-style: italic;"></span></span></li>
</ul>
<br>
<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 186px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V1.3.6 / 08-May-2018</span></h3>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Provided with ST25R3911B DISCO v1.2.0<o:p></o:p></span></u></b></p>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main Changes<o:p></o:p></span></u></b></p>
<ul style="margin-top: 0cm;" type="square">
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Added ISO15693 x4 and x8 mode support <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Added S(PARAMETERS) support <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Interface changes for measurement, Wake-Up and DPO methods <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Added further feature switches to enable/disable individual modules <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Changed communication protection <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Improved NFC-A anti-collision <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Several driver improvements <span style="font-weight: bold; font-style: italic;"></span></span></li>
</ul>
<br>
<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 186px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V1.3.4 / 07-May-2018</span></h3>
<!--<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Provided with <o:p></o:p></span></u></b></p>-->
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main Changes<o:p></o:p></span></u></b></p>
<ul style="margin-top: 0cm;" type="square">
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Fixed NFC-V Read operation in addressed mode <span style="font-weight: bold; font-style: italic;"></span></span></li>
</ul>
<br>
<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 186px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V1.3.2 / 31-January-2018</span></h3>
<!--<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Provided with <o:p></o:p></span></u></b></p>-->
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main Changes<o:p></o:p></span></u></b></p>
<ul style="margin-top: 0cm;" type="square">
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Modified Wake-Up mode interface <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Fixed SFGI calculation in ISO-DEP <span style="font-weight: bold; font-style: italic;"></span></span></li>
</ul>
<br>
<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 186px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V1.3.0 / 22-January-2018</span></h3>
<!--<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Provided with <o:p></o:p></span></u></b></p>-->
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main Changes<o:p></o:p></span></u></b></p>
<ul style="margin-top: 0cm;" type="square">
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Introduced a new IRQ status handling to read the registers only once <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Several changes for supporting Linux platform <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">SPI Select/Deselect moved to platform.h <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Additional protection of the IRQ status reading, new macros available: platformProtectST25R391xIrqStatus / platformUnprotectST25R391xIrqStatus<span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Renamed the IRQ Enable/Disable macros to platformProtectST25R391xComm / platformUnprotectST25R391xComm <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Renamed SPI pins from chip specific to ST25R391X <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Introduced a new option ST25R391X_COM_SINGLETXRX which executes SPI in one single exchange (additional buffer required) <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Updated and added errata handlings to latest ST25R3911 Errata version <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Fixed inconsistency on Analog settings for NFC-V <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Fixed issue on NFC-V 1of256 decoding <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Changed the default NFC-A FDT Listen to be more strict <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Added Wake-Up mode support <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Added RFAL version definition <span style="font-weight: bold; font-style: italic;"></span></span></li>
</ul>
<br>
<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 186px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V1.2.0 / 17-August-2017</span></h3>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Provided with ST25R3911B Disco v1.1.16<o:p></o:p></span></u></b></p>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main Changes<o:p></o:p></span></u></b></p>
<ul style="margin-top: 0cm;" type="square">
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Aligned Technology modules to NFC Activity v1.1 and EMVCo v2.6 <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Extended NFC-B Collision Resolution allowing user define Slots <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Added feature switches to enable/disable individual modules <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">ISO-DEP Interface changes allowing more user configurations and further EMVCo alignment <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Changed ST25TB detection to always perform Anti Collision loop regardeless of the result of the Poll<span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Fixed FIFO WL handling <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Modified FDT Poll handling <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">changed rfalCalibrate() to not overwrite dynamic configs <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Added adjustment for TR1PUTMIN <span style="font-weight: bold; font-style: italic;"></span></span></li>
</ul>
<span style="font-size: 10pt; font-family: Verdana;"></span>
<br>
<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 186px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V1.1.0 / 30-June-2017</span></h3>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Provided with ST25R3911B Disco v1.1.12<o:p></o:p></span></u></b></p>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main Changes<o:p></o:p></span></u></b></p>
<ul style="margin-top: 0cm;" type="square">
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">EMD suppression enabled for ST25R3911B<span style="font-weight: bold; font-style: italic;"></span></span></li>
</ul>
<span style="font-size: 10pt; font-family: Verdana;"></span>
<br>
<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 186px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V1.0.0 / 16-May-2017</span></h3>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Provided with X-NUCLEO-NFC05A1 v1.0.0<o:p></o:p></span></u></b></p>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main Changes<o:p></o:p></span></u></b></p>
<ul style="margin-top: 0cm;" type="square">
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Added support for B', CTS and PicoPass/iClass mode <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Several impromvements for NFC-V mode <span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Improved error detection during NFC-B collision resolution<span style="font-weight: bold; font-style: italic;"></span></span></li>
<li class="MsoNormal"><span style="font-size: 10pt; font-family: Verdana;">Extended T1T module <span style="font-weight: bold; font-style: italic;"></span></span></li>
</ul>
<span style="font-size: 10pt; font-family: Verdana;"></span>
<br>
<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 186px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V0.9.0 / 02-March-2017</span></h3>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Provided with ST25R3911B Discovery Kit on Embedded World Conference (binary only)<o:p></o:p></span></u></b></p>
<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main Changes<o:p></o:p></span></u></b></p>
<span style="font-size: 10pt; font-family: Verdana;"></span>
<br>
</td>
</tr>
</tbody>
</table>
<p class="MsoNormal"><span style="font-size: 10pt;"><o:p></o:p></span></p>
</td>
</tr>
</tbody>
</table>
</div>
<p class="MsoNormal"><o:p>&nbsp;</o:p></p>
</div>
</body></html>
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.
-435
View File
@@ -1,435 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_AnalogConfig.h
*
* \author bkam
*
* \brief RF Chip Analog Configuration Settings
*
*
* \addtogroup RFAL
* @{
*
* \addtogroup RFAL-HAL
* \brief RFAL Hardware Abstraction Layer
* @{
*
* \addtogroup AnalogConfig
* \brief RFAL Analog Config Module
* @{
*
*/
#ifndef RFAL_ANALOG_CONFIG_H
#define RFAL_ANALOG_CONFIG_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
#include "st_errno.h"
#include "rfal_rf.h"
/*
******************************************************************************
* DEFINES
******************************************************************************
*/
#define RFAL_ANALOG_CONFIG_LUT_SIZE \
(87U) /*!< Maximum number of Configuration IDs in the Loop Up Table */
#define RFAL_ANALOG_CONFIG_LUT_NOT_FOUND \
(0xFFU) /*!< Index value indicating no Configuration IDs found */
#define RFAL_ANALOG_CONFIG_TBL_SIZE \
(1024U) /*!< Maximum number of Register-Mask-Value in the Setting List */
#define RFAL_ANALOG_CONFIG_POLL_LISTEN_MODE_MASK \
(0x8000U) /*!< Mask bit of Poll Mode in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_TECH_MASK \
(0x7F00U) /*!< Mask bits for Technology in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_BITRATE_MASK \
(0x00F0U) /*!< Mask bits for Bit rate in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_DIRECTION_MASK \
(0x000FU) /*!< Mask bits for Direction in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_CHIP_SPECIFIC_MASK \
(0x00FFU) /*!< Mask bits for Chip Specific Technology */
#define RFAL_ANALOG_CONFIG_POLL_LISTEN_MODE_SHIFT \
(15U) /*!< Shift value of Poll Mode in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_TECH_SHIFT \
(8U) /*!< Shift value for Technology in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_BITRATE_SHIFT \
(4U) /*!< Shift value for Technology in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_DIRECTION_SHIFT \
(0U) /*!< Shift value for Direction in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_POLL \
(0x0000U) /*!< Poll Mode bit setting in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_LISTEN \
(0x8000U) /*!< Listen Mode bit setting in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_TECH_CHIP \
(0x0000U) /*!< Chip-Specific bit setting in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_TECH_NFCA \
(0x0100U) /*!< NFC-A Technology bits setting in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_TECH_NFCB \
(0x0200U) /*!< NFC-B Technology bits setting in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_TECH_NFCF \
(0x0400U) /*!< NFC-F Technology bits setting in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_TECH_AP2P \
(0x0800U) /*!< AP2P Technology bits setting in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_TECH_NFCV \
(0x1000U) /*!< NFC-V Technology bits setting in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_TECH_RFU (0x2000U) /*!< RFU for Technology bits */
#define RFAL_ANALOG_CONFIG_BITRATE_COMMON \
(0x0000U) /*!< Common settings for all bit rates in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_BITRATE_106 \
(0x0010U) /*!< 106kbits/s settings in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_BITRATE_212 \
(0x0020U) /*!< 212kbits/s settings in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_BITRATE_424 \
(0x0030U) /*!< 424kbits/s settings in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_BITRATE_848 \
(0x0040U) /*!< 848kbits/s settings in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_BITRATE_1695 \
(0x0050U) /*!< 1695kbits/s settings in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_BITRATE_3390 \
(0x0060U) /*!< 3390kbits/s settings in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_BITRATE_6780 \
(0x0070U) /*!< 6780kbits/s settings in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_BITRATE_1OF4 \
(0x00C0U) /*!< 1 out of 4 for NFC-V setting in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_BITRATE_1OF256 \
(0x00D0U) /*!< 1 out of 256 for NFC-V setting in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_NO_DIRECTION \
(0x0000U) /*!< No direction setting in Analog Conf ID (Chip Specific only) */
#define RFAL_ANALOG_CONFIG_TX \
(0x0001U) /*!< Transmission bit setting in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_RX \
(0x0002U) /*!< Reception bit setting in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_ANTICOL \
(0x0003U) /*!< Anticollision setting in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_DPO \
(0x0004U) /*!< DPO setting in Analog Configuration ID */
#define RFAL_ANALOG_CONFIG_CHIP_INIT \
(0x0000U) /*!< Chip-Specific event: Startup;Reset;Initialize */
#define RFAL_ANALOG_CONFIG_CHIP_DEINIT \
(0x0001U) /*!< Chip-Specific event: Deinitialize */
#define RFAL_ANALOG_CONFIG_CHIP_FIELD_ON \
(0x0002U) /*!< Chip-Specific event: Field On */
#define RFAL_ANALOG_CONFIG_CHIP_FIELD_OFF \
(0x0003U) /*!< Chip-Specific event: Field Off */
#define RFAL_ANALOG_CONFIG_CHIP_WAKEUP_ON \
(0x0004U) /*!< Chip-Specific event: Wake-up On */
#define RFAL_ANALOG_CONFIG_CHIP_WAKEUP_OFF \
(0x0005U) /*!< Chip-Specific event: Wake-up Off */
#define RFAL_ANALOG_CONFIG_CHIP_LISTEN_ON \
(0x0006U) /*!< Chip-Specific event: Listen On */
#define RFAL_ANALOG_CONFIG_CHIP_LISTEN_OFF \
(0x0007U) /*!< Chip-Specific event: Listen Off */
#define RFAL_ANALOG_CONFIG_CHIP_POLL_COMMON \
(0x0008U) /*!< Chip-Specific event: Poll common */
#define RFAL_ANALOG_CONFIG_CHIP_LISTEN_COMMON \
(0x0009U) /*!< Chip-Specific event: Listen common */
#define RFAL_ANALOG_CONFIG_CHIP_LOWPOWER_ON \
(0x000AU) /*!< Chip-Specific event: Low Power On */
#define RFAL_ANALOG_CONFIG_CHIP_LOWPOWER_OFF \
(0x000BU) /*!< Chip-Specific event: Low Power Off */
#define RFAL_ANALOG_CONFIG_UPDATE_LAST \
(0x00U) /*!< Value indicating Last configuration set during update */
#define RFAL_ANALOG_CONFIG_UPDATE_MORE \
(0x01U) /*!< Value indicating More configuration set coming during update */
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
#define RFAL_ANALOG_CONFIG_ID_GET_POLL_LISTEN(id) \
(RFAL_ANALOG_CONFIG_POLL_LISTEN_MODE_MASK & (id)) /*!< Check if id indicates Listen mode */
#define RFAL_ANALOG_CONFIG_ID_GET_TECH(id) \
(RFAL_ANALOG_CONFIG_TECH_MASK & (id)) /*!< Get the technology of Configuration ID */
#define RFAL_ANALOG_CONFIG_ID_IS_CHIP(id) \
(RFAL_ANALOG_CONFIG_TECH_MASK & (id)) /*!< Check if ID indicates Chip-specific */
#define RFAL_ANALOG_CONFIG_ID_IS_NFCA(id) \
(RFAL_ANALOG_CONFIG_TECH_NFCA & (id)) /*!< Check if ID indicates NFC-A */
#define RFAL_ANALOG_CONFIG_ID_IS_NFCB(id) \
(RFAL_ANALOG_CONFIG_TECH_NFCB & (id)) /*!< Check if ID indicates NFC-B */
#define RFAL_ANALOG_CONFIG_ID_IS_NFCF(id) \
(RFAL_ANALOG_CONFIG_TECH_NFCF & (id)) /*!< Check if ID indicates NFC-F */
#define RFAL_ANALOG_CONFIG_ID_IS_AP2P(id) \
(RFAL_ANALOG_CONFIG_TECH_AP2P & (id)) /*!< Check if ID indicates AP2P */
#define RFAL_ANALOG_CONFIG_ID_IS_NFCV(id) \
(RFAL_ANALOG_CONFIG_TECH_NFCV & (id)) /*!< Check if ID indicates NFC-V */
#define RFAL_ANALOG_CONFIG_ID_GET_BITRATE(id) \
(RFAL_ANALOG_CONFIG_BITRATE_MASK & (id)) /*!< Get Bitrate of Configuration ID */
#define RFAL_ANALOG_CONFIG_ID_IS_COMMON(id) \
(RFAL_ANALOG_CONFIG_BITRATE_MASK & (id)) /*!< Check if ID indicates common bitrate */
#define RFAL_ANALOG_CONFIG_ID_IS_106(id) \
(RFAL_ANALOG_CONFIG_BITRATE_106 & (id)) /*!< Check if ID indicates 106kbits/s */
#define RFAL_ANALOG_CONFIG_ID_IS_212(id) \
(RFAL_ANALOG_CONFIG_BITRATE_212 & (id)) /*!< Check if ID indicates 212kbits/s */
#define RFAL_ANALOG_CONFIG_ID_IS_424(id) \
(RFAL_ANALOG_CONFIG_BITRATE_424 & (id)) /*!< Check if ID indicates 424kbits/s */
#define RFAL_ANALOG_CONFIG_ID_IS_848(id) \
(RFAL_ANALOG_CONFIG_BITRATE_848 & (id)) /*!< Check if ID indicates 848kbits/s */
#define RFAL_ANALOG_CONFIG_ID_IS_1695(id) \
(RFAL_ANALOG_CONFIG_BITRATE_1695 & (id)) /*!< Check if ID indicates 1695kbits/s */
#define RFAL_ANALOG_CONFIG_ID_IS_3390(id) \
(RFAL_ANALOG_CONFIG_BITRATE_3390 & (id)) /*!< Check if ID indicates 3390kbits/s */
#define RFAL_ANALOG_CONFIG_ID_IS_6780(id) \
(RFAL_ANALOG_CONFIG_BITRATE_6780 & (id)) /*!< Check if ID indicates 6780kbits/s */
#define RFAL_ANALOG_CONFIG_ID_IS_1OF4(id) \
(RFAL_ANALOG_CONFIG_BITRATE_1OF4 & (id)) /*!< Check if ID indicates 1 out of 4 bitrate */
#define RFAL_ANALOG_CONFIG_ID_IS_1OF256(id) \
(RFAL_ANALOG_CONFIG_BITRATE_1OF256 & (id)) /*!< Check if ID indicates 1 out of 256 bitrate */
#define RFAL_ANALOG_CONFIG_ID_GET_DIRECTION(id) \
(RFAL_ANALOG_CONFIG_DIRECTION_MASK & (id)) /*!< Get Direction of Configuration ID */
#define RFAL_ANALOG_CONFIG_ID_IS_TX(id) \
(RFAL_ANALOG_CONFIG_TX & (id)) /*!< Check if id indicates TX */
#define RFAL_ANALOG_CONFIG_ID_IS_RX(id) \
(RFAL_ANALOG_CONFIG_RX & (id)) /*!< Check if id indicates RX */
#define RFAL_ANALOG_CONFIG_CONFIG_NUM(x) \
(sizeof(x) / sizeof((x)[0])) /*!< Get Analog Config number */
/*! Set Analog Config ID value by: Mode, Technology, Bitrate and Direction */
#define RFAL_ANALOG_CONFIG_ID_SET(mode, tech, br, direction) \
(RFAL_ANALOG_CONFIG_ID_GET_POLL_LISTEN(mode) | RFAL_ANALOG_CONFIG_ID_GET_TECH(tech) | \
RFAL_ANALOG_CONFIG_ID_GET_BITRATE(br) | RFAL_ANALOG_CONFIG_ID_GET_DIRECTION(direction))
/*
******************************************************************************
* GLOBAL DATA TYPES
******************************************************************************
*/
typedef uint8_t
rfalAnalogConfigMode; /*!< Polling or Listening Mode of Configuration */
typedef uint8_t
rfalAnalogConfigTech; /*!< Technology of Configuration */
typedef uint8_t
rfalAnalogConfigBitrate; /*!< Bitrate of Configuration */
typedef uint8_t
rfalAnalogConfigDirection; /*!< Transmit/Receive direction of Configuration */
typedef uint8_t
rfalAnalogConfigRegAddr[2]; /*!< Register Address to ST Chip */
typedef uint8_t
rfalAnalogConfigRegMask; /*!< Register Mask Value */
typedef uint8_t
rfalAnalogConfigRegVal; /*!< Register Value */
typedef uint16_t
rfalAnalogConfigId; /*!< Analog Configuration ID */
typedef uint16_t
rfalAnalogConfigOffset; /*!< Analog Configuration offset address in the table */
typedef uint8_t
rfalAnalogConfigNum; /*!< Number of Analog settings for the respective Configuration ID */
/*! Struct that contain the Register-Mask-Value set. Make sure that the whole structure size is even and unaligned! */
typedef struct {
rfalAnalogConfigRegAddr addr; /*!< Register Address */
rfalAnalogConfigRegMask mask; /*!< Register Mask Value */
rfalAnalogConfigRegVal val; /*!< Register Value */
} rfalAnalogConfigRegAddrMaskVal;
/*! Struct that represents the Analog Configs */
typedef struct {
uint8_t id[sizeof(rfalAnalogConfigId)]; /*!< Configuration ID */
rfalAnalogConfigNum num; /*!< Number of Config Sets to follow */
rfalAnalogConfigRegAddrMaskVal regSet[];
/*!< Register-Mask-Value sets */ /* PRQA S 1060 # MISRA 18.7 - Flexible Array Members are the only meaningful way of denoting a variable length input buffer which follows a fixed header structure. */
} rfalAnalogConfig;
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief Initialize the Analog Configuration
*
* Reset the Analog Configuration LUT pointer to reference to default settings.
*
*****************************************************************************
*/
void rfalAnalogConfigInitialize(void);
/*!
*****************************************************************************
* \brief Indicate if the current Analog Configuration Table is complete and ready to be used.
*
* \return true if current Analog Configuration Table is complete and ready to be used.
* \return false if current Analog Configuration Table is incomplete
*
*****************************************************************************
*/
bool rfalAnalogConfigIsReady(void);
/*!
*****************************************************************************
* \brief Write the whole Analog Configuration table in raw format
*
* Writes the Analog Configuration and Look Up Table with the given raw table
*
* NOTE: Function does not check the validity of the given Table contents
*
* \param[in] configTbl: location of config Table to be loaded
* \param[in] configTblSize: size of the config Table to be loaded
*
* \return ERR_NONE : if setting is updated
* \return ERR_PARAM : if configTbl is invalid
* \return ERR_NOMEM : if the given Table is bigger exceeds the max size
* \return ERR_REQUEST : if the update Configuration Id is disabled
*
*****************************************************************************
*/
ReturnCode rfalAnalogConfigListWriteRaw(const uint8_t* configTbl, uint16_t configTblSize);
/*!
*****************************************************************************
* \brief Write the Analog Configuration table with new analog settings.
*
* Writes the Analog Configuration and Look Up Table with the new list of register-mask-value
* and Configuration ID respectively.
*
* NOTE: Function does not check for the validity of the Register Address.
*
* \param[in] more: 0x00 indicates it is last Configuration ID settings;
* 0x01 indicates more Configuration ID setting(s) are coming.
* \param[in] *config: reference to the configuration list of current Configuration ID.
*
* \return ERR_PARAM : if Configuration ID or parameter is invalid
* \return ERR_NOMEM : if LUT is full
* \return ERR_REQUEST : if the update Configuration Id is disabled
* \return ERR_NONE : if setting is updated
*
*****************************************************************************
*/
ReturnCode rfalAnalogConfigListWrite(uint8_t more, const rfalAnalogConfig* config);
/*!
*****************************************************************************
* \brief Read the whole Analog Configuration table in raw format
*
* Reads the whole Analog Configuration Table in raw format
*
* \param[out] tblBuf: location to the buffer to place the Config Table
* \param[in] tblBufLen: length of the buffer to place the Config Table
* \param[out] configTblSize: Config Table size
*
* \return ERR_PARAM : if configTbl or configTblSize is invalid
* \return ERR_NOMEM : if configTblSize is not enough for the whole table
* \return ERR_NONE : if read is successful
*
*****************************************************************************
*/
ReturnCode
rfalAnalogConfigListReadRaw(uint8_t* tblBuf, uint16_t tblBufLen, uint16_t* configTblSize);
/*!
*****************************************************************************
* \brief Read the Analog Configuration table.
*
* Read the Analog Configuration Table
*
* \param[in] configOffset: offset to the next Configuration ID in the List Table to be read.
* \param[out] more: 0x00 indicates it is last Configuration ID settings;
* 0x01 indicates more Configuration ID setting(s) are coming.
* \param[out] config: configuration id, number of configuration sets and register-mask-value sets
* \param[in] numConfig: the remaining configuration settings space available;
*
* \return ERR_NOMEM : if number of Configuration for respective Configuration ID is greater the the remaining configuration setting space available
* \return ERR_NONE : if read is successful
*
*****************************************************************************
*/
ReturnCode rfalAnalogConfigListRead(
rfalAnalogConfigOffset* configOffset,
uint8_t* more,
rfalAnalogConfig* config,
rfalAnalogConfigNum numConfig);
/*!
*****************************************************************************
* \brief Set the Analog settings of indicated Configuration ID.
*
* Update the chip with indicated analog settings of indicated Configuration ID.
*
* \param[in] configId: configuration ID
*
* \return ERR_PARAM if Configuration ID is invalid
* \return ERR_INTERNAL if error updating setting to chip
* \return ERR_NONE if new settings is applied to chip
*
*****************************************************************************
*/
ReturnCode rfalSetAnalogConfig(rfalAnalogConfigId configId);
/*!
*****************************************************************************
* \brief Generates Analog Config mode ID
*
* Converts RFAL mode and bitrate into Analog Config Mode ID.
*
* Update the chip with indicated analog settings of indicated Configuration ID.
*
* \param[in] md: RFAL mode format
* \param[in] br: RFAL bit rate format
* \param[in] dir: Analog Config communication direction
*
* \return Analog Config Mode ID
*
*****************************************************************************
*/
uint16_t rfalAnalogConfigGenModeID(rfalMode md, rfalBitRate br, uint16_t dir);
#endif /* RFAL_ANALOG_CONFIG_H */
/**
* @}
*
* @}
*
* @}
*/
-287
View File
@@ -1,287 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_chip.h
*
* \author Gustavo Patricio
*
* \brief RF Chip specific Layer
*
* \warning This layer, which provides direct access to RF chip, should
* only be used for debug purposes and/or advanced features
*
*
* \addtogroup RFAL
* @{
*
* \addtogroup RFAL-HAL
* \brief RFAL Hardware Abstraction Layer
* @{
*
* \addtogroup Chip
* \brief RFAL RF Chip Module
* @{
*
*/
#ifndef RFAL_CHIP_H
#define RFAL_CHIP_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
#include "st_errno.h"
#include "rfal_rf.h"
/*****************************************************************************
* RF Chip *
*****************************************************************************/
/*!
*****************************************************************************
* \brief Writes a register on the RF Chip
*
* Checks if the given register is valid and if so, writes the value(s)
* on the RF Chip register
*
* \param[in] reg: register address to be written, or the first if len > 1
* \param[in] values: pointer with content to be written on the register(s)
* \param[in] len: number of consecutive registers to be written
*
*
* \return ERR_PARAM : Invalid register or bad request
* \return ERR_NOTSUPP : Feature not supported
* \return ERR_NONE : Write done with no error
*****************************************************************************
*/
ReturnCode rfalChipWriteReg(uint16_t reg, const uint8_t* values, uint8_t len);
/*!
*****************************************************************************
* \brief Reads a register on the RF Chip
*
* Checks if the given register is valid and if so, reads the value(s)
* of the RF Chip register(s)
*
* \param[in] reg: register address to be read, or the first if len > 1
* \param[out] values: pointer where the register(s) read content will be placed
* \param[in] len: number of consecutive registers to be read
*
* \return ERR_PARAM : Invalid register or bad request
* \return ERR_NOTSUPP : Feature not supported
* \return ERR_NONE : Read done with no error
*****************************************************************************
*/
ReturnCode rfalChipReadReg(uint16_t reg, uint8_t* values, uint8_t len);
/*!
*****************************************************************************
* \brief Change a register on the RF Chip
*
* Change the value of the register bits on the RF Chip Test set in the valueMask.
*
* \param[in] reg: register address to be modified
* \param[in] valueMask: mask value of the register bits to be changed
* \param[in] value: register value to be set
*
* \return ERR_PARAM : Invalid register or bad request
* \return ERR_NOTSUPP : Feature not supported
* \return ERR_OK : Change done with no error
*****************************************************************************
*/
ReturnCode rfalChipChangeRegBits(uint16_t reg, uint8_t valueMask, uint8_t value);
/*!
*****************************************************************************
* \brief Writes a Test register on the RF Chip
*
* Writes the value on the RF Chip Test register
*
* \param[in] reg: register address to be written
* \param[in] value: value to be written on the register
*
*
* \return ERR_PARAM : Invalid register or bad request
* \return ERR_NOTSUPP : Feature not supported
* \return ERR_NONE : Write done with no error
*****************************************************************************
*/
ReturnCode rfalChipWriteTestReg(uint16_t reg, uint8_t value);
/*!
*****************************************************************************
* \brief Reads a Test register on the RF Chip
*
* Reads the value of the RF Chip Test register
*
* \param[in] reg: register address to be read
* \param[out] value: pointer where the register content will be placed
*
* \return ERR_PARAM :Invalid register or bad request
* \return ERR_NOTSUPP : Feature not supported
* \return ERR_NONE : Read done with no error
*****************************************************************************
*/
ReturnCode rfalChipReadTestReg(uint16_t reg, uint8_t* value);
/*!
*****************************************************************************
* \brief Change a Test register on the RF Chip
*
* Change the value of the register bits on the RF Chip Test set in the valueMask.
*
* \param[in] reg: test register address to be modified
* \param[in] valueMask: mask value of the register bits to be changed
* \param[in] value: register value to be set
*
* \return ERR_PARAM : Invalid register or bad request
* \return ERR_NOTSUPP : Feature not supported
* \return ERR_OK : Change done with no error
*****************************************************************************
*/
ReturnCode rfalChipChangeTestRegBits(uint16_t reg, uint8_t valueMask, uint8_t value);
/*!
*****************************************************************************
* \brief Execute command on the RF Chip
*
* Checks if the given command is valid and if so, executes it on
* the RF Chip
*
* \param[in] cmd: direct command to be executed
*
* \return ERR_PARAM : Invalid command or bad request
* \return ERR_NOTSUPP : Feature not supported
* \return ERR_NONE : Direct command executed with no error
*****************************************************************************
*/
ReturnCode rfalChipExecCmd(uint16_t cmd);
/*!
*****************************************************************************
* \brief Set RFO
*
* Sets the RFO value to be used when the field is on (unmodulated/active)
*
* \param[in] rfo : the RFO value to be used
*
* \return ERR_IO : Internal error
* \return ERR_NOTSUPP : Feature not supported
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalChipSetRFO(uint8_t rfo);
/*!
*****************************************************************************
* \brief Get RFO
*
* Gets the RFO value used used when the field is on (unmodulated/active)
*
* \param[out] result : the current RFO value
*
* \return ERR_IO : Internal error
* \return ERR_NOTSUPP : Feature not supported
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalChipGetRFO(uint8_t* result);
/*!
*****************************************************************************
* \brief Measure Amplitude
*
* Measures the RF Amplitude
*
* \param[out] result : result of RF measurement
*
* \return ERR_IO : Internal error
* \return ERR_NOTSUPP : Feature not supported
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalChipMeasureAmplitude(uint8_t* result);
/*!
*****************************************************************************
* \brief Measure Phase
*
* Measures the Phase
*
* \param[out] result : result of Phase measurement
*
* \return ERR_IO : Internal error
* \return ERR_NOTSUPP : Feature not supported
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalChipMeasurePhase(uint8_t* result);
/*!
*****************************************************************************
* \brief Measure Capacitance
*
* Measures the Capacitance
*
* \param[out] result : result of Capacitance measurement
*
* \return ERR_IO : Internal error
* \return ERR_NOTSUPP : Feature not supported
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalChipMeasureCapacitance(uint8_t* result);
/*!
*****************************************************************************
* \brief Measure Power Supply
*
* Measures the Power Supply
*
* \param[in] param : measurement parameter (chip specific)
* \param[out] result : result of the measurement
*
* \return ERR_IO : Internal error
* \return ERR_NOTSUPP : Feature not supported
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalChipMeasurePowerSupply(uint8_t param, uint8_t* result);
#endif /* RFAL_CHIP_H */
/**
* @}
*
* @}
*
* @}
*/
-74
View File
@@ -1,74 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_crc.h
*
* \author Ulrich Herrmann
*
* \brief CRC calculation module
*
*/
/*!
*
*/
#ifndef RFAL_CRC_H_
#define RFAL_CRC_H_
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief Calculate CRC according to CCITT standard.
*
* This function takes \a length bytes from \a buf and calculates the CRC
* for this data. The result is returned.
* \note This implementation calculates the CRC with LSB first, i.e. all
* bytes are "read" from right to left.
*
* \param[in] preloadValue : Initial value of CRC calculation.
* \param[in] buf : buffer to calculate the CRC for.
* \param[in] length : size of the buffer.
*
* \return 16 bit long crc value.
*
*****************************************************************************
*/
extern uint16_t rfalCrcCalculateCcitt(uint16_t preloadValue, const uint8_t* buf, uint16_t length);
#endif /* RFAL_CRC_H_ */
-207
View File
@@ -1,207 +0,0 @@
/******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* $Revision: $
* LANGUAGE: ISO C99
*/
/*! \file rfal_dpo.h
*
* \author Martin Zechleitner
*
* \brief Dynamic Power adjustment
*
* This module provides an interface to perform the power adjustment dynamically
*
*
* \addtogroup RFAL
* @{
*
* \addtogroup RFAL-HAL
* \brief RFAL Hardware Abstraction Layer
* @{
*
* \addtogroup DPO
* \brief RFAL Dynamic Power Module
* @{
*
*/
#ifndef RFAL_DPO_H
#define RFAL_DPO_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
#include "st_errno.h"
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_DPO_TABLE_SIZE_MAX 15U /*!< Max DPO table size */
#define RFAL_DPO_TABLE_PARAMETER 3U /*!< DPO table Parameter length */
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
/*! DPO table entry struct */
typedef struct {
uint8_t rfoRes; /*!< Setting for the resistance level of the RFO */
uint8_t inc; /*!< Threshold for incrementing the output power */
uint8_t dec; /*!< Threshold for decrementing the output power */
} rfalDpoEntry;
/*! Function pointer to method doing the reference measurement */
typedef ReturnCode (*rfalDpoMeasureFunc)(uint8_t*);
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief Initialize dynamic power table
*
* This function sets the internal dynamic power table to the default
* values stored in rfal_DpoTbl.h
*
*****************************************************************************
*/
void rfalDpoInitialize(void);
/*!
*****************************************************************************
* \brief Set the measurement method
*
* This function sets the measurement method used for reference measurement.
* Based on the measurement the power will then be adjusted
*
* \param[in] dpoMeasureFunc: callback of measurement function
*
*****************************************************************************
*/
void rfalDpoSetMeasureCallback(rfalDpoMeasureFunc dpoMeasureFunc);
/*!
*****************************************************************************
* \brief Write dynamic power table
*
* Load the dynamic power table
*
* \param[in] powerTbl: location of power Table to be loaded
* \param[in] powerTblEntries: number of entries of the power Table to be loaded
*
* \return ERR_NONE : No error
* \return ERR_PARAM : if configTbl is invalid
* \return ERR_NOMEM : if the given Table is bigger exceeds the max size
*****************************************************************************
*/
ReturnCode rfalDpoTableWrite(rfalDpoEntry* powerTbl, uint8_t powerTblEntries);
/*!
*****************************************************************************
* \brief Dynamic power table Read
*
* Read the dynamic power table
*
* \param[out] tblBuf: location to the rfalDpoEntry[] to place the Table
* \param[in] tblBufEntries: number of entries available in tblBuf to place the power Table
* \param[out] tableEntries: returned number of entries actually written into tblBuf
*
* \return ERR_NONE : No error
* \return ERR_PARAM : if configTbl is invalid or parameters are invalid
*****************************************************************************
*/
ReturnCode rfalDpoTableRead(rfalDpoEntry* tblBuf, uint8_t tblBufEntries, uint8_t* tableEntries);
/*!
*****************************************************************************
* \brief Dynamic power adjust
*
* It measures the current output and adjusts the power accordingly to
* the dynamic power table
*
* \return ERR_NONE : No error
* \return ERR_PARAM : if configTbl is invalid or parameters are invalid
* \return ERR_WRONG_STATE : if the current state is valid for DPO Adjustment
*****************************************************************************
*/
ReturnCode rfalDpoAdjust(void);
/*!
*****************************************************************************
* \brief Get Current Dynamic power table entry
*
* Return current used DPO power table entry settings
*
* \return ERR_NONE : Current DpoEntry. This includes d_res, inc and dec
*
*****************************************************************************
*/
rfalDpoEntry* rfalDpoGetCurrentTableEntry(void);
/*!
*****************************************************************************
* \brief Dynamic power set enabled state
*
* \param[in] enable: new active state
*
* Set state to enable or disable the Dynamic power adjustment
*
*****************************************************************************
*/
void rfalDpoSetEnabled(bool enable);
/*!
*****************************************************************************
* \brief Get the Dynamic power enabled state
*
* Get state of the Dynamic power adjustment
*
* \return true : enabled
* \return false : disabled
*****************************************************************************
*/
bool rfalDpoIsEnabled(void);
#endif /* RFAL_DPO_H */
/**
* @}
*
* @}
*
* @}
*/
-206
View File
@@ -1,206 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_iso15693_2.h
*
* \author Ulrich Herrmann
*
* \brief Implementation of ISO-15693-2
*
*/
/*!
*
*/
#ifndef RFAL_ISO_15693_2_H
#define RFAL_ISO_15693_2_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
#include "st_errno.h"
/*
******************************************************************************
* GLOBAL DATATYPES
******************************************************************************
*/
/*! Enum holding possible VCD codings */
typedef enum { ISO15693_VCD_CODING_1_4, ISO15693_VCD_CODING_1_256 } iso15693VcdCoding_t;
/*! Enum holding possible VICC datarates */
/*! Configuration parameter used by #iso15693PhyConfigure */
typedef struct {
iso15693VcdCoding_t coding; /*!< desired VCD coding */
uint32_t
speedMode; /*!< 0: normal mode, 1: 2^1 = x2 Fast mode, 2 : 2^2 = x4 mode, 3 : 2^3 = x8 mode - all rx pulse numbers and times are divided by 1,2,4,8 */
} iso15693PhyConfig_t;
/*! Parameters how the stream mode should work */
struct iso15693StreamConfig {
uint8_t useBPSK; /*!< 0: subcarrier, 1:BPSK */
uint8_t din; /*!< the divider for the in subcarrier frequency: fc/2^din */
uint8_t dout; /*!< the divider for the in subcarrier frequency fc/2^dout */
uint8_t report_period_length; /*!< the length of the reporting period 2^report_period_length*/
};
/*
******************************************************************************
* GLOBAL CONSTANTS
******************************************************************************
*/
#define ISO15693_REQ_FLAG_TWO_SUBCARRIERS \
0x01U /*!< Flag indication that communication uses two subcarriers */
#define ISO15693_REQ_FLAG_HIGH_DATARATE \
0x02U /*!< Flag indication that communication uses high bitrate */
#define ISO15693_MASK_FDT_LISTEN \
(65) /*!< t1min = 308,2us = 4192/fc = 65.5 * 64/fc */
/*! t1max = 323,3us = 4384/fc = 68.5 * 64/fc
* 12 = 768/fc unmodulated time of single subcarrior SoF */
#define ISO15693_FWT (69 + 12)
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief Initialize the ISO15693 phy
*
* \param[in] config : ISO15693 phy related configuration (See #iso15693PhyConfig_t)
* \param[out] needed_stream_config : return a pointer to the stream config
* needed for this iso15693 config. To be used for configure RF chip.
*
* \return ERR_IO : Error during communication.
* \return ERR_NONE : No error.
*
*****************************************************************************
*/
extern ReturnCode iso15693PhyConfigure(
const iso15693PhyConfig_t* config,
const struct iso15693StreamConfig** needed_stream_config);
/*!
*****************************************************************************
* \brief Return current phy configuration
*
* This function returns current Phy configuration previously
* set by #iso15693PhyConfigure
*
* \param[out] config : ISO15693 phy configuration.
*
* \return ERR_NONE : No error.
*
*****************************************************************************
*/
extern ReturnCode iso15693PhyGetConfiguration(iso15693PhyConfig_t* config);
/*!
*****************************************************************************
* \brief Code an ISO15693 compatible frame
*
* This function takes \a length bytes from \a buffer, perform proper
* encoding and sends out the frame to the ST25R391x.
*
* \param[in] buffer : data to send, modified to adapt flags.
* \param[in] length : number of bytes to send.
* \param[in] sendCrc : If set to true, CRC is appended to the frame
* \param[in] sendFlags: If set to true, flag field is sent according to
* ISO15693.
* \param[in] picopassMode : If set to true, the coding will be according to Picopass
* \param[out] subbit_total_length : Return the complete bytes which need to
* be send for the current coding
* \param[in,out] offset : Set to 0 for first transfer, function will update it to
point to next byte to be coded
* \param[out] outbuf : buffer where the function will store the coded subbit stream
* \param[out] outBufSize : the size of the output buffer
* \param[out] actOutBufSize : the amount of data stored into the buffer at this call
*
* \return ERR_IO : Error during communication.
* \return ERR_AGAIN : Data was not coded all the way. Call function again with a new/emptied buffer
* \return ERR_NO_MEM : In case outBuf is not big enough. Needs to have at
least 5 bytes for 1of4 coding and 65 bytes for 1of256 coding
* \return ERR_NONE : No error.
*
*****************************************************************************
*/
extern ReturnCode iso15693VCDCode(
uint8_t* buffer,
uint16_t length,
bool sendCrc,
bool sendFlags,
bool picopassMode,
uint16_t* subbit_total_length,
uint16_t* offset,
uint8_t* outbuf,
uint16_t outBufSize,
uint16_t* actOutBufSize);
/*!
*****************************************************************************
* \brief Receive an ISO15693 compatible frame
*
* This function receives an ISO15693 frame from the ST25R391x, decodes the frame
* and writes the raw data to \a buffer.
* \note Buffer needs to be big enough to hold CRC also (+2 bytes)
*
* \param[in] inBuf : buffer with the hamming coded stream to be decoded
* \param[in] inBufLen : number of bytes to decode (=length of buffer).
* \param[out] outBuf : buffer where received data shall be written to.
* \param[in] outBufLen : Length of output buffer, should be approx twice the size of inBuf
* \param[out] outBufPos : The number of decoded bytes. Could be used in
* extended implementation to allow multiple calls
* \param[out] bitsBeforeCol : in case of ERR_COLLISION this value holds the
* number of bits in the current byte where the collision happened.
* \param[in] ignoreBits : number of bits in the beginning where collisions will be ignored
* \param[in] picopassMode : if set to true, the decoding will be according to Picopass
*
* \return ERR_COLLISION : collision occurred, data incorrect
* \return ERR_CRC : CRC error, data incorrect
* \return ERR_TIMEOUT : timeout waiting for data.
* \return ERR_NONE : No error.
*
*****************************************************************************
*/
extern ReturnCode iso15693VICCDecode(
const uint8_t* inBuf,
uint16_t inBufLen,
uint8_t* outBuf,
uint16_t outBufLen,
uint16_t* outBufPos,
uint16_t* bitsBeforeCol,
uint16_t ignoreBits,
bool picopassMode);
#endif /* RFAL_ISO_15693_2_H */
File diff suppressed because it is too large Load Diff
-425
View File
@@ -1,425 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_nfc.h
*
* \brief RFAL NFC device
*
* This module provides the required features to behave as an NFC Poller
* or Listener device. It grants an easy to use interface for the following
* activities: Technology Detection, Collision Resolution, Activation,
* Data Exchange, and Deactivation
*
* This layer is influenced by (but not fully aligned with) the NFC Forum
* specifications, in particular: Activity 2.0 and NCI 2.0
*
*
*
* \addtogroup RFAL
* @{
*
* \addtogroup RFAL-HL
* \brief RFAL Higher Layer
* @{
*
* \addtogroup NFC
* \brief RFAL NFC Device
* @{
*
*/
#ifndef RFAL_NFC_H
#define RFAL_NFC_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
#include "st_errno.h"
#include "rfal_rf.h"
#include "rfal_nfca.h"
#include "rfal_nfcb.h"
#include "rfal_nfcf.h"
#include "rfal_nfcv.h"
#include "rfal_st25tb.h"
#include "rfal_nfcDep.h"
#include "rfal_isoDep.h"
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_NFC_TECH_NONE 0x0000U /*!< No technology */
#define RFAL_NFC_POLL_TECH_A 0x0001U /*!< NFC-A technology Flag */
#define RFAL_NFC_POLL_TECH_B 0x0002U /*!< NFC-B technology Flag */
#define RFAL_NFC_POLL_TECH_F 0x0004U /*!< NFC-F technology Flag */
#define RFAL_NFC_POLL_TECH_V 0x0008U /*!< NFC-V technology Flag */
#define RFAL_NFC_POLL_TECH_AP2P 0x0010U /*!< AP2P technology Flag */
#define RFAL_NFC_POLL_TECH_ST25TB 0x0020U /*!< ST25TB technology Flag */
#define RFAL_NFC_LISTEN_TECH_A 0x1000U /*!< NFC-V technology Flag */
#define RFAL_NFC_LISTEN_TECH_B 0x2000U /*!< NFC-V technology Flag */
#define RFAL_NFC_LISTEN_TECH_F 0x4000U /*!< NFC-V technology Flag */
#define RFAL_NFC_LISTEN_TECH_AP2P 0x8000U /*!< NFC-V technology Flag */
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
/*! Checks if a device is currently activated */
#define rfalNfcIsDevActivated(st) \
(((st) >= RFAL_NFC_STATE_ACTIVATED) && ((st) < RFAL_NFC_STATE_DEACTIVATION))
/*! Checks if a device is in discovery */
#define rfalNfcIsInDiscovery(st) \
(((st) >= RFAL_NFC_STATE_START_DISCOVERY) && ((st) < RFAL_NFC_STATE_ACTIVATED))
/*! Checks if remote device is in Poll mode */
#define rfalNfcIsRemDevPoller(tp) \
(((tp) >= RFAL_NFC_POLL_TYPE_NFCA) && ((tp) <= RFAL_NFC_POLL_TYPE_AP2P))
/*! Checks if remote device is in Listen mode */
#define rfalNfcIsRemDevListener(tp) \
(((int16_t)(tp) >= (int16_t)RFAL_NFC_LISTEN_TYPE_NFCA) && ((tp) <= RFAL_NFC_LISTEN_TYPE_AP2P))
/*
******************************************************************************
* GLOBAL ENUMS
******************************************************************************
*/
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
/*! Main state */
typedef enum {
RFAL_NFC_STATE_NOTINIT = 0, /*!< Not Initialized state */
RFAL_NFC_STATE_IDLE = 1, /*!< Initialize state */
RFAL_NFC_STATE_START_DISCOVERY = 2, /*!< Start Discovery loop state */
RFAL_NFC_STATE_WAKEUP_MODE = 3, /*!< Wake-Up state */
RFAL_NFC_STATE_POLL_TECHDETECT = 10, /*!< Technology Detection state */
RFAL_NFC_STATE_POLL_COLAVOIDANCE = 11, /*!< Collision Avoidance state */
RFAL_NFC_STATE_POLL_SELECT = 12, /*!< Wait for Selection state */
RFAL_NFC_STATE_POLL_ACTIVATION = 13, /*!< Activation state */
RFAL_NFC_STATE_LISTEN_TECHDETECT = 20, /*!< Listen Tech Detect */
RFAL_NFC_STATE_LISTEN_COLAVOIDANCE = 21, /*!< Listen Collision Avoidance */
RFAL_NFC_STATE_LISTEN_ACTIVATION = 22, /*!< Listen Activation state */
RFAL_NFC_STATE_LISTEN_SLEEP = 23, /*!< Listen Sleep state */
RFAL_NFC_STATE_ACTIVATED = 30, /*!< Activated state */
RFAL_NFC_STATE_DATAEXCHANGE = 31, /*!< Data Exchange Start state */
RFAL_NFC_STATE_DATAEXCHANGE_DONE = 33, /*!< Data Exchange terminated */
RFAL_NFC_STATE_DEACTIVATION = 34 /*!< Deactivation state */
} rfalNfcState;
/*! Device type */
typedef enum {
RFAL_NFC_LISTEN_TYPE_NFCA = 0, /*!< NFC-A Listener device type */
RFAL_NFC_LISTEN_TYPE_NFCB = 1, /*!< NFC-B Listener device type */
RFAL_NFC_LISTEN_TYPE_NFCF = 2, /*!< NFC-F Listener device type */
RFAL_NFC_LISTEN_TYPE_NFCV = 3, /*!< NFC-V Listener device type */
RFAL_NFC_LISTEN_TYPE_ST25TB = 4, /*!< ST25TB Listener device type */
RFAL_NFC_LISTEN_TYPE_AP2P = 5, /*!< AP2P Listener device type */
RFAL_NFC_POLL_TYPE_NFCA = 10, /*!< NFC-A Poller device type */
RFAL_NFC_POLL_TYPE_NFCB = 11, /*!< NFC-B Poller device type */
RFAL_NFC_POLL_TYPE_NFCF = 12, /*!< NFC-F Poller device type */
RFAL_NFC_POLL_TYPE_NFCV = 13, /*!< NFC-V Poller device type */
RFAL_NFC_POLL_TYPE_AP2P = 15 /*!< AP2P Poller device type */
} rfalNfcDevType;
/*! Device interface */
typedef enum {
RFAL_NFC_INTERFACE_RF = 0, /*!< RF Frame interface */
RFAL_NFC_INTERFACE_ISODEP = 1, /*!< ISO-DEP interface */
RFAL_NFC_INTERFACE_NFCDEP = 2 /*!< NFC-DEP interface */
} rfalNfcRfInterface;
/*! Device struct containing all its details */
typedef struct {
rfalNfcDevType type; /*!< Device's type */
union { /* PRQA S 0750 # MISRA 19.2 - Members of the union will not be used concurrently, only one technology at a time */
rfalNfcaListenDevice nfca; /*!< NFC-A Listen Device instance */
rfalNfcbListenDevice nfcb; /*!< NFC-B Listen Device instance */
rfalNfcfListenDevice nfcf; /*!< NFC-F Listen Device instance */
rfalNfcvListenDevice nfcv; /*!< NFC-V Listen Device instance */
rfalSt25tbListenDevice st25tb; /*!< ST25TB Listen Device instance*/
} dev; /*!< Device's instance */
uint8_t* nfcid; /*!< Device's NFCID */
uint8_t nfcidLen; /*!< Device's NFCID length */
rfalNfcRfInterface rfInterface; /*!< Device's interface */
union { /* PRQA S 0750 # MISRA 19.2 - Members of the union will not be used concurrently, only one protocol at a time */
rfalIsoDepDevice isoDep; /*!< ISO-DEP instance */
rfalNfcDepDevice nfcDep; /*!< NFC-DEP instance */
} proto; /*!< Device's protocol */
} rfalNfcDevice;
/*! Discovery parameters */
typedef struct {
rfalComplianceMode compMode; /*!< Compliance mode to be used */
uint16_t techs2Find; /*!< Technologies to search for */
uint16_t totalDuration; /*!< Duration of a whole Poll + Listen cycle */
uint8_t devLimit; /*!< Max number of devices */
rfalBitRate maxBR; /*!< Max Bit rate to be used for communications */
rfalBitRate nfcfBR; /*!< Bit rate to poll for NFC-F */
uint8_t
nfcid3[RFAL_NFCDEP_NFCID3_LEN]; /*!< NFCID3 to be used on the ATR_REQ/ATR_RES */
uint8_t GB[RFAL_NFCDEP_GB_MAX_LEN]; /*!< General bytes to be used on the ATR-REQ */
uint8_t GBLen; /*!< Length of the General Bytes */
rfalBitRate ap2pBR; /*!< Bit rate to poll for AP2P */
rfalLmConfPA lmConfigPA; /*!< Configuration for Passive Listen mode NFC-A */
rfalLmConfPF lmConfigPF; /*!< Configuration for Passive Listen mode NFC-A */
void (*notifyCb)(rfalNfcState st); /*!< Callback to Notify upper layer */
bool wakeupEnabled; /*!< Enable Wake-Up mode before polling */
bool wakeupConfigDefault; /*!< Wake-Up mode default configuration */
rfalWakeUpConfig wakeupConfig; /*!< Wake-Up mode configuration */
bool activate_after_sak; // Set device to Active mode after SAK response
} rfalNfcDiscoverParam;
/*! Buffer union, only one interface is used at a time */
typedef union { /* PRQA S 0750 # MISRA 19.2 - Members of the union will not be used concurrently, only one interface at a time */
uint8_t rfBuf[RFAL_FEATURE_NFC_RF_BUF_LEN]; /*!< RF buffer */
rfalIsoDepApduBufFormat isoDepBuf; /*!< ISO-DEP buffer format (with header/prologue) */
rfalNfcDepPduBufFormat nfcDepBuf; /*!< NFC-DEP buffer format (with header/prologue) */
} rfalNfcBuffer;
/*******************************************************************************/
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief RFAL NFC Worker
*
* It runs the internal state machine and runs the RFAL RF worker.
*****************************************************************************
*/
void rfalNfcWorker(void);
/*!
*****************************************************************************
* \brief RFAL NFC Initialize
*
* It initializes this module and its dependencies
*
* \return ERR_WRONG_STATE : Incorrect state for this operation
* \return ERR_IO : Generic internal error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcInitialize(void);
/*!
*****************************************************************************
* \brief RFAL NFC Discovery
*
* It set the device in Discovery state.
* In discovery it will Poll and/or Listen for the technologies configured,
* and perform Wake-up mode if configured to do so.
*
* The device list passed on disParams must not be empty.
* The number of devices on the list is indicated by the devLimit and shall
* be at >= 1.
*
* \param[in] disParams : discovery configuration parameters
*
* \return ERR_WRONG_STATE : Incorrect state for this operation
* \return ERR_PARAM : Invalid parameters
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcDiscover(const rfalNfcDiscoverParam* disParams);
/*!
*****************************************************************************
* \brief RFAL NFC Get State
*
* It returns the current state
*
* \return rfalNfcState : the current state
*****************************************************************************
*/
rfalNfcState rfalNfcGetState(void);
/*!
*****************************************************************************
* \brief RFAL NFC Get Devices Found
*
* It returns the location of the device list and the number of
* devices found.
*
* \param[out] devList : device list location
* \param[out] devCnt : number of devices found
*
* \return ERR_WRONG_STATE : Incorrect state for this operation
* Discovery still ongoing
* \return ERR_PARAM : Invalid parameters
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcGetDevicesFound(rfalNfcDevice** devList, uint8_t* devCnt);
/*!
*****************************************************************************
* \brief RFAL NFC Get Active Device
*
* It returns the location of the device current Active device
*
* \param[out] dev : device info location
*
* \return ERR_WRONG_STATE : Incorrect state for this operation
* No device activated
* \return ERR_PARAM : Invalid parameters
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcGetActiveDevice(rfalNfcDevice** dev);
/*!
*****************************************************************************
* \brief RFAL NFC Select Device
*
* It selects the device to be activated.
* It shall be called when more than one device has been identified to
* indiacte which device shall be active
*
* \param[in] devIdx : device index to be activated
*
* \return ERR_WRONG_STATE : Incorrect state for this operation
* Not in select state
* \return ERR_PARAM : Invalid parameters
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcSelect(uint8_t devIdx);
/*!
*****************************************************************************
* \brief RFAL NFC Start Data Exchange
*
* After a device has been activated, it starts a data exchange.
* It handles automatically which interface/protocol to be used and acts accordingly.
*
* In Listen mode the first frame/data shall be sent by the Reader/Initiator
* therefore this method must be called first with txDataLen set to zero
* to retrieve the rxData and rcvLen locations.
*
*
* \param[in] txData : data to be transmitted
* \param[in] txDataLen : size of the data to be transmitted
* \param[out] rxData : location of the received data after operation is completed
* \param[out] rvdLen : location of thelength of the received data
* \param[in] fwt : FWT to be used in case of RF interface.
* If ISO-DEP or NFC-DEP interface is used, this will be ignored
*
* \return ERR_WRONG_STATE : Incorrect state for this operation
* \return ERR_PARAM : Invalid parameters
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcDataExchangeStart(
uint8_t* txData,
uint16_t txDataLen,
uint8_t** rxData,
uint16_t** rvdLen,
uint32_t fwt,
uint32_t tx_flag);
ReturnCode rfalNfcDataExchangeCustomStart(
uint8_t* txData,
uint16_t txDataLen,
uint8_t** rxData,
uint16_t** rvdLen,
uint32_t fwt,
uint32_t flags);
/*!
*****************************************************************************
* \brief RFAL NFC Get Data Exchange Status
*
* Gets current Data Exchange status
*
* \return ERR_NONE : Transceive done with no error
* \return ERR_BUSY : Transceive ongoing
* \return ERR_AGAIN : received one chaining block, copy received data
* and continue to call this method to retrieve the
* remaining blocks
* \return ERR_XXXX : Error occurred
* \return ERR_TIMEOUT : No response
* \return ERR_FRAMING : Framing error detected
* \return ERR_PAR : Parity error detected
* \return ERR_CRC : CRC error detected
* \return ERR_LINK_LOSS : Link Loss - External Field is Off
* \return ERR_RF_COLLISION : Collision detected
* \return ERR_IO : Internal error
*****************************************************************************
*/
ReturnCode rfalNfcDataExchangeGetStatus(void);
/*!
*****************************************************************************
* \brief RFAL NFC Deactivate
*
* It triggers the deactivation procedure to terminate communications with
* remote device. At the end the field will be turned off.
*
* \param[in] discovery : TRUE if after deactivation go back into discovery
* : FALSE if after deactivation remain in idle
*
* \return ERR_WRONG_STATE : Incorrect state for this operation
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcDeactivate(bool discovery);
#endif /* RFAL_NFC_H */
/**
* @}
*
* @}
*
* @}
*/
-830
View File
@@ -1,830 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_nfcDep.h
*
* \author Gustavo Patricio
*
* \brief Implementation of NFC-DEP protocol
*
* NFC-DEP is also known as NFCIP - Near Field Communication
* Interface and Protocol
*
* This implementation was based on the following specs:
* - NFC Forum Digital 1.1
* - ECMA 340 3rd Edition 2013
*
*
* \addtogroup RFAL
* @{
*
* \addtogroup RFAL-AL
* \brief RFAL Abstraction Layer
* @{
*
* \addtogroup NFC-DEP
* \brief RFAL NFC-DEP Module
* @{
*/
#ifndef RFAL_NFCDEP_H_
#define RFAL_NFCDEP_H_
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
#include "st_errno.h"
#include "rfal_rf.h"
/*
******************************************************************************
* ENABLE SWITCH
******************************************************************************
*/
#ifndef RFAL_FEATURE_NFC_DEP
#define RFAL_FEATURE_NFC_DEP \
false /*!< NFC-DEP module configuration missing. Disabled by default */
#endif
/* If module is disabled remove the need for the user to set lengths */
#if !RFAL_FEATURE_NFC_DEP
#undef RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN
#undef RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN
#define RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN 1U /*!< NFC-DEP Block/Payload length, set to "none" */
#define RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN 1U /*!< NFC-DEP PDU length, set to "none" */
#endif /* !RFAL_FEATURE_NFC_DEP */
/*
******************************************************************************
* DEFINES
******************************************************************************
*/
#define RFAL_NFCDEP_FRAME_SIZE_MAX_LEN \
254U /*!< Maximum Frame Size Digital 2.0 Table 90 */
#define RFAL_NFCDEP_DEPREQ_HEADER_LEN \
5U /*!< DEP_REQ header length: CMD_TYPE + CMD_CMD + PBF + DID + NAD */
/*! Length NFCIP DEP REQ or RES header (incl LEN) */
#define RFAL_NFCDEP_DEP_HEADER \
(RFAL_NFCDEP_LEN_LEN + RFAL_NFCDEP_CMDTYPE_LEN + RFAL_NFCDEP_CMD_LEN + RFAL_NFCDEP_DEP_PFB_LEN)
#define RFAL_NFCDEP_HEADER \
(RFAL_NFCDEP_CMDTYPE_LEN + RFAL_NFCDEP_CMD_LEN) /*!< NFCIP header length */
#define RFAL_NFCDEP_SB_LEN \
1U /*!< SB length on NFCIP fram for NFC-A */
#define RFAL_NFCDEP_LEN_LEN \
1U /*!< LEN length on NFCIP frame */
#define RFAL_NFCDEP_CMDTYPE_LEN \
1U /*!< Length of the cmd type (REQ | RES) on NFCIP frame */
#define RFAL_NFCDEP_CMD_LEN \
1U /*!< Length of the cmd on NFCIP frame */
#define RFAL_NFCDEP_DID_LEN \
1U /*!< Length of did on NFCIP frame */
#define RFAL_NFCDEP_DEP_PFB_LEN \
1U /*!< Length of the PFB field on NFCIP frame */
#define RFAL_NFCDEP_DSL_RLS_LEN_NO_DID \
(RFAL_NFCDEP_LEN_LEN + RFAL_NFCDEP_CMDTYPE_LEN + \
RFAL_NFCDEP_CMD_LEN) /*!< Length of DSL_REQ and RLS_REQ with no DID */
#define RFAL_NFCDEP_DSL_RLS_LEN_DID \
(RFAL_NFCDEP_DSL_RLS_LEN_NO_DID + \
RFAL_NFCDEP_DID_LEN) /*!< Length of DSL_REQ and RLS_REQ with DID */
#define RFAL_NFCDEP_FS_VAL_MIN \
64U /*!< Minimum LR value */
#define RFAL_NFCDEP_LR_VAL_MASK \
0x03U /*!< Bit mask for a LR value */
#define RFAL_NFCDEP_PP_LR_MASK \
0x30U /*!< Bit mask for LR value in PP byte on a ATR REQ/RES */
#define RFAL_NFCDEP_PP_LR_SHIFT \
4U /*!< Position of LR value in PP byte on a ATR REQ/RES */
#define RFAL_NFCDEP_DID_MAX \
14U /*!< Max DID value Digital 14.6.2.3 */
#define RFAL_NFCDEP_DID_KEEP \
0xFFU /*!< Keep DID value already configured */
#define RFAL_NFCDEP_DID_NO \
0x00U /*!< No DID shall be used */
#define RFAL_NFCDEP_NAD_NO \
0x00U /*!< No NAD shall be used */
#define RFAL_NFCDEP_OPER_RTOX_REQ_DIS \
0x01U /*!< Operation config: RTOX REQ disable */
#define RFAL_NFCDEP_OPER_RTOX_REQ_EN \
0x00U /*!< Operation config: RTOX REQ enable */
#define RFAL_NFCDEP_OPER_ATN_DIS \
0x00U /*!< Operation config: ATN disable */
#define RFAL_NFCDEP_OPER_ATN_EN \
0x02U /*!< Operation config: ATN enable */
#define RFAL_NFCDEP_OPER_EMPTY_DEP_DIS \
0x04U /*!< Operation config: empty DEPs disable */
#define RFAL_NFCDEP_OPER_EMPTY_DEP_EN \
0x00U /*!< Operation config: empty DEPs enable */
#define RFAL_NFCDEP_OPER_FULL_MI_DIS \
0x00U /*!< Operation config: full chaining DEPs disable */
#define RFAL_NFCDEP_OPER_FULL_MI_EN \
0x08U /*!< Operation config: full chaining DEPs enable */
#define RFAL_NFCDEP_BRS_MAINTAIN \
0xC0U /*!< Value signalling that BR is to be maintained (no PSL) */
#define RFAL_NFCDEP_BRS_Dx_MASK \
0x07U /*!< Value signalling that BR is to be maintained (no PSL) */
#define RFAL_NFCDEP_BRS_DSI_POS \
3U /*!< Value signalling that BR is to be maintained (no PSL) */
#define RFAL_NFCDEP_WT_DELTA \
(16U - RFAL_NFCDEP_WT_DELTA_ADJUST) /*!< NFC-DEP dWRT (adjusted) Digital 2.0 B.10 */
#define RFAL_NFCDEP_WT_DELTA_ADJUST \
4U /*!< dWRT value adjustment */
#define RFAL_NFCDEP_ATR_REQ_NFCID3_POS \
2U /*!< NFCID3 offset in ATR_REQ frame */
#define RFAL_NFCDEP_NFCID3_LEN \
10U /*!< NFCID3 Length */
#define RFAL_NFCDEP_LEN_MIN \
3U /*!< Minimum length byte LEN value */
#define RFAL_NFCDEP_LEN_MAX \
255U /*!< Maximum length byte LEN value */
#define RFAL_NFCDEP_ATRRES_HEADER_LEN \
2U /*!< ATR RES Header Len: CmdType: 0xD5 + Cod: 0x01 */
#define RFAL_NFCDEP_ATRRES_MIN_LEN \
17U /*!< Minimum length for an ATR RES */
#define RFAL_NFCDEP_ATRRES_MAX_LEN \
64U /*!< Maximum length for an ATR RES Digital 1.0 14.6.1 */
#define RFAL_NFCDEP_ATRREQ_MIN_LEN \
16U /*!< Minimum length for an ATR REQ */
#define RFAL_NFCDEP_ATRREQ_MAX_LEN \
RFAL_NFCDEP_ATRRES_MAX_LEN /*!< Maximum length for an ATR REQ Digital 1.0 14.6.1 */
#define RFAL_NFCDEP_GB_MAX_LEN \
(RFAL_NFCDEP_ATRREQ_MAX_LEN - \
RFAL_NFCDEP_ATRREQ_MIN_LEN) /*!< Maximum length the General Bytes on ATR Digital 1.1 16.6.3 */
#define RFAL_NFCDEP_WT_INI_DEFAULT \
RFAL_NFCDEP_WT_INI_MAX /*!< WT Initiator default value Digital 1.0 14.6.3.8 */
#define RFAL_NFCDEP_WT_INI_MIN 0U /*!< WT Initiator minimum value Digital 1.0 14.6.3.8 */
#define RFAL_NFCDEP_WT_INI_MAX 14U /*!< WT Initiator maximum value Digital 1.0 14.6.3.8 A.10 */
#define RFAL_NFCDEP_RWT_INI_MAX \
rfalNfcDepWT2RWT(RFAL_NFCDEP_WT_INI_MAX) /*!< RWT Initiator maximum value */
#define RFAL_NFCDEP_WT_TRG_MAX_D10 8U /*!< WT target max Digital 1.0 14.6.3.8 A.10 */
#define RFAL_NFCDEP_WT_TRG_MAX_D11 14U /*!< WT target max Digital 1.1 16.6.3.9 A.9 */
#define RFAL_NFCDEP_WT_TRG_MAX_L13 10U /*!< WT target max [LLCP] 1.3 6.2.1 */
#define RFAL_NFCDEP_WT_TRG_MAX \
RFAL_NFCDEP_WT_TRG_MAX_D11 /*!< WT target max Digital x.x | LLCP x.x */
#define RFAL_NFCDEP_RWT_TRG_MAX \
rfalNfcDepWT2RWT(RFAL_NFCDEP_WT_TRG_MAX) /*!< RWT Initiator maximum value */
/*! Maximum Frame Waiting Time = ((256 * 16/fc)*2^FWImax) = ((256*16/fc)*2^14) = (1048576 / 64)/fc = (100000h*64)/fc */
#define RFAL_NFCDEP_MAX_FWT ((uint32_t)1U << 20)
#define RFAL_NFCDEP_WT_MASK \
0x0FU /*!< Bit mask for the Wait Time value */
#define RFAL_NFCDEP_BR_MASK_106 \
0x01U /*!< Enable mask bit rate 106 */
#define RFAL_NFCDEP_BR_MASK_212 \
0x02U /*!< Enable mask bit rate 242 */
#define RFAL_NFCDEP_BR_MASK_424 \
0x04U /*!< Enable mask bit rate 424 */
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
#define rfalNfcDepWT2RWT(wt) \
((uint32_t)1U \
<< (((uint32_t)(wt)&RFAL_NFCDEP_WT_MASK) + \
12U)) /*!< Converts WT value to RWT (1/fc) */
/*! Returns the BRS value from the given bit rate */
#define rfalNfcDepDx2BRS(br) \
((((uint8_t)(br)&RFAL_NFCDEP_BRS_Dx_MASK) << RFAL_NFCDEP_BRS_DSI_POS) | \
((uint8_t)(br)&RFAL_NFCDEP_BRS_Dx_MASK))
#define rfalNfcDepBRS2DRI(brs) \
(uint8_t)(( \
uint8_t)(brs)&RFAL_NFCDEP_BRS_Dx_MASK) /*!< Returns the DRI value from the given BRS byte */
#define rfalNfcDepBRS2DSI(brs) \
(uint8_t)( \
((uint8_t)(brs) >> RFAL_NFCDEP_BRS_DSI_POS) & \
RFAL_NFCDEP_BRS_Dx_MASK) /*!< Returns the DSI value from the given BRS byte */
#define rfalNfcDepPP2LR(PPx) \
(((uint8_t)(PPx)&RFAL_NFCDEP_PP_LR_MASK) >> \
RFAL_NFCDEP_PP_LR_SHIFT) /*!< Returns the LR value from the given PPx byte */
#define rfalNfcDepLR2PP(LRx) \
(((uint8_t)(LRx) << RFAL_NFCDEP_PP_LR_SHIFT) & \
RFAL_NFCDEP_PP_LR_MASK) /*!< Returns the PP byte with the given LRx value */
/*! Returns the Frame size value from the given LRx value */
#define rfalNfcDepLR2FS(LRx) \
(uint16_t)( \
MIN((RFAL_NFCDEP_FS_VAL_MIN * ((uint16_t)(LRx) + 1U)), RFAL_NFCDEP_FRAME_SIZE_MAX_LEN))
/*!
* Despite DIGITAL 1.0 14.6.2.1 stating that the last two bytes may filled with
* any value, some devices (Samsung Google Nexus) only accept when these are 0 */
#define rfalNfcDepSetNFCID(dst, src, len) \
ST_MEMSET((dst), 0x00, RFAL_NFCDEP_NFCID3_LEN); \
if((len) > 0U) { \
ST_MEMCPY((dst), (src), (len)); \
}
/*
******************************************************************************
* GLOBAL ENUMERATIONS
******************************************************************************
*/
/*! Enumeration of NFC-DEP bit rate in ATR Digital 1.0 Table 93 and 94 */
enum {
RFAL_NFCDEP_Bx_NO_HIGH_BR = 0x00, /*!< Peer supports no high bit rates */
RFAL_NFCDEP_Bx_08_848 = 0x01, /*!< Peer also supports 848 */
RFAL_NFCDEP_Bx_16_1695 = 0x02, /*!< Peer also supports 1695 */
RFAL_NFCDEP_Bx_32_3390 = 0x04, /*!< Peer also supports 3390 */
RFAL_NFCDEP_Bx_64_6780 = 0x08 /*!< Peer also supports 6780 */
};
/*! Enumeration of NFC-DEP bit rate Divider in PSL Digital 1.0 Table 100 */
enum {
RFAL_NFCDEP_Dx_01_106 = RFAL_BR_106, /*!< Divisor D = 1 : bit rate = 106 */
RFAL_NFCDEP_Dx_02_212 = RFAL_BR_212, /*!< Divisor D = 2 : bit rate = 212 */
RFAL_NFCDEP_Dx_04_424 = RFAL_BR_424, /*!< Divisor D = 4 : bit rate = 424 */
RFAL_NFCDEP_Dx_08_848 = RFAL_BR_848, /*!< Divisor D = 8 : bit rate = 848 */
RFAL_NFCDEP_Dx_16_1695 = RFAL_BR_1695, /*!< Divisor D = 16 : bit rate = 1695 */
RFAL_NFCDEP_Dx_32_3390 = RFAL_BR_3390, /*!< Divisor D = 32 : bit rate = 3390 */
RFAL_NFCDEP_Dx_64_6780 = RFAL_BR_6780 /*!< Divisor D = 64 : bit rate = 6780 */
};
/*! Enumeration of NFC-DEP Length Reduction (LR) Digital 1.0 Table 91 */
enum {
RFAL_NFCDEP_LR_64 = 0x00, /*!< Maximum payload size is 64 bytes */
RFAL_NFCDEP_LR_128 = 0x01, /*!< Maximum payload size is 128 bytes */
RFAL_NFCDEP_LR_192 = 0x02, /*!< Maximum payload size is 192 bytes */
RFAL_NFCDEP_LR_254 = 0x03 /*!< Maximum payload size is 254 bytes */
};
/*
******************************************************************************
* GLOBAL DATA TYPES
******************************************************************************
*/
/*! NFC-DEP callback to check if upper layer has deactivation pending */
typedef bool (*rfalNfcDepDeactCallback)(void);
/*! Enumeration of the nfcip communication modes */
typedef enum {
RFAL_NFCDEP_COMM_PASSIVE, /*!< Passive communication mode */
RFAL_NFCDEP_COMM_ACTIVE /*!< Active communication mode */
} rfalNfcDepCommMode;
/*! Enumeration of the nfcip roles */
typedef enum {
RFAL_NFCDEP_ROLE_INITIATOR, /*!< Perform as Initiator */
RFAL_NFCDEP_ROLE_TARGET /*!< Perform as Target */
} rfalNfcDepRole;
/*! Struct that holds all NFCIP configs */
typedef struct {
rfalNfcDepRole role; /*!< Current NFCIP role */
rfalNfcDepCommMode commMode; /*!< Current NFCIP communication mode */
uint8_t oper; /*!< Operation config similar to NCI 1.0 Table 81 */
uint8_t did; /*!< Current Device ID (DID) */
uint8_t nad; /*!< Current Node Addressing (NAD) */
uint8_t bs; /*!< Bit rate in Sending Direction */
uint8_t br; /*!< Bit rate in Receiving Direction */
uint8_t nfcid[RFAL_NFCDEP_NFCID3_LEN]; /*!< Pointer to the NFCID to be used */
uint8_t nfcidLen; /*!< Length of the given NFCID in nfcid */
uint8_t gb[RFAL_NFCDEP_GB_MAX_LEN]; /*!< Pointer General Bytes (GB) to be used */
uint8_t gbLen; /*!< Length of the given GB in gb */
uint8_t lr; /*!< Length Reduction (LR) to be used */
uint8_t to; /*!< Timeout (TO) to be used */
uint32_t fwt; /*!< Frame Waiting Time (FWT) to be used */
uint32_t dFwt; /*!< Delta Frame Waiting Time (dFWT) to be used */
} rfalNfcDepConfigs;
/*! ATR_REQ command Digital 1.1 16.6.2 */
typedef struct {
uint8_t CMD1; /*!< Command format 0xD4 */
uint8_t CMD2; /*!< Command Value */
uint8_t NFCID3[RFAL_NFCDEP_NFCID3_LEN]; /*!< NFCID3 value */
uint8_t DID; /*!< DID */
uint8_t BSi; /*!< Sending Bitrate for Initiator */
uint8_t BRi; /*!< Receiving Bitrate for Initiator */
uint8_t PPi; /*!< Optional Parameters presence indicator */
uint8_t GBi[RFAL_NFCDEP_GB_MAX_LEN]; /*!< General Bytes */
} rfalNfcDepAtrReq;
/*! ATR_RES response Digital 1.1 16.6.3 */
typedef struct {
uint8_t CMD1; /*!< Response Byte 0xD5 */
uint8_t CMD2; /*!< Command Value */
uint8_t NFCID3[RFAL_NFCDEP_NFCID3_LEN]; /*!< NFCID3 value */
uint8_t DID; /*!< DID */
uint8_t BSt; /*!< Sending Bitrate for Initiator */
uint8_t BRt; /*!< Receiving Bitrate for Initiator */
uint8_t TO; /*!< Timeout */
uint8_t PPt; /*!< Optional Parameters presence indicator */
uint8_t GBt[RFAL_NFCDEP_GB_MAX_LEN]; /*!< General Bytes */
} rfalNfcDepAtrRes;
/*! Structure of transmit I-PDU Buffer format from caller */
typedef struct {
uint8_t prologue[RFAL_NFCDEP_DEPREQ_HEADER_LEN]; /*!< Prologue space for NFC-DEP header*/
uint8_t inf[RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN]; /*!< INF | Data area of the buffer */
} rfalNfcDepBufFormat;
/*! Structure of APDU Buffer format from caller */
typedef struct {
uint8_t prologue[RFAL_NFCDEP_DEPREQ_HEADER_LEN]; /*!< Prologue/SoD buffer */
uint8_t pdu[RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN]; /*!< Complete PDU/Payload buffer */
} rfalNfcDepPduBufFormat;
/*! Activation info as Initiator and Target */
typedef union { /* PRQA S 0750 # MISRA 19.2 - Both members of the union will not be used concurrently , device is only initiatior or target a time. No problem can occur. */
struct {
rfalNfcDepAtrRes ATR_RES; /*!< ATR RES (Initiator mode) */
uint8_t ATR_RESLen; /*!< ATR RES length (Initiator mode) */
} Target; /*!< Target */
struct {
rfalNfcDepAtrReq ATR_REQ; /*!< ATR REQ (Target mode) */
uint8_t ATR_REQLen; /*!< ATR REQ length (Target mode) */
} Initiator; /*!< Initiator */
} rfalNfcDepActivation;
/*! NFC-DEP device Info */
typedef struct {
uint8_t GBLen; /*!< General Bytes length */
uint8_t WT; /*!< WT to be used (ignored in Listen Mode) */
uint32_t FWT; /*!< FWT to be used (1/fc)(ignored Listen Mode) */
uint32_t dFWT; /*!< Delta FWT to be used (1/fc) */
uint8_t LR; /*!< Length Reduction coding the max payload */
uint16_t FS; /*!< Frame Size */
rfalBitRate DSI; /*!< Bit Rate coding from Initiator to Target */
rfalBitRate DRI; /*!< Bit Rate coding from Target to Initiator */
uint8_t DID; /*!< Device ID (RFAL_NFCDEP_DID_NO if no DID) */
uint8_t NAD; /*!< Node ADdress (RFAL_NFCDEP_NAD_NO if no NAD)*/
} rfalNfcDepInfo;
/*! NFC-DEP Device structure */
typedef struct {
rfalNfcDepActivation activation; /*!< Activation Info */
rfalNfcDepInfo info; /*!< NFC-DEP device Info */
} rfalNfcDepDevice;
/*! NFCIP Protocol structure for P2P Target
*
* operParam : derives from NFC-Forum NCI NFC-DEP Operation Parameter
* NCI 1.1 Table 86: NFC-DEP Operation Parameter
* and it's a bit mask composed as:
* [ 0000b
* | Chain SHALL use max. Transport Data Byte[1b]
* | I-PDU with no Transport Data SHALL NOT be sent [1b]
* | NFC-DEP Target SHALL NOT send RTOX request [1b]
* ]
*
*/
typedef struct {
rfalNfcDepCommMode commMode; /*!< Initiator in Active P2P or Passive P2P*/
uint8_t operParam; /*!< NFC-DEP Operation Parameter */
uint8_t* nfcid; /*!< Initiator's NFCID2 or NFCID3 */
uint8_t nfcidLen; /*!< Initiator's NFCID length (NFCID2/3) */
uint8_t DID; /*!< Initiator's Device ID DID */
uint8_t NAD; /*!< Initiator's Node ID NAD */
uint8_t BS; /*!< Initiator's Bit Rates supported in Tx */
uint8_t BR; /*!< Initiator's Bit Rates supported in Rx */
uint8_t LR; /*!< Initiator's Length reduction */
uint8_t* GB; /*!< Initiator's General Bytes (Gi) */
uint8_t GBLen; /*!< Initiator's General Bytes length */
} rfalNfcDepAtrParam;
/*! Structure of parameters to be passed in for nfcDepListenStartActivation */
typedef struct {
rfalNfcDepBufFormat* rxBuf; /*!< Receive Buffer struct reference */
uint16_t* rxLen; /*!< Receive INF data length in bytes */
bool* isRxChaining; /*!< Received data is not complete */
rfalNfcDepDevice* nfcDepDev; /*!< NFC-DEP device info */
} rfalNfcDepListenActvParam;
/*! NFCIP Protocol structure for P2P Target
*
* operParam : derives from NFC-Forum NCI NFC-DEP Operation Parameter
* NCI 1.1 Table 86: NFC-DEP Operation Parameter
* and it's a bit mask composed as:
* [ 0000b
* | Chain SHALL use max. Transport Data Byte[1b]
* | I-PDU with no Transport Data SHALL NOT be sent [1b]
* | NFC-DEP Target SHALL NOT send RTOX request [1b]
* ]
*
*/
typedef struct {
rfalNfcDepCommMode commMode; /*!< Target in Active P2P or Passive P2P */
uint8_t nfcid3[RFAL_NFCDEP_NFCID3_LEN]; /*!< Target's NFCID3 */
uint8_t bst; /*!< Target's Bit Rates supported in Tx */
uint8_t brt; /*!< Target's Bit Rates supported in Rx */
uint8_t to; /*!< Target's timeout (TO) value */
uint8_t ppt; /*!< Target's Presence optional Params(PPt)*/
uint8_t GBt[RFAL_NFCDEP_GB_MAX_LEN]; /*!< Target's General Bytes (Gt) */
uint8_t GBtLen; /*!< Target's General Bytes length */
uint8_t operParam; /*!< NFC-DEP Operation Parameter */
} rfalNfcDepTargetParam;
/*! Structure of parameters to be passed in for nfcDepStartIpduTransceive */
typedef struct {
rfalNfcDepBufFormat* txBuf; /*!< Transmit Buffer struct reference */
uint16_t txBufLen; /*!< Transmit Buffer INF field length in bytes */
bool isTxChaining; /*!< Transmit data is not complete */
rfalNfcDepBufFormat* rxBuf; /*!< Receive Buffer struct reference */
uint16_t* rxLen; /*!< Receive INF data length */
bool* isRxChaining; /*!< Received data is not complete */
uint32_t FWT; /*!< FWT to be used (ignored in Listen Mode) */
uint32_t dFWT; /*!< Delta FWT to be used */
uint16_t FSx; /*!< Other device Frame Size (FSD or FSC) */
uint8_t DID; /*!< Device ID (RFAL_ISODEP_NO_DID if no DID) */
} rfalNfcDepTxRxParam;
/*! Structure of parameters used on NFC DEP PDU Transceive */
typedef struct {
rfalNfcDepPduBufFormat* txBuf; /*!< Transmit Buffer struct reference */
uint16_t txBufLen; /*!< Transmit Buffer INF field length in Bytes*/
rfalNfcDepPduBufFormat* rxBuf; /*!< Receive Buffer struct reference in Bytes */
uint16_t* rxLen; /*!< Received INF data length in Bytes */
rfalNfcDepBufFormat* tmpBuf; /*!< Temp buffer for single PDUs (internal) */
uint32_t FWT; /*!< FWT to be used (ignored in Listen Mode) */
uint32_t dFWT; /*!< Delta FWT to be used */
uint16_t FSx; /*!< Other device Frame Size (FSD or FSC) */
uint8_t DID; /*!< Device ID (RFAL_ISODEP_NO_DID if no DID) */
} rfalNfcDepPduTxRxParam;
/*
* *****************************************************************************
* GLOBAL VARIABLE DECLARATIONS
******************************************************************************
*/
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
******************************************************************************
* \brief NFCIP Initialize
*
* This method resets all NFC-DEP inner states, counters and context and sets
* default values
*
******************************************************************************
*/
void rfalNfcDepInitialize(void);
/*!
******************************************************************************
* \brief Set deactivating callback
*
* Sets the deactivating callback so that nfcip layer can check if upper layer
* has a deactivation pending, and not perform error recovery upon specific
* errors
*
* \param[in] pFunc : method pointer to deactivation flag check
******************************************************************************
*/
void rfalNfcDepSetDeactivatingCallback(rfalNfcDepDeactCallback pFunc);
/*!
******************************************************************************
* \brief Calculate Response Waiting Time
*
* Calculates the Response Waiting Time (RWT) from the given Waiting Time (WT)
*
* \param[in] wt : the WT value to calculate RWT
*
* \return RWT value in 1/fc
******************************************************************************
*/
uint32_t rfalNfcDepCalculateRWT(uint8_t wt);
/*!
******************************************************************************
* \brief NFC-DEP Initiator ATR (Attribute Request)
*
* This method configures the NFC-DEP layer with given parameters and then
* sends an ATR to the Target with and checks for a valid response response
*
* \param[in] param : parameters to initialize and compose the ATR
* \param[out] atrRes : location to store the ATR_RES
* \param[out] atrResLen : length of the ATR_RES received
*
* \return ERR_NONE : No error
* \return ERR_TIMEOUT : Timeout occurred
* \return ERR_PROTO : Protocol error occurred
******************************************************************************
*/
ReturnCode
rfalNfcDepATR(const rfalNfcDepAtrParam* param, rfalNfcDepAtrRes* atrRes, uint8_t* atrResLen);
/*!
******************************************************************************
* \brief NFC-DEP Initiator PSL (Parameter Selection)
*
* This method sends a PSL to the Target with the given parameters and checks
* for a valid response response
*
* The parameters must be coded according to Digital 1.1 16.7.1
*
* \param[in] BRS : the selected Bit Rates for Initiator and Target
* \param[in] FSL : the maximum length of Commands and Responses
*
* \return ERR_NONE : No error
* \return ERR_TIMEOUT : Timeout occurred
* \return ERR_PROTO : Protocol error occurred
******************************************************************************
*/
ReturnCode rfalNfcDepPSL(uint8_t BRS, uint8_t FSL);
/*!
******************************************************************************
* \brief NFC-DEP Initiator DSL (Deselect)
*
* This method checks if the NFCIP module is configured as initiator and if
* so sends a DSL REQ, waits the target's response and checks it
*
* In case of performing as target no action is taken
*
* \return ERR_NONE : No error
* \return ERR_TIMEOUT : Timeout occurred
* \return ERR_MAX_RERUNS : Timeout occurred
* \return ERR_PROTO : Protocol error occurred
******************************************************************************
*/
ReturnCode rfalNfcDepDSL(void);
/*!
******************************************************************************
* \brief NFC-DEP Initiator RLS (Release)
*
* This method checks if the NFCIP module is configured as initiator and if
* so sends a RLS REQ, waits target's response and checks it
*
* In case of performing as target no action is taken
*
* \return ERR_NONE : No error
* \return ERR_TIMEOUT : Timeout occurred
* \return ERR_MAX_RERUNS : Timeout occurred
* \return ERR_PROTO : Protocol error occurred
******************************************************************************
*/
ReturnCode rfalNfcDepRLS(void);
/*!
*****************************************************************************
* \brief NFC-DEP Initiator Handle Activation
*
* This performs a Activation into NFC-DEP layer with the given
* parameters. It sends ATR_REQ and if the higher bit rates are supported by
* both devices it additionally sends PSL
* Once Activated all details of the device are provided on nfcDepDev
*
* \param[in] param : required parameters to initialize and send ATR_REQ
* \param[in] desiredBR : Desired bit rate supported by the Poller
* \param[out] nfcDepDev : NFC-DEP information of the activated Listen device
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_TIMEOUT : Timeout error
* \return ERR_PAR : Parity error detected
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_NONE : No error, activation successful
*****************************************************************************
*/
ReturnCode rfalNfcDepInitiatorHandleActivation(
rfalNfcDepAtrParam* param,
rfalBitRate desiredBR,
rfalNfcDepDevice* nfcDepDev);
/*!
******************************************************************************
* \brief Check if buffer contains valid ATR_REQ
*
* This method checks if the given ATR_REQ is valid
*
*
* \param[in] buf : buffer holding Initiator's received request
* \param[in] bufLen : size of the msg contained on the buf in Bytes
* \param[out] nfcid3 : pointer to where the NFCID3 may be outputted,
* nfcid3 has NFCF_SENSF_NFCID3_LEN as length
* Pass NULL if output parameter not desired
*
* \return true : Valid ATR_REQ received, the ATR_RES has been computed in txBuf
* \return false : Invalid protocol request
*
******************************************************************************
*/
bool rfalNfcDepIsAtrReq(const uint8_t* buf, uint16_t bufLen, uint8_t* nfcid3);
/*!
******************************************************************************
* \brief Check is Target has received ATR
*
* This method checks if the NFCIP module is configured as target and if a
* ATR REQ has been received ( whether is in activation or in data exchange)
*
* \return true : a ATR has already been received
* \return false : no ATR has been received
******************************************************************************
*/
bool rfalNfcDepTargetRcvdATR(void);
/*!
*****************************************************************************
* \brief NFCDEP Start Listen Activation Handling
*
* Start Activation Handling and setup to receive first frame which may
* contain complete or partial DEP-REQ after activation is completed
*
* Pass in ATR_REQ for NFC-DEP to handle ATR_RES. The Activation Handling
* handles ATR_RES and PSL_RES if a PSL_REQ is received
*
* Activation is completed if PSL_RES is sent or if first I-PDU is received
*
* \ref rfalNfcDepListenGetActivationStatus() provide status of the
* ongoing activation
*
* \warning nfcDepGetTransceiveStatus() shall be called right after activation
* is completed (i.e. rfalNfcDepListenGetActivationStatus() return ERR_NONE)
* to check for first received frame.
*
* \param[in] param : Target parameters to be used
* \param[in] atrReq : reference to buffer containing ATR_REQ
* \param[in] atrReqLength: Length of ATR_REQ
* \param[out] rxParam : references to buffer, length and chaining indication
* for first complete LLCP to be received
*
* \return ERR_NONE : ATR_REQ is valid and activation ongoing
* \return ERR_PARAM : ATR_REQ or other params are invalid
* \return ERR_LINK_LOSS : Remote Field is turned off
*****************************************************************************
*/
ReturnCode rfalNfcDepListenStartActivation(
const rfalNfcDepTargetParam* param,
const uint8_t* atrReq,
uint16_t atrReqLength,
rfalNfcDepListenActvParam rxParam);
/*!
*****************************************************************************
* \brief Get the current NFC-DEP Activation Status
*
* \return ERR_NONE : Activation has completed successfully
* \return ERR_BUSY : Activation is ongoing
* \return ERR_LINK_LOSS : Remote Field was turned off
*****************************************************************************
*/
ReturnCode rfalNfcDepListenGetActivationStatus(void);
/*!
*****************************************************************************
* \brief Start Transceive
*
* Transceives a complete or partial DEP block
*
* The txBuf contains complete or partial of DEP to be transmitted.
* The Prologue field of the I-PDU is handled internally
*
* If the buffer contains partial LLCP and is not the last block, then
* isTxChaining must be set to true
*
* \param[in] param: reference parameters to be used for the Transceive
*
* \return ERR_PARAM : Bad request
* \return ERR_WRONG_STATE : The module is not in a proper state
* \return ERR_NONE : The Transceive request has been started
*****************************************************************************
*/
ReturnCode rfalNfcDepStartTransceive(const rfalNfcDepTxRxParam* param);
/*!
*****************************************************************************
* \brief Return the Transceive status
*
* Returns the status of the NFC-DEP Transceive
*
* \warning When the other device is performing chaining once a chained
* block is received the error ERR_AGAIN is sent. At this point
* caller must handle the received data immediately.
* When ERR_AGAIN is returned an ACK has already been sent to
* the other device and the next block might be incoming.
* If rfalWorker() is called frequently it will place the next
* block on the given buffer
*
* \return ERR_NONE : Transceive has been completed successfully
* \return ERR_BUSY : Transceive is ongoing
* \return ERR_PROTO : Protocol error occurred
* \return ERR_TIMEOUT : Timeout error occurred
* \return ERR_SLEEP_REQ : Deselect has been received and responded
* \return ERR_NOMEM : The received I-PDU does not fit into the
* receive buffer
* \return ERR_LINK_LOSS : Communication is lost because Reader/Writer
* has turned off its field
* \return ERR_AGAIN : received one chaining block, continue to call
* this method to retrieve the remaining blocks
*****************************************************************************
*/
ReturnCode rfalNfcDepGetTransceiveStatus(void);
/*!
*****************************************************************************
* \brief Start PDU Transceive
*
* This method triggers a NFC-DEP Transceive containing a complete PDU
* It transmits the given message and handles all protocol retransmitions,
* error handling and control messages
*
* The txBuf contains a complete PDU to be transmitted
* The Prologue field will be manipulated by the Transceive
*
* \warning the txBuf will be modified during the transmission
* \warning the maximum RF frame which can be received is limited by param.tmpBuf
*
* \param[in] param: reference parameters to be used for the Transceive
*
* \return ERR_PARAM : Bad request
* \return ERR_WRONG_STATE : The module is not in a proper state
* \return ERR_NONE : The Transceive request has been started
*****************************************************************************
*/
ReturnCode rfalNfcDepStartPduTransceive(rfalNfcDepPduTxRxParam param);
/*!
*****************************************************************************
* \brief Return the PSU Transceive status
*
* Returns the status of the NFC-DEP PDU Transceive
*
*
* \return ERR_NONE : Transceive has been completed successfully
* \return ERR_BUSY : Transceive is ongoing
* \return ERR_PROTO : Protocol error occurred
* \return ERR_TIMEOUT : Timeout error occurred
* \return ERR_SLEEP_REQ : Deselect has been received and responded
* \return ERR_NOMEM : The received I-PDU does not fit into the
* receive buffer
* \return ERR_LINK_LOSS : Communication is lost because Reader/Writer
* has turned off its field
*****************************************************************************
*/
ReturnCode rfalNfcDepGetPduTransceiveStatus(void);
#endif /* RFAL_NFCDEP_H_ */
/**
* @}
*
* @}
*
* @}
*/
-497
View File
@@ -1,497 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_nfca.h
*
* \author Gustavo Patricio
*
* \brief Provides several NFC-A convenience methods and definitions
*
* It provides a Poller (ISO14443A PCD) interface and as well as
* some NFC-A Listener (ISO14443A PICC) helpers.
*
* The definitions and helpers methods provided by this module are only
* up to ISO14443-3 layer
*
*
* An usage example is provided here: \ref exampleRfalNfca.c
* \example exampleRfalNfca.c
*
*
* \addtogroup RFAL
* @{
*
* \addtogroup RFAL-AL
* \brief RFAL Abstraction Layer
* @{
*
* \addtogroup NFC-A
* \brief RFAL NFC-A Module
* @{
*
*/
#ifndef RFAL_NFCA_H
#define RFAL_NFCA_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
#include "st_errno.h"
#include "rfal_rf.h"
#include "rfal_t1t.h"
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_NFCA_CASCADE_1_UID_LEN \
4U /*!< UID length of cascade level 1 only tag */
#define RFAL_NFCA_CASCADE_2_UID_LEN \
7U /*!< UID length of cascade level 2 only tag */
#define RFAL_NFCA_CASCADE_3_UID_LEN \
10U /*!< UID length of cascade level 3 only tag */
#define RFAL_NFCA_SENS_RES_PLATFORM_MASK \
0x0FU /*!< SENS_RES (ATQA) platform configuration mask Digital 1.1 Table 10 */
#define RFAL_NFCA_SENS_RES_PLATFORM_T1T \
0x0CU /*!< SENS_RES (ATQA) T1T platform configuration Digital 1.1 Table 10 */
#define RFAL_NFCA_SEL_RES_CONF_MASK \
0x60U /*!< SEL_RES (SAK) platform configuration mask Digital 1.1 Table 19 */
#define RFAL_NFCA_SEL_RES_CONF_T2T \
0x00U /*!< SEL_RES (SAK) T2T configuration Digital 1.1 Table 19 */
#define RFAL_NFCA_SEL_RES_CONF_T4T \
0x20U /*!< SEL_RES (SAK) T4T configuration Digital 1.1 Table 19 */
#define RFAL_NFCA_SEL_RES_CONF_NFCDEP \
0x40U /*!< SEL_RES (SAK) NFC-DEP configuration Digital 1.1 Table 19 */
#define RFAL_NFCA_SEL_RES_CONF_T4T_NFCDEP \
0x60U /*!< SEL_RES (SAK) T4T and NFC-DEP configuration Digital 1.1 Table 19 */
/*! NFC-A minimum FDT(listen) = ((n * 128 + (84)) / fc) with n_min = 9 Digital 1.1 6.10.1
* = (1236)/fc
* Relax with 3etu: (3*128)/fc as with multiple NFC-A cards, response may take longer (JCOP cards)
* = (1236 + 384)/fc = 1620 / fc */
#define RFAL_NFCA_FDTMIN 1620U
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
/*! Checks if device is a T1T given its SENS_RES */
#define rfalNfcaIsSensResT1T(sensRes) \
((((rfalNfcaSensRes*)(sensRes))->platformInfo & RFAL_NFCA_SENS_RES_PLATFORM_MASK) == \
RFAL_NFCA_SENS_RES_PLATFORM_T1T)
/*! Checks if device is a T2T given its SENS_RES */
#define rfalNfcaIsSelResT2T(selRes) \
((((rfalNfcaSelRes*)(selRes))->sak & RFAL_NFCA_SEL_RES_CONF_MASK) == \
RFAL_NFCA_SEL_RES_CONF_T2T)
/*! Checks if device is a T4T given its SENS_RES */
#define rfalNfcaIsSelResT4T(selRes) \
((((rfalNfcaSelRes*)(selRes))->sak & RFAL_NFCA_SEL_RES_CONF_MASK) == \
RFAL_NFCA_SEL_RES_CONF_T4T)
/*! Checks if device supports NFC-DEP protocol given its SENS_RES */
#define rfalNfcaIsSelResNFCDEP(selRes) \
((((rfalNfcaSelRes*)(selRes))->sak & RFAL_NFCA_SEL_RES_CONF_MASK) == \
RFAL_NFCA_SEL_RES_CONF_NFCDEP)
/*! Checks if device supports ISO-DEP and NFC-DEP protocol given its SENS_RES */
#define rfalNfcaIsSelResT4TNFCDEP(selRes) \
((((rfalNfcaSelRes*)(selRes))->sak & RFAL_NFCA_SEL_RES_CONF_MASK) == \
RFAL_NFCA_SEL_RES_CONF_T4T_NFCDEP)
/*! Checks if a NFC-A listener device supports multiple protocols (ISO-DEP and NFC-DEP) */
#define rfalNfcaLisDevIsMultiProto(lisDev) \
(((rfalNfcaListenDevice*)(lisDev))->type == RFAL_NFCA_T4T_NFCDEP)
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
/*! NFC-A Listen device types */
typedef enum {
RFAL_NFCA_T1T =
0x01, /* Device configured for T1T Digital 1.1 Table 9 */
RFAL_NFCA_T2T =
0x00, /* Device configured for T2T Digital 1.1 Table 19 */
RFAL_NFCA_T4T =
0x20, /* Device configured for T4T Digital 1.1 Table 19 */
RFAL_NFCA_NFCDEP =
0x40, /* Device configured for NFC-DEP Digital 1.1 Table 19 */
RFAL_NFCA_T4T_NFCDEP =
0x60 /* Device configured for NFC-DEP and T4T Digital 1.1 Table 19 */
} rfalNfcaListenDeviceType;
/*! SENS_RES (ATQA) format Digital 1.1 6.6.3 & Table 7 */
typedef struct {
uint8_t
anticollisionInfo; /*!< SENS_RES Anticollision Information */
uint8_t
platformInfo; /*!< SENS_RES Platform Information */
} rfalNfcaSensRes;
/*! SDD_REQ (Anticollision) format Digital 1.1 6.7.1 & Table 11 */
typedef struct {
uint8_t
selCmd; /*!< SDD_REQ SEL_CMD: cascade Level */
uint8_t
selPar; /*!< SDD_REQ SEL_PAR: Byte Count[4b] | Bit Count[4b] (NVB: Number of Valid Bits)*/
} rfalNfcaSddReq;
/*! SDD_RES (UID CLn) format Digital 1.1 6.7.2 & Table 15 */
typedef struct {
uint8_t nfcid1
[RFAL_NFCA_CASCADE_1_UID_LEN]; /*!< NFCID1 cascade level NFCID */
uint8_t bcc; /*!< BCC Exclusive-OR over first 4 bytes of SDD_RES */
} rfalNfcaSddRes;
/*! SEL_REQ (Select) format Digital 1.1 6.8.1 & Table 17 */
typedef struct {
uint8_t
selCmd; /*!< SDD_REQ SEL_CMD: cascade Level */
uint8_t
selPar; /*!< SDD_REQ SEL_PAR: Byte Count[4b] | Bit Count[4b] (NVB: Number of Valid Bits)*/
uint8_t nfcid1
[RFAL_NFCA_CASCADE_1_UID_LEN]; /*!< NFCID1 data */
uint8_t bcc; /*!< Checksum calculated as exclusive-OR over the 4 bytes of NFCID1 CLn */
} rfalNfcaSelReq;
/*! SEL_RES (SAK) format Digital 1.1 6.8.2 & Table 19 */
typedef struct {
uint8_t sak; /*!< Select Acknowledge */
} rfalNfcaSelRes;
/*! NFC-A listener device (PICC) struct */
typedef struct {
rfalNfcaListenDeviceType
type; /*!< NFC-A Listen device type */
rfalNfcaSensRes
sensRes; /*!< SENS_RES (ATQA) */
rfalNfcaSelRes
selRes; /*!< SEL_RES (SAK) */
uint8_t
nfcId1Len; /*!< NFCID1 Length */
uint8_t nfcId1
[RFAL_NFCA_CASCADE_3_UID_LEN]; /*!< NFCID1 (UID) */
#ifdef RFAL_FEATURE_T1T
rfalT1TRidRes
ridRes; /*!< RID_RES */
#endif /* RFAL_FEATURE_T1T */
bool isSleep; /*!< Device sleeping flag */
} rfalNfcaListenDevice;
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief Initialize NFC-A Poller mode
*
* This methods configures RFAL RF layer to perform as a
* NFC-A Poller/RW (ISO14443A PCD) including all default timings and bit rate
* to 106 kbps
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcaPollerInitialize(void);
/*!
*****************************************************************************
* \brief NFC-A Poller Check Presence
*
* This method checks if a NFC-A Listen device (PICC) is present on the field
* by sending an ALL_REQ (WUPA) or SENS_REQ (REQA)
*
* \param[in] cmd : Indicate if to send an ALL_REQ or a SENS_REQ
* \param[out] sensRes : If received, the SENS_RES
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_RF_COLLISION : Collision detected one or more device in the field
* \return ERR_PAR : Parity error detected, one or more device in the field
* \return ERR_CRC : CRC error detected, one or more device in the field
* \return ERR_FRAMING : Framing error detected, one or more device in the field
* \return ERR_PROTO : Protocol error detected, one or more device in the field
* \return ERR_TIMEOUT : Timeout error, no listener device detected
* \return ERR_NONE : No error, one or more device in the field
*****************************************************************************
*/
ReturnCode rfalNfcaPollerCheckPresence(rfal14443AShortFrameCmd cmd, rfalNfcaSensRes* sensRes);
/*!
*****************************************************************************
* \brief NFC-A Poller Select
*
* This method selects a NFC-A Listener device (PICC)
*
* \param[in] nfcid1 : Listener device NFCID1 to be selected
* \param[in] nfcidLen : Length of the NFCID1 to be selected
* \param[out] selRes : pointer to place the SEL_RES
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_TIMEOUT : Timeout error
* \return ERR_PAR : Parity error detected
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_NONE : No error, SEL_RES received
*****************************************************************************
*/
ReturnCode rfalNfcaPollerSelect(const uint8_t* nfcid1, uint8_t nfcidLen, rfalNfcaSelRes* selRes);
/*!
*****************************************************************************
* \brief NFC-A Poller Sleep
*
* This method sends a SLP_REQ (HLTA)
* No response is expected afterwards Digital 1.1 6.9.2.1
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcaPollerSleep(void);
/*!
*****************************************************************************
* \brief NFC-A Technology Detection
*
* This method performs NFC-A Technology Detection as defined in the spec
* given in the compliance mode
*
* \param[in] compMode : compliance mode to be performed
* \param[out] sensRes : location to store the SENS_RES, if received
*
* When compMode is set to ISO compliance a SLP_REQ (HLTA) is not sent
* after detection. When set to EMV a ALL_REQ (WUPA) is sent instead of
* a SENS_REQ (REQA)
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_NONE : No error, one or more device in the field
*****************************************************************************
*/
ReturnCode
rfalNfcaPollerTechnologyDetection(rfalComplianceMode compMode, rfalNfcaSensRes* sensRes);
/*!
*****************************************************************************
* \brief NFC-A Poller Collision Resolution
*
* Collision resolution for one NFC-A Listener device/card (PICC) as
* defined in Activity 2.1 9.3.4
*
* This method executes anti collision loop and select the device with higher NFCID1
*
* When devLimit = 0 it is configured to perform collision detection only. Once a collision
* is detected the collision resolution is aborted immediately. If only one device is found
* with no collisions, it will properly resolved.
*
* \param[in] devLimit : device limit value (CON_DEVICES_LIMIT)
* \param[out] collPending : pointer to collision pending flag (INT_COLL_PEND)
* \param[out] selRes : location to store the last Select Response from listener device (PICC)
* \param[out] nfcId1 : location to store the NFCID1 (UID), ensure RFAL_NFCA_CASCADE_3_UID_LEN
* \param[out] nfcId1Len : pointer to length of NFCID1 (UID)
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_PROTO : Card length invalid
* \return ERR_IGNORE : conDevLimit is 0 and there is a collision
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcaPollerSingleCollisionResolution(
uint8_t devLimit,
bool* collPending,
rfalNfcaSelRes* selRes,
uint8_t* nfcId1,
uint8_t* nfcId1Len);
/*!
*****************************************************************************
* \brief NFC-A Poller Full Collision Resolution
*
* Performs a full Collision resolution as defined in Activity 2.1 9.3.4
*
* \param[in] compMode : compliance mode to be performed
* \param[in] devLimit : device limit value, and size nfcaDevList
* \param[out] nfcaDevList : NFC-A listener device info
* \param[out] devCnt : Devices found counter
*
* When compMode is set to ISO compliance it assumes that the device is
* not sleeping and therefore no ALL_REQ (WUPA) is sent at the beginning.
* When compMode is set to NFC compliance an additional ALL_REQ (WUPA) is sent
* at the beginning.
*
*
* When devLimit = 0 it is configured to perform collision detection only. Once a collision
* is detected the collision resolution is aborted immediately. If only one device is found
* with no collisions, it will properly resolved.
*
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcaPollerFullCollisionResolution(
rfalComplianceMode compMode,
uint8_t devLimit,
rfalNfcaListenDevice* nfcaDevList,
uint8_t* devCnt);
/*!
*****************************************************************************
* \brief NFC-A Poller Full Collision Resolution with Sleep
*
* Performs a full Collision resolution similar to rfalNfcaPollerFullCollisionResolution
* but an additional SLP_REQ (HLTA) -> SENS_RES (REQA) is sent regardless if there
* was a collision.
* This proprietary behaviour ensures proper activation of certain devices that suffer
* from influence of Type B commands as foreseen in ISO14443-3 5.2.3 or were somehow
* not detected by the first round of collision resolution
*
* \param[in] devLimit : device limit value, and size nfcaDevList
* \param[out] nfcaDevList : NFC-A listener device info
* \param[out] devCnt : Devices found counter
*
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcaPollerSleepFullCollisionResolution(
uint8_t devLimit,
rfalNfcaListenDevice* nfcaDevList,
uint8_t* devCnt);
/*!
*****************************************************************************
* \brief NFC-A Poller Start Full Collision Resolution
*
* This method starts the full Collision resolution as defined
* in Activity 1.0 or 1.1 9.3.4
*
* \param[in] compMode : compliance mode to be performed
* \param[in] devLimit : device limit value, and size nfcaDevList
* \param[out] nfcaDevList : NFC-A listener device info
* \param[out] devCnt : Devices found counter
*
* When compMode is set to ISO compliance it assumes that the device is
* not sleeping and therefore no ALL_REQ (WUPA) is sent at the beginning.
* When compMode is set to NFC compliance an additional ALL_REQ (WUPA) is sent at
* the beginning.
*
*
* When devLimit = 0 it is configured to perform collision detection only. Once a collision
* is detected the collision resolution is aborted immediately. If only one device is found
* with no collisions, it will properly resolved.
*
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcaPollerStartFullCollisionResolution(
rfalComplianceMode compMode,
uint8_t devLimit,
rfalNfcaListenDevice* nfcaDevList,
uint8_t* devCnt);
/*!
*****************************************************************************
* \brief NFC-A Get Full Collision Resolution Status
*
* Returns the Collision Resolution status
*
* \return ERR_BUSY : Operation is ongoing
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_TIMEOUT : Timeout error
* \return ERR_PAR : Parity error detected
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_NONE : No error, activation successful
*****************************************************************************
*/
ReturnCode rfalNfcaPollerGetFullCollisionResolutionStatus(void);
/*!
*****************************************************************************
* \brief NFC-A Listener is SLP_REQ
*
* Checks if the given buffer contains valid NFC-A SLP_REQ (HALT)
*
* \param[in] buf: buffer containing data
* \param[in] bufLen: length of the data in buffer to be checked
*
* \return true if data in buf contains a SLP_REQ ; false otherwise
*****************************************************************************
*/
bool rfalNfcaListenerIsSleepReq(const uint8_t* buf, uint16_t bufLen);
#endif /* RFAL_NFCA_H */
/**
* @}
*
* @}
*
* @}
*/
-425
View File
@@ -1,425 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_nfcb.h
*
* \author Gustavo Patricio
*
* \brief Implementation of NFC-B (ISO14443B) helpers
*
* It provides a NFC-B Poller (ISO14443B PCD) interface and
* also provides some NFC-B Listener (ISO14443B PICC) helpers
*
* The definitions and helpers methods provided by this module are only
* up to ISO14443-3 layer (excluding ATTRIB)
*
*
* \addtogroup RFAL
* @{
*
* \addtogroup RFAL-AL
* \brief RFAL Abstraction Layer
* @{
*
* \addtogroup NFC-B
* \brief RFAL NFC-B Module
* @{
*
*/
#ifndef RFAL_NFCB_H
#define RFAL_NFCB_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
#include "st_errno.h"
#include "rfal_rf.h"
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_NFCB_FWTSENSB 7680U /*!< NFC-B FWT(SENSB) Digital 2.0 B.3 */
#define RFAL_NFCB_DFWT 49152U /*!< NFC-B dFWT Delta 2.0 7.9.1.3 & B.3 */
#define RFAL_NFCB_DTPOLL_10 rfalConvMsTo1fc(20) /*!< NFC-B Delta Tb Poll Digital 1.0 A.2 */
#define RFAL_NFCB_DTPOLL_20 rfalConvMsTo1fc(17) /*!< NFC-B Delta Tb Poll Digital 2.1 B.3 */
#define RFAL_NFCB_AFI 0x00U /*!< NFC-B default Application Family Digital 1.1 7.6.1.1 */
#define RFAL_NFCB_PARAM 0x00U /*!< NFC-B default SENSB_REQ PARAM */
#define RFAL_NFCB_CRC_LEN 2U /*!< NFC-B CRC length and CRC_B(AID) Digital 1.1 Table 28 */
#define RFAL_NFCB_NFCID0_LEN 4U /*!< Length of NFC-B NFCID0 */
#define RFAL_NFCB_CMD_LEN 1U /*!< Length of NFC-B Command */
#define RFAL_NFCB_SENSB_RES_LEN 12U /*!< Standard length of SENSB_RES without SFGI byte */
#define RFAL_NFCB_SENSB_RES_EXT_LEN \
13U /*!< Extended length of SENSB_RES with SFGI byte */
#define RFAL_NFCB_SENSB_REQ_ADV_FEATURE \
0x20U /*!< Bit mask for Advance Feature in SENSB_REQ */
#define RFAL_NFCB_SENSB_RES_FSCI_MASK \
0x0FU /*!< Bit mask for FSCI value in SENSB_RES */
#define RFAL_NFCB_SENSB_RES_FSCI_SHIFT \
4U /*!< Shift for FSCI value in SENSB_RES */
#define RFAL_NFCB_SENSB_RES_PROTO_RFU_MASK \
0x08U /*!< Bit mask for Protocol Type RFU in SENSB_RES */
#define RFAL_NFCB_SENSB_RES_PROTO_TR2_MASK \
0x03U /*!< Bit mask for Protocol Type TR2 in SENSB_RES */
#define RFAL_NFCB_SENSB_RES_PROTO_TR2_SHIFT \
1U /*!< Shift for Protocol Type TR2 in SENSB_RES */
#define RFAL_NFCB_SENSB_RES_PROTO_ISO_MASK \
0x01U /*!< Bit mask Protocol Type ISO14443 Compliant in SENSB_RES */
#define RFAL_NFCB_SENSB_RES_FWI_MASK \
0x0FU /*!< Bit mask for FWI value in SENSB_RES */
#define RFAL_NFCB_SENSB_RES_FWI_SHIFT \
4U /*!< Bit mask for FWI value in SENSB_RES */
#define RFAL_NFCB_SENSB_RES_ADC_MASK \
0x0CU /*!< Bit mask for ADC value in SENSB_RES */
#define RFAL_NFCB_SENSB_RES_ADC_ADV_FEATURE_MASK \
0x08U /*!< Bit mask for ADC.Advanced Proto Features in SENSB_RES */
#define RFAL_NFCB_SENSB_RES_ADC_PROPRIETARY_MASK \
0x04U /*!< Bit mask for ADC.Proprietary Application in SENSB_RES */
#define RFAL_NFCB_SENSB_RES_FO_DID_MASK \
0x01U /*!< Bit mask for DID in SENSB_RES */
#define RFAL_NFCB_SENSB_RES_FO_NAD_MASK \
0x02U /*!< Bit mask for DID in SENSB_RES */
#define RFAL_NFCB_SENSB_RES_FO_MASK \
0x03U /*!< Bit mask for FO value in SENSB_RES (NAD and DID) */
#define RFAL_NFCB_SENSB_RES_SFGI_MASK \
0x0FU /*!< Bit mask for SFGI in SENSB_RES */
#define RFAL_NFCB_SENSB_RES_SFGI_SHIFT \
4U /*!< Shift for SFGI in SENSB_RES */
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
/*! Get device's FSCI given its SENSB_RES Digital 1.1 7.6.2 */
#define rfalNfcbGetFSCI(sensbRes) \
((((rfalNfcbSensbRes*)(sensbRes))->protInfo.FsciProType >> RFAL_NFCB_SENSB_RES_FSCI_SHIFT) & \
RFAL_NFCB_SENSB_RES_FSCI_MASK)
/*! Checks if the given NFC-B device indicates ISO-DEP support */
#define rfalNfcbIsIsoDepSupported(dev) \
((((rfalNfcbListenDevice*)(dev))->sensbRes.protInfo.FsciProType & \
RFAL_NFCB_SENSB_RES_PROTO_ISO_MASK) != 0U)
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
/*! SENSB_REQ and ALLB_REQ param Digital 1.1 7.6.1 */
typedef enum {
RFAL_NFCB_SENS_CMD_ALLB_REQ = 0x08, /*!< ALLB_REQ (WUPB) */
RFAL_NFCB_SENS_CMD_SENSB_REQ = 0x00 /*!< SENSB_REQ (REQB) */
} rfalNfcbSensCmd;
/*! Number of Slots (NI) codes used for NFC-B anti collision Digital 1.1 Table 26 */
typedef enum {
RFAL_NFCB_SLOT_NUM_1 = 0, /*!< N=0 : 1 slot */
RFAL_NFCB_SLOT_NUM_2 = 1, /*!< N=1 : 2 slots */
RFAL_NFCB_SLOT_NUM_4 = 2, /*!< N=2 : 4 slots */
RFAL_NFCB_SLOT_NUM_8 = 3, /*!< N=3 : 8 slots */
RFAL_NFCB_SLOT_NUM_16 = 4 /*!< N=4 : 16 slots */
} rfalNfcbSlots;
/*! SENSB_RES (ATQB) Application Data Format Digital 1.1 Table 28 */
typedef struct {
uint8_t AFI; /*!< Application Family Identifier */
uint8_t CRC_B[RFAL_NFCB_CRC_LEN]; /*!< CRC_B of AID */
uint8_t numApps; /*!< Number of Applications */
} rfalNfcbSensbResAppData;
/*! SENSB_RES Protocol Info format Digital 1.1 Table 29 */
typedef struct {
uint8_t
BRC; /*!< Bit Rate Capability */
uint8_t
FsciProType; /*!< Frame Size Card Integer [4b] | Protocol Type[4 bits] */
uint8_t
FwiAdcFo; /*!< Frame Waiting Integer [4b] | Application Data Coding [2b] | Frame Options [2b] */
uint8_t
SFGI; /*!< Optional: Start-Up Frame Guard Time Integer[4b] | RFU [4b] */
} rfalNfcbSensbResProtocolInfo;
/*! SENSB_RES format Digital 1.1 7.6.2 */
typedef struct {
uint8_t cmd; /*!< SENSB_RES: 50h */
uint8_t nfcid0[RFAL_NFCB_NFCID0_LEN]; /*!< NFC Identifier (PUPI)*/
rfalNfcbSensbResAppData appData; /*!< Application Data */
rfalNfcbSensbResProtocolInfo protInfo; /*!< Protocol Information */
} rfalNfcbSensbRes;
/*! NFC-B listener device (PICC) struct */
typedef struct {
uint8_t sensbResLen; /*!< SENSB_RES length */
rfalNfcbSensbRes sensbRes; /*!< SENSB_RES */
bool isSleep; /*!< Device sleeping flag */
} rfalNfcbListenDevice;
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief Initialize NFC-B Poller mode
*
* This methods configures RFAL RF layer to perform as a
* NFC-B Poller/RW (ISO14443B PCD) including all default timings
*
* It sets NFC-B parameters (AFI, PARAM) to default values
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcbPollerInitialize(void);
/*!
*****************************************************************************
* \brief Set NFC-B Poller parameters
*
* This methods configures RFAL RF layer to perform as a
* NFCA Poller/RW (ISO14443A PCD) including all default timings
*
* Additionally configures NFC-B specific parameters to be used on the
* following communications
*
* \param[in] AFI : Application Family Identifier to be used
* \param[in] PARAM : PARAM to be used, it announces whether Advanced
* Features or Extended SENSB_RES is supported
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcbPollerInitializeWithParams(uint8_t AFI, uint8_t PARAM);
/*!
*****************************************************************************
* \brief NFC-B Poller Check Presence
*
* This method checks if a NFC-B Listen device (PICC) is present on the field
* by sending an ALLB_REQ (WUPB) or SENSB_REQ (REQB)
*
* \param[in] cmd : Indicate if to send an ALL_REQ or a SENS_REQ
* \param[in] slots : The number of slots to be announced
* \param[out] sensbRes : If received, the SENSB_RES
* \param[out] sensbResLen : If received, the SENSB_RES length
*
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_TIMEOUT : Timeout error, no listener device detected
* \return ERR_RF_COLLISION : Collision detected one or more device in the field
* \return ERR_PAR : Parity error detected, one or more device in the field
* \return ERR_CRC : CRC error detected, one or more device in the field
* \return ERR_FRAMING : Framing error detected, one or more device in the field
* \return ERR_PROTO : Protocol error detected, invalid SENSB_RES received
* \return ERR_NONE : No error, SENSB_RES received
*****************************************************************************
*/
ReturnCode rfalNfcbPollerCheckPresence(
rfalNfcbSensCmd cmd,
rfalNfcbSlots slots,
rfalNfcbSensbRes* sensbRes,
uint8_t* sensbResLen);
/*!
*****************************************************************************
* \brief NFC-B Poller Sleep
*
* This function is used to send the SLPB_REQ (HLTB) command to put the PICC with
* the given NFCID0 to state HALT so that they do not reply to further SENSB_REQ
* commands (only to ALLB_REQ)
*
* \param[in] nfcid0 : NFCID of the device to be put to Sleep
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcbPollerSleep(const uint8_t* nfcid0);
/*!
*****************************************************************************
* \brief NFC-B Poller Slot Marker
*
* This method selects a NFC-B Slot marker frame
*
* \param[in] slotCode : Slot Code [1-15]
* \param[out] sensbRes : If received, the SENSB_RES
* \param[out] sensbResLen : If received, the SENSB_RES length
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_TIMEOUT : Timeout error
* \return ERR_PAR : Parity error detected
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_NONE : No error, SEL_RES received
*****************************************************************************
*/
ReturnCode
rfalNfcbPollerSlotMarker(uint8_t slotCode, rfalNfcbSensbRes* sensbRes, uint8_t* sensbResLen);
/*!
*****************************************************************************
* \brief NFC-B Technology Detection
*
* This method performs NFC-B Technology Detection as defined in the spec
* given in the compliance mode
*
* \param[in] compMode : compliance mode to be performed
* \param[out] sensbRes : location to store the SENSB_RES, if received
* \param[out] sensbResLen : length of the SENSB_RES, if received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_NONE : No error, one or more device in the field
*****************************************************************************
*/
ReturnCode rfalNfcbPollerTechnologyDetection(
rfalComplianceMode compMode,
rfalNfcbSensbRes* sensbRes,
uint8_t* sensbResLen);
/*!
*****************************************************************************
* \brief NFC-B Poller Collision Resolution
*
* NFC-B Collision resolution Listener device/card (PICC) as
* defined in Activity 1.1 9.3.5
*
* This function is used to perform collision resolution for detection in case
* of multiple NFC Forum Devices with Technology B detected.
* Target with valid SENSB_RES will be stored in devInfo and nfcbDevCount incremented.
*
* \param[in] compMode : compliance mode to be performed
* \param[in] devLimit : device limit value, and size nfcbDevList
* \param[out] nfcbDevList : NFC-B listener device info
* \param[out] devCnt : devices found counter
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_PROTO : Protocol error detected
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcbPollerCollisionResolution(
rfalComplianceMode compMode,
uint8_t devLimit,
rfalNfcbListenDevice* nfcbDevList,
uint8_t* devCnt);
/*!
*****************************************************************************
* \brief NFC-B Poller Collision Resolution Slotted
*
* NFC-B Collision resolution Listener device/card (PICC). The sequence can
* be configured to be according to NFC Forum Activity 1.1 9.3.5, ISO10373
* or EMVCo
*
* This function is used to perform collision resolution for detection in case
* of multiple NFC Forum Devices with Technology B are detected.
* Target with valid SENSB_RES will be stored in devInfo and nfcbDevCount incremented.
*
* This method provides the means to perform a collision resolution loop with specific
* initial and end number of slots. This allows to user to start the loop already with
* greater number of slots, and or limit the end number of slots. At the end a flag
* indicating whether there were collisions pending is returned.
*
* If RFAL_COMPLIANCE_MODE_ISO is used \a initSlots must be set to RFAL_NFCB_SLOT_NUM_1
*
*
* \param[in] compMode : compliance mode to be performed
* \param[in] devLimit : device limit value, and size nfcbDevList
* \param[in] initSlots : number of slots to open initially
* \param[in] endSlots : number of slots when to stop collision resolution
* \param[out] nfcbDevList : NFC-B listener device info
* \param[out] devCnt : devices found counter
* \param[out] colPending : flag indicating whether collision are still pending
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_PROTO : Protocol error detected
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcbPollerSlottedCollisionResolution(
rfalComplianceMode compMode,
uint8_t devLimit,
rfalNfcbSlots initSlots,
rfalNfcbSlots endSlots,
rfalNfcbListenDevice* nfcbDevList,
uint8_t* devCnt,
bool* colPending);
/*!
*****************************************************************************
* \brief NFC-B TR2 code to FDT
*
* Converts the TR2 code as defined in Digital 1.1 Table 33 Minimum
* TR2 Coding to Frame Delay Time (FDT) in 1/Fc
*
* \param[in] tr2Code : TR2 code as defined in Digital 1.1 Table 33
*
* \return FDT in 1/Fc
*****************************************************************************
*/
uint32_t rfalNfcbTR2ToFDT(uint8_t tr2Code);
#endif /* RFAL_NFCB_H */
/**
* @}
*
* @}
*
* @}
*/
-403
View File
@@ -1,403 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_nfcf.h
*
* \author Gustavo Patricio
*
* \brief Implementation of NFC-F Poller (FeliCa PCD) device
*
* The definitions and helpers methods provided by this module are
* aligned with NFC-F (FeliCa - JIS X6319-4)
*
*
* \addtogroup RFAL
* @{
*
* \addtogroup RFAL-AL
* \brief RFAL Abstraction Layer
* @{
*
* \addtogroup NFC-F
* \brief RFAL NFC-F Module
* @{
*
*/
#ifndef RFAL_NFCF_H
#define RFAL_NFCF_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
#include "st_errno.h"
#include "rfal_rf.h"
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_NFCF_NFCID2_LEN 8U /*!< NFCID2 (FeliCa IDm) length */
#define RFAL_NFCF_SENSF_RES_LEN_MIN 16U /*!< SENSF_RES minimum length */
#define RFAL_NFCF_SENSF_RES_LEN_MAX 18U /*!< SENSF_RES maximum length */
#define RFAL_NFCF_SENSF_RES_PAD0_LEN 2U /*!< SENSF_RES PAD0 length */
#define RFAL_NFCF_SENSF_RES_PAD1_LEN 2U /*!< SENSF_RES PAD1 length */
#define RFAL_NFCF_SENSF_RES_RD_LEN 2U /*!< SENSF_RES Request Data length */
#define RFAL_NFCF_SENSF_RES_BYTE1 1U /*!< SENSF_RES first byte value */
#define RFAL_NFCF_SENSF_SC_LEN 2U /*!< Felica SENSF_REQ System Code length */
#define RFAL_NFCF_SENSF_PARAMS_SC1_POS 0U /*!< System Code byte1 position in the SENSF_REQ */
#define RFAL_NFCF_SENSF_PARAMS_SC2_POS 1U /*!< System Code byte2 position in the SENSF_REQ */
#define RFAL_NFCF_SENSF_PARAMS_RC_POS 2U /*!< Request Code position in the SENSF_REQ */
#define RFAL_NFCF_SENSF_PARAMS_TSN_POS 3U /*!< Time Slot Number position in the SENSF_REQ */
#define RFAL_NFCF_POLL_MAXCARDS 16U /*!< Max number slots/cards 16 */
#define RFAL_NFCF_CMD_POS 0U /*!< Command/Response code length */
#define RFAL_NFCF_CMD_LEN 1U /*!< Command/Response code length */
#define RFAL_NFCF_LENGTH_LEN 1U /*!< LEN field length */
#define RFAL_NFCF_HEADER_LEN (RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CMD_LEN) /*!< Header length*/
#define RFAL_NFCF_SENSF_NFCID2_BYTE1_POS \
0U /*!< NFCID2 byte1 position */
#define RFAL_NFCF_SENSF_NFCID2_BYTE2_POS \
1U /*!< NFCID2 byte2 position */
#define RFAL_NFCF_SENSF_NFCID2_PROT_TYPE_LEN \
2U /*!< NFCID2 length for byte 1 and byte 2 indicating NFC-DEP or T3T support */
#define RFAL_NFCF_SENSF_NFCID2_BYTE1_NFCDEP \
0x01U /*!< NFCID2 byte1 NFC-DEP support Digital 1.0 Table 44 */
#define RFAL_NFCF_SENSF_NFCID2_BYTE2_NFCDEP \
0xFEU /*!< NFCID2 byte2 NFC-DEP support Digital 1.0 Table 44 */
#define RFAL_NFCF_SYSTEMCODE \
0xFFFFU /*!< SENSF_RES Default System Code Digital 1.0 6.6.1.1 */
#define RFAL_NFCF_BLOCK_LEN \
16U /*!< NFCF T3T Block size T3T 1.0 4.1 */
#define RFAL_NFCF_CHECKUPDATE_RES_ST1_POS \
9U /*!< Check|Update Res Status Flag 1 position T3T 1.0 Table 8 */
#define RFAL_NFCF_CHECKUPDATE_RES_ST2_POS \
10U /*!< Check|Update Res Status Flag 2 position T3T 1.0 Table 8 */
#define RFAL_NFCF_CHECKUPDATE_RES_NOB_POS \
11U /*!< Check|Update Res Number of Blocks position T3T 1.0 Table 8 */
#define RFAL_NFCF_STATUS_FLAG_SUCCESS \
0x00U /*!< Check response Number of Blocks position T3T 1.0 Table 11 */
#define RFAL_NFCF_STATUS_FLAG_ERROR \
0xFFU /*!< Check response Number of Blocks position T3T 1.0 Table 11 */
#define RFAL_NFCF_BLOCKLISTELEM_LEN \
0x80U /*!< Block List Element Length bit (2|3 bytes) T3T 1.0 5.6.1 */
#define RFAL_NFCF_SERVICECODE_RDONLY \
0x000BU /*!< NDEF Service Code as Read-Only T3T 1.0 7.2.1 */
#define RFAL_NFCF_SERVICECODE_RDWR \
0x0009U /*!< NDEF Service Code as Read and Write T3T 1.0 7.2.1 */
/*! NFC-F Felica command set JIS X6319-4 9.1 */
enum {
RFAL_NFCF_CMD_POLLING =
0x00, /*!< SENSF_REQ (Felica Poll/REQC command to identify a card ) */
RFAL_NFCF_CMD_POLLING_RES =
0x01, /*!< SENSF_RES (Felica Poll/REQC command response ) */
RFAL_NFCF_CMD_REQUEST_SERVICE =
0x02, /*!< verify the existence of Area and Service */
RFAL_NFCF_CMD_REQUEST_RESPONSE =
0x04, /*!< verify the existence of a card */
RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION =
0x06, /*!< read Block Data from a Service that requires no authentication */
RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION_RES =
0x07, /*!< read Block Data response from a Service with no authentication */
RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION =
0x08, /*!< write Block Data to a Service that requires no authentication */
RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION_RES =
0x09, /*!< write Block Data response to a Service with no authentication */
RFAL_NFCF_CMD_REQUEST_SYSTEM_CODE =
0x0c, /*!< acquire the System Code registered to a card */
RFAL_NFCF_CMD_AUTHENTICATION1 =
0x10, /*!< authenticate a card */
RFAL_NFCF_CMD_AUTHENTICATION2 =
0x12, /*!< allow a card to authenticate a Reader/Writer */
RFAL_NFCF_CMD_READ =
0x14, /*!< read Block Data from a Service that requires authentication */
RFAL_NFCF_CMD_WRITE =
0x16, /*!< write Block Data to a Service that requires authentication */
};
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
/*! Checks if the given NFC-F device indicates NFC-DEP support */
#define rfalNfcfIsNfcDepSupported(dev) \
((((rfalNfcfListenDevice*)(dev))->sensfRes.NFCID2[RFAL_NFCF_SENSF_NFCID2_BYTE1_POS] == \
RFAL_NFCF_SENSF_NFCID2_BYTE1_NFCDEP) && \
(((rfalNfcfListenDevice*)(dev))->sensfRes.NFCID2[RFAL_NFCF_SENSF_NFCID2_BYTE2_POS] == \
RFAL_NFCF_SENSF_NFCID2_BYTE2_NFCDEP))
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
/*! NFC-F SENSF_RES format Digital 1.1 8.6.2 */
typedef struct {
uint8_t CMD; /*!< Command Code: 01h */
uint8_t NFCID2[RFAL_NFCF_NFCID2_LEN]; /*!< NFCID2 */
uint8_t PAD0[RFAL_NFCF_SENSF_RES_PAD0_LEN]; /*!< PAD0 */
uint8_t PAD1[RFAL_NFCF_SENSF_RES_PAD1_LEN]; /*!< PAD1 */
uint8_t MRTIcheck; /*!< MRTIcheck */
uint8_t MRTIupdate; /*!< MRTIupdate */
uint8_t PAD2; /*!< PAD2 */
uint8_t RD[RFAL_NFCF_SENSF_RES_RD_LEN]; /*!< Request Data */
} rfalNfcfSensfRes;
/*! NFC-F poller device (PCD) struct */
typedef struct {
uint8_t NFCID2[RFAL_NFCF_NFCID2_LEN]; /*!< NFCID2 */
} rfalNfcfPollDevice;
/*! NFC-F listener device (PICC) struct */
typedef struct {
uint8_t sensfResLen; /*!< SENF_RES length */
rfalNfcfSensfRes sensfRes; /*!< SENF_RES */
} rfalNfcfListenDevice;
typedef uint16_t rfalNfcfServ; /*!< NFC-F Service Code */
/*! NFC-F Block List Element (2 or 3 bytes element) T3T 1.0 5.6.1 */
typedef struct {
uint8_t conf; /*!< Access Mode | Serv Code List Order */
uint16_t blockNum; /*!< Block Number */
} rfalNfcfBlockListElem;
/*! Check Update Service list and Block list parameter */
typedef struct {
uint8_t numServ; /*!< Number of Services */
rfalNfcfServ* servList; /*!< Service Code List */
uint8_t numBlock; /*!< Number of Blocks */
rfalNfcfBlockListElem* blockList; /*!< Block Number List */
} rfalNfcfServBlockListParam;
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief Initialize NFC-F Poller mode
*
* This methods configures RFAL RF layer to perform as a
* NFC-F Poller/RW (FeliCa PCD) including all default timings
*
* \param[in] bitRate : NFC-F bitrate to be initialize (212 or 424)
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Incorrect bitrate
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcfPollerInitialize(rfalBitRate bitRate);
/*!
*****************************************************************************
* \brief NFC-F Poller Check Presence
*
* This function sends a Poll/SENSF command according to NFC Activity spec
* It detects if a NCF-F device is within range
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error, no listener device detected
* \return ERR_NONE : No error and some NFC-F device was detected
*
*****************************************************************************
*/
ReturnCode rfalNfcfPollerCheckPresence(void);
/*!
*****************************************************************************
* \brief NFC-F Poller Poll
*
* This function sends to all PICCs in field the POLL command with the given
* number of slots.
*
* \param[in] slots : the number of slots to be performed
* \param[in] sysCode : as given in FeliCa poll command
* \param[in] reqCode : FeliCa communication parameters
* \param[out] cardList : Parameter of type rfalFeliCaPollRes which will hold the cards found
* \param[out] devCnt : actual number of cards found
* \param[out] collisions : number of collisions encountered
*
* \warning the list cardList has to be as big as the number of slots for the Poll
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error, no listener device detected
* \return ERR_NONE : No error and some NFC-F device was detected
*
*****************************************************************************
*/
ReturnCode rfalNfcfPollerPoll(
rfalFeliCaPollSlots slots,
uint16_t sysCode,
uint8_t reqCode,
rfalFeliCaPollRes* cardList,
uint8_t* devCnt,
uint8_t* collisions);
/*!
*****************************************************************************
* \brief NFC-F Poller Full Collision Resolution
*
* Performs a full Collision resolution as defined in Activity 1.1 9.3.4
*
* \param[in] compMode : compliance mode to be performed
* \param[in] devLimit : device limit value, and size nfcaDevList
* \param[out] nfcfDevList : NFC-F listener devices list
* \param[out] devCnt : Devices found counter
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcfPollerCollisionResolution(
rfalComplianceMode compMode,
uint8_t devLimit,
rfalNfcfListenDevice* nfcfDevList,
uint8_t* devCnt);
/*!
*****************************************************************************
* \brief NFC-F Poller Check/Read
*
* It computes a Check / Read command according to T3T 1.0 and JIS X6319-4 and
* sends it to PICC. If successfully, the rxBuf will contain the the number of
* blocks in the first byte followed by the blocks data.
*
* \param[in] nfcid2 : nfcid2 of the device
* \param[in] servBlock : parameter containing the list of Services and
* Blocks to be addressed by this command
* \param[out] rxBuf : buffer to place check/read data
* \param[in] rxBufLen : size of the rxBuf
* \param[out] rcvdLen : length of data placed in rxBuf
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_REQUEST : The request was executed with error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcfPollerCheck(
const uint8_t* nfcid2,
const rfalNfcfServBlockListParam* servBlock,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvdLen);
/*!
*****************************************************************************
* \brief NFC-F Poller Update/Write
*
* It computes a Update / Write command according to T3T 1.0 and JIS X6319-4 and
* sends it to PICC.
*
* \param[in] nfcid2 : nfcid2 of the device
* \param[in] servBlock : parameter containing the list of Services and
* Blocks to be addressed by this command
* \param[in] txBuf : buffer where the request will be composed
* \param[in] txBufLen : size of txBuf
* \param[in] blockData : data to written on the given block(s)
* \param[out] rxBuf : buffer to place check/read data
* \param[in] rxBufLen : size of the rxBuf
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_REQUEST : The request was executed with error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcfPollerUpdate(
const uint8_t* nfcid2,
const rfalNfcfServBlockListParam* servBlock,
uint8_t* txBuf,
uint16_t txBufLen,
const uint8_t* blockData,
uint8_t* rxBuf,
uint16_t rxBufLen);
/*!
*****************************************************************************
* \brief NFC-F Listener is T3T Request
*
* This method checks if the given data is a valid T3T command (Read or Write)
* and in case a valid request has been received it may output the request's NFCID2
*
* \param[in] buf : buffer holding Initiator's received command
* \param[in] bufLen : length of received command in bytes
* \param[out] nfcid2 : pointer to where the NFCID2 may be outputted,
* nfcid2 has NFCF_SENSF_NFCID2_LEN as length
* Pass NULL if output parameter not desired
*
* \return true : Valid T3T command (Read or Write) received
* \return false : Invalid protocol request
*
*****************************************************************************
*/
bool rfalNfcfListenerIsT3TReq(const uint8_t* buf, uint16_t bufLen, uint8_t* nfcid2);
#endif /* RFAL_NFCF_H */
/**
* @}
*
* @}
*
* @}
*/
-923
View File
@@ -1,923 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_nfcv.h
*
* \author Gustavo Patricio
*
* \brief Implementation of NFC-V Poller (ISO15693) device
*
* The definitions and helpers methods provided by this module
* are aligned with NFC-V Digital 2.1
*
*
* \addtogroup RFAL
* @{
*
* \addtogroup RFAL-AL
* \brief RFAL Abstraction Layer
* @{
*
* \addtogroup NFC-V
* \brief RFAL NFC-V Module
* @{
*
*/
#ifndef RFAL_NFCV_H
#define RFAL_NFCV_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
#include "st_errno.h"
#include "rfal_rf.h"
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_NFCV_UID_LEN 8U /*!< NFC-V UID length */
#define RFAL_NFCV_MAX_BLOCK_LEN \
32U /*!< Max Block size: can be of up to 256 bits ISO 15693 2000 5 */
#define RFAL_NFCV_BNO_LEN 1U /*!< NFC-V Block Number length */
#define RFAL_NFCV_CRC_LEN 2U /*!< NFC-V CRC length */
#define RFAL_NFCV_MAX_GEN_DATA_LEN \
(RFAL_NFCV_MAX_BLOCK_LEN + RFAL_NFCV_BNO_LEN + RFAL_NFCV_UID_LEN) /*!<Max data */
#define RFAL_NFCV_BLOCKNUM_LEN \
1U /*!< Block Number length on normal commands: 8 bits */
#define RFAL_NFCV_BLOCKNUM_EXTENDED_LEN \
2U /*!< Block Number length on extended commands: 16 bits */
#define RFAL_NFCV_PARAM_SKIP \
0U /*!< Skip proprietary Param Request */
/*! NFC-V RequestFlags ISO15693 2000 7.3.1 */
enum {
RFAL_NFCV_REQ_FLAG_DEFAULT =
0x02U, /*!< Default Request Flags */
RFAL_NFCV_REQ_FLAG_SUB_CARRIER =
0x01U, /*!< Sub Carrier flag */
RFAL_NFCV_REQ_FLAG_DATA_RATE =
0x02U, /*!< Data Rate flag */
RFAL_NFCV_REQ_FLAG_INVENTORY =
0x04U, /*!< Inventory flag */
RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT =
0x08U, /*!< Protocol Extension flag */
RFAL_NFCV_REQ_FLAG_SELECT =
0x10U, /*!< Select flag */
RFAL_NFCV_REQ_FLAG_ADDRESS =
0x20U, /*!< Address flag */
RFAL_NFCV_REQ_FLAG_OPTION =
0x40U, /*!< Option flag */
RFAL_NFCV_REQ_FLAG_RFU =
0x80U, /*!< RFU flag */
RFAL_NFCV_REQ_FLAG_AFI =
0x10U, /*!< AFI flag */
RFAL_NFCV_REQ_FLAG_NB_SLOTS =
0x20U, /*!< Number of Slots flag */
};
/*! NFC-V Response Flags ISO15693 2000 7.4.1 */
enum {
RFAL_NFCV_RES_FLAG_ERROR =
0x01U, /*!< Error flag */
RFAL_NFCV_RES_FLAG_RFU1 =
0x02U, /*!< RFU flag */
RFAL_NFCV_RES_FLAG_RFU2 =
0x04U, /*!< RFU flag */
RFAL_NFCV_RES_FLAG_EXTENSION =
0x08U, /*!< Extension flag */
RFAL_NFCV_RES_FLAG_RFU3 =
0x10U, /*!< RFU flag */
RFAL_NFCV_RES_FLAG_RFU4 =
0x20U, /*!< RFU flag */
RFAL_NFCV_RES_FLAG_RFU5 =
0x40U, /*!< RFU flag */
RFAL_NFCV_RES_FLAG_RFU6 =
0x80U /*!< RFU flag */
};
/*! NFC-V Error code ISO15693 2000 7.4.2 */
enum {
RFAL_NFCV_ERROR_CMD_NOT_SUPPORTED =
0x01U, /*!< The command is not supported, code is not recognised */
RFAL_NFCV_ERROR_CMD_NOT_RECOGNIZED =
0x02U, /*!< The command is not recognised, format error occurred */
RFAL_NFCV_ERROR_OPTION_NOT_SUPPORTED =
0x03U, /*!< The option is not supported */
RFAL_NFCV_ERROR_UNKNOWN =
0x0FU, /*!< Unknown error */
RFAL_NFCV_ERROR_BLOCK_NOT_AVALIABLE =
0x10U, /*!< The specified block is not available */
RFAL_NFCV_ERROR_BLOCK_ALREDY_LOCKED =
0x11U, /*!< The specified block is already locked */
RFAL_NFCV_ERROR_BLOCK_LOCKED =
0x12U, /*!< The specified block is locked */
RFAL_NFCV_ERROR_WRITE_FAILED =
0x13U, /*!< The specified block was not successfully programmed */
RFAL_NFCV_ERROR_BLOCK_FAILED =
0x14U /*!< The specified block was not successfully locked */
};
/*! NFC-V command set ISO15693 2000 9.1 */
enum {
RFAL_NFCV_CMD_INVENTORY =
0x01U, /*!< INVENTORY_REQ (Inventory) command */
RFAL_NFCV_CMD_SLPV =
0x02U, /*!< SLPV_REQ (Stay quiet) command */
RFAL_NFCV_CMD_READ_SINGLE_BLOCK =
0x20U, /*!< Read single block command */
RFAL_NFCV_CMD_WRITE_SINGLE_BLOCK =
0x21U, /*!< Write single block command */
RFAL_NFCV_CMD_LOCK_BLOCK =
0x22U, /*!< Lock block command */
RFAL_NFCV_CMD_READ_MULTIPLE_BLOCKS =
0x23U, /*!< Read multiple blocks command */
RFAL_NFCV_CMD_WRITE_MULTIPLE_BLOCKS =
0x24U, /*!< Write multiple blocks command */
RFAL_NFCV_CMD_SELECT =
0x25U, /*!< Select command */
RFAL_NFCV_CMD_RESET_TO_READY =
0x26U, /*!< Reset To Ready command */
RFAL_NFCV_CMD_GET_SYS_INFO =
0x2BU, /*!< Get System Information command */
RFAL_NFCV_CMD_EXTENDED_READ_SINGLE_BLOCK =
0x30U, /*!< Extended read single block command */
RFAL_NFCV_CMD_EXTENDED_WRITE_SINGLE_BLOCK =
0x31U, /*!< Extended write single block command */
RFAL_NFCV_CMD_EXTENDED_LOCK_SINGLE_BLOCK =
0x32U, /*!< Extended lock single block command */
RFAL_NFCV_CMD_EXTENDED_READ_MULTIPLE_BLOCK =
0x33U, /*!< Extended read multiple block command */
RFAL_NFCV_CMD_EXTENDED_WRITE_MULTIPLE_BLOCK =
0x34U, /*!< Extended read multiple block command */
RFAL_NFCV_CMD_EXTENDED_GET_SYS_INFO =
0x3BU /*!< Extended Get System Information command */
};
/*! ST25TV/ST25DV command set */
enum {
RFAL_NFCV_CMD_READ_CONFIGURATION =
0xA0U, /*!< Read configuration command */
RFAL_NFCV_CMD_WRITE_CONFIGURATION =
0xA1U, /*!< Write configuration command */
RFAL_NFCV_CMD_SET_EAS =
0xA2U, /*!< Set EAS command */
RFAL_NFCV_CMD_RESET_EAS =
0xA3U, /*!< Reset EAS command */
RFAL_NFCV_CMD_LOCK_EAS =
0xA4U, /*!< Lock EAS command */
RFAL_NFCV_CMD_ENABLE_EAS =
0xA5U, /*!< Enable EAS command */
RFAL_NFCV_CMD_KILL = 0xA6U, /*!< Kill command */
RFAL_NFCV_CMD_WRITE_EAS_ID =
0xA7U, /*!< Write EAS ID command */
RFAL_NFCV_CMD_WRITE_EAS_CONFIG =
0xA8U, /*!< Write EAS CONFIG command */
RFAL_NFCV_CMD_MANAGE_GPO =
0xA9U, /*!< Manage GPO command */
RFAL_NFCV_CMD_WRITE_MESSAGE =
0xAAU, /*!< Write Message command */
RFAL_NFCV_CMD_READ_MESSAGE_LENGTH =
0xABU, /*!< Read Message Length command */
RFAL_NFCV_CMD_READ_MESSAGE =
0xACU, /*!< Read Message command */
RFAL_NFCV_CMD_READ_DYN_CONFIGURATION =
0xADU, /*!< Read Dynamic Configuration command */
RFAL_NFCV_CMD_WRITE_DYN_CONFIGURATION =
0xAEU, /*!< Write Dynamic Configuration command */
RFAL_NFCV_CMD_WRITE_PASSWORD =
0xB1U, /*!< Write Kill Password / Write Password command */
RFAL_NFCV_CMD_LOCK_KILL =
0xB2U, /*!< Lock Kill command */
RFAL_NFCV_CMD_PRESENT_PASSWORD =
0xB3U, /*!< Present Password command */
RFAL_NFCV_CMD_GET_RANDOM_NUMBER =
0xB4U, /*!< Get Random Number command */
RFAL_NFCV_CMD_FAST_READ_SINGLE_BLOCK =
0xC0U, /*!< Fast Read single block command */
RFAL_NFCV_CMD_FAST_READ_MULTIPLE_BLOCKS =
0xC3U, /*!< Fast Read multiple blocks command */
RFAL_NFCV_CMD_FAST_EXTENDED_READ_SINGLE_BLOCK =
0xC4U, /*!< Fast Extended Read single block command */
RFAL_NFCV_CMD_FAST_EXTENDED_READ_MULTIPLE_BLOCKS =
0xC5U, /*!< Fast Extended Read multiple blocks command */
RFAL_NFCV_CMD_FAST_WRITE_MESSAGE =
0xCAU, /*!< Fast Write Message */
RFAL_NFCV_CMD_FAST_READ_MESSAGE_LENGTH =
0xCBU, /*!< Fast Read Message Length */
RFAL_NFCV_CMD_FAST_READ_MESSAGE =
0xCCU, /*!< Fast Read Message */
RFAL_NFCV_CMD_FAST_READ_DYN_CONFIGURATION =
0xCDU, /*!< Fast Read Dynamic configuration */
RFAL_NFCV_CMD_FAST_WRITE_DYN_CONFIGURATION =
0xCEU /*!< Fast Write Dynamic Configuration */
};
/*! ISO 15693 Get System info parameter request field ISO15693 2018 Table 94 */
enum {
RFAL_NFCV_SYSINFO_DFSID =
0x01U, /*!< Get System info DFSID flag */
RFAL_NFCV_SYSINFO_AFI =
0x02U, /*!< Get System info AFI flag */
RFAL_NFCV_SYSINFO_MEMSIZE =
0x04U, /*!< Get System info MEMSIZE flag */
RFAL_NFCV_SYSINFO_ICREF =
0x08U, /*!< Get System info ICREF flag */
RFAL_NFCV_SYSINFO_MOI =
0x10U, /*!< Get System info MOI flag */
RFAL_NFCV_SYSINFO_CMDLIST =
0x20U, /*!< Get System info CMDLIST flag */
RFAL_NFCV_SYSINFO_CSI =
0x40U, /*!< Get System info CSI flag */
RFAL_NFCV_SYSINFO_REQ_ALL =
0x7FU /*!< Get System info request of all parameters */
};
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
/*! NFC-V Number of slots Digital 2.0 9.6.1 */
typedef enum {
RFAL_NFCV_NUM_SLOTS_1 = 0x20, /*!< Number of slots: 1 */
RFAL_NFCV_NUM_SLOTS_16 = 0x00, /*!< Number of slots: 16 */
} rfalNfcvNumSlots;
/*! NFC-V INVENTORY_RES format Digital 2.0 9.6.2 */
typedef struct {
uint8_t RES_FLAG; /*!< Response Flags */
uint8_t DSFID; /*!< Data Storage Format Identifier */
uint8_t UID[RFAL_NFCV_UID_LEN]; /*!< NFC-V device UID */
uint8_t crc[RFAL_CRC_LEN]; /*!< CRC */
} rfalNfcvInventoryRes;
/*! NFC-V Generic Req format */
typedef struct {
uint8_t REQ_FLAG; /*!< Request Flags */
uint8_t CMD; /*!< Command code */
union { /* PRQA S 0750 # MISRA 19.2 - Both members are of the same type, just different names. Thus no problem can occur. */
uint8_t UID[RFAL_NFCV_UID_LEN]; /*!< Mask Value */
uint8_t data[RFAL_NFCV_MAX_GEN_DATA_LEN]; /*!< Data */
} payload; /*!< Payload */
} rfalNfcvGenericReq;
/*! NFC-V Generic Response format */
typedef struct {
uint8_t RES_FLAG; /*!< Response Flags */
uint8_t data[RFAL_NFCV_MAX_GEN_DATA_LEN]; /*!< Data */
} rfalNfcvGenericRes;
/*! NFC-V listener device (VICC) struct */
typedef struct {
rfalNfcvInventoryRes InvRes; /*!< INVENTORY_RES */
bool isSleep; /*!< Device sleeping flag */
} rfalNfcvListenDevice;
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief Initialize NFC-V Poller mode
*
* This methods configures RFAL RF layer to perform as a
* NFC-F Poller/RW (ISO15693) including all default timings
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Incorrect bitrate
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcvPollerInitialize(void);
/*!
*****************************************************************************
* \brief NFC-V Poller Check Presence
*
* This method checks if a NFC-V Listen device (VICC) is present on the field
* by sending an Inventory (INVENTORY_REQ)
*
* \param[out] invRes : If received, the INVENTORY_RES
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_TIMEOUT : Timeout error, no listener device detectedd
* \return ERR_NONE : No error, one or more device in the field
*****************************************************************************
*/
ReturnCode rfalNfcvPollerCheckPresence(rfalNfcvInventoryRes* invRes);
/*!
*****************************************************************************
* \brief NFC-F Poller Poll
*
* This function sends to all VICCs in field the INVENTORY command with the
* given number of slots
*
* If more than one slot is used the following EOF need to be handled
* by the caller using rfalISO15693TransceiveEOFAnticollision()
*
* \param[in] nSlots : Number of Slots to be sent (1 or 16)
* \param[in] maskLen : Number bits on the Mask value
* \param[in] maskVal : location of the Mask value
* \param[out] invRes : location to place the INVENTORY_RES
* \param[out] rcvdLen : number of bits received (without collision)
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_RF_COLLISION : Collision detected
* \return ERR_CRC : CRC error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcvPollerInventory(
rfalNfcvNumSlots nSlots,
uint8_t maskLen,
const uint8_t* maskVal,
rfalNfcvInventoryRes* invRes,
uint16_t* rcvdLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Full Collision Resolution
*
* Performs a full Collision resolution as defined in Activity 2.0 9.3.7
* Once done, the devCnt will indicate how many (if any) devices have
* been identified and their details are contained on nfcvDevList
*
* \param[in] compMode : compliance mode to be performed
* \param[in] devLimit : device limit value, and size nfcaDevList
* \param[out] nfcvDevList : NFC-v listener devices list
* \param[out] devCnt : Devices found counter
*
* When compMode is set to ISO the function immediately goes to 16 slots improving
* chances to detect more than only one strong card.
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcvPollerCollisionResolution(
rfalComplianceMode compMode,
uint8_t devLimit,
rfalNfcvListenDevice* nfcvDevList,
uint8_t* devCnt);
/*!
*****************************************************************************
* \brief NFC-V Poller Full Collision Resolution With Sleep
*
* Performs a full Collision resolution which is different from Activity 2.0 9.3.7.
* The implementation uses SLPV (StayQuiet) command to make sure all cards are found.
* Once done, the devCnt will indicate how many (if any) devices have
* been identified and their details are contained on nfcvDevList
*
* \param[in] devLimit : device limit value, and size nfcaDevList
* \param[out] nfcvDevList : NFC-v listener devices list
* \param[out] devCnt : Devices found counter
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcvPollerSleepCollisionResolution(
uint8_t devLimit,
rfalNfcvListenDevice* nfcvDevList,
uint8_t* devCnt);
/*!
*****************************************************************************
* \brief NFC-V Poller Sleep
*
* This function is used to send the SLPV_REQ (Stay Quiet) command to put the VICC
* with the given UID to state QUIET so that they do not reply to more Inventory
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to Sleep
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcvPollerSleep(uint8_t flags, const uint8_t* uid);
/*!
*****************************************************************************
* \brief NFC-V Poller Select
*
* Selects a device (VICC) by its UID
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be Selected
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcvPollerSelect(uint8_t flags, const uint8_t* uid);
/*!
*****************************************************************************
* \brief NFC-V Poller Read Single Block
*
* Reads a Single Block from a device (VICC)
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if UID is provided Addressed mode will be used
* \param[in] blockNum : Number of the block to read
* \param[out] rxBuf : buffer to store response (also with RES_FLAGS)
* \param[in] rxBufLen : length of rxBuf
* \param[out] rcvLen : number of bytes received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcvPollerReadSingleBlock(
uint8_t flags,
const uint8_t* uid,
uint8_t blockNum,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Write Single Block
*
* Writes a Single Block from a device (VICC)
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be written
* if UID is provided Addressed mode will be used
* \param[in] blockNum : Number of the block to write
* \param[in] wrData : data to be written on the given block
* \param[in] blockLen : number of bytes of a block
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcvPollerWriteSingleBlock(
uint8_t flags,
const uint8_t* uid,
uint8_t blockNum,
const uint8_t* wrData,
uint8_t blockLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Read Multiple Blocks
*
* Reads Multiple Blocks from a device (VICC)
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if UID is provided Addressed mode will be used
* \param[in] firstBlockNum : first block to be read
* \param[in] numOfBlocks : number of block to read
* \param[out] rxBuf : buffer to store response (also with RES_FLAGS)
* \param[in] rxBufLen : length of rxBuf
* \param[out] rcvLen : number of bytes received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcvPollerReadMultipleBlocks(
uint8_t flags,
const uint8_t* uid,
uint8_t firstBlockNum,
uint8_t numOfBlocks,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Write Multiple Blocks
*
* Reads Multiple Blocks from a device (VICC)
* In order to not limit the length of the Write multiple command, a buffer
* must be provided where the request will be composed and then sent.
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if UID is provided Addressed mode will be used
* \param[in] firstBlockNum : first block to be write
* \param[in] numOfBlocks : number of consecutive blocks to write
* \param[in] txBuf : buffer where the request will be composed
* \param[in] txBufLen : length of txBuf
* \param[in] blockLen : number of bytes of a block
* \param[in] wrData : data to be written
* \param[in] wrDataLen : length of the data do be written. Must be
* aligned with number of blocks to write and
* the size of a block
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcvPollerWriteMultipleBlocks(
uint8_t flags,
const uint8_t* uid,
uint8_t firstBlockNum,
uint8_t numOfBlocks,
uint8_t* txBuf,
uint16_t txBufLen,
uint8_t blockLen,
const uint8_t* wrData,
uint16_t wrDataLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Extended Lock Single Block
*
* Blocks a Single Block from a device (VICC) supporting extended commands
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device
* if UID is provided Addressed mode will be used
* \param[in] blockNum : Number of the block to be locked
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcvPollerLockBlock(uint8_t flags, const uint8_t* uid, uint8_t blockNum);
/*!
*****************************************************************************
* \brief NFC-V Poller Extended Lock Single Block
*
* Blocks a Single Block from a device (VICC) supporting extended commands
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device
* if UID is provided Addressed mode will be used
* \param[in] blockNum : Number of the block to be locked (16 bits)
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode
rfalNfcvPollerExtendedLockSingleBlock(uint8_t flags, const uint8_t* uid, uint16_t blockNum);
/*!
*****************************************************************************
* \brief NFC-V Poller Extended Read Single Block
*
* Reads a Single Block from a device (VICC) supporting extended commands
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if UID is provided Addressed mode will be used
* \param[in] blockNum : Number of the block to read (16 bits)
* \param[out] rxBuf : buffer to store response (also with RES_FLAGS)
* \param[in] rxBufLen : length of rxBuf
* \param[out] rcvLen : number of bytes received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcvPollerExtendedReadSingleBlock(
uint8_t flags,
const uint8_t* uid,
uint16_t blockNum,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Extended Write Single Block
*
* Writes a Single Block from a device (VICC) supporting extended commands
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device
* if UID is provided Addressed mode will be used
* \param[in] blockNum : Number of the block to write (16 bits)
* \param[in] wrData : data to be written on the given block
* \param[in] blockLen : number of bytes of a block
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcvPollerExtendedWriteSingleBlock(
uint8_t flags,
const uint8_t* uid,
uint16_t blockNum,
const uint8_t* wrData,
uint8_t blockLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Extended Read Multiple Blocks
*
* Reads Multiple Blocks from a device (VICC) supporting extended commands
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if UID is provided Addressed mode will be used
* \param[in] firstBlockNum : first block to be read (16 bits)
* \param[in] numOfBlocks : number of consecutive blocks to read (16 bits)
* \param[out] rxBuf : buffer to store response (also with RES_FLAGS)
* \param[in] rxBufLen : length of rxBuf
* \param[out] rcvLen : number of bytes received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcvPollerExtendedReadMultipleBlocks(
uint8_t flags,
const uint8_t* uid,
uint16_t firstBlockNum,
uint16_t numOfBlocks,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Extended Write Multiple Blocks
*
* Writes Multiple Blocks from a device (VICC) supporting extended commands
* In order to not limit the length of the Write multiple command, a buffer
* must be provided where the request will be composed and then sent.
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if UID is provided Addressed mode will be used
* \param[in] firstBlockNum : first block to be write (16 bits)
* \param[in] numOfBlocks : number of consecutive blocks to write (16 bits)
* \param[in] txBuf : buffer where the request will be composed
* \param[in] txBufLen : length of txBuf
* \param[in] blockLen : number of bytes of a block
* \param[in] wrData : data to be written
* \param[in] wrDataLen : length of the data do be written. Must be
* aligned with number of blocks to write and
* the size of a block
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcvPollerExtendedWriteMultipleBlocks(
uint8_t flags,
const uint8_t* uid,
uint16_t firstBlockNum,
uint16_t numOfBlocks,
uint8_t* txBuf,
uint16_t txBufLen,
uint8_t blockLen,
const uint8_t* wrData,
uint16_t wrDataLen);
/*!
*****************************************************************************
* \brief NFC-V Get System Information
*
* Sends Get System Information command
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if UID is provided Addressed mode will be used
* \param[out] rxBuf : buffer to store response (also with RES_FLAGS)
* \param[in] rxBufLen : length of rxBuf
* \param[out] rcvLen : number of bytes received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcvPollerGetSystemInformation(
uint8_t flags,
const uint8_t* uid,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
/*!
*****************************************************************************
* \brief NFC-V Extended Get System Information
*
* Sends Extended Get System Information command
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if UID is provided Addressed mode will be used
* \param[in] requestField : Get System info parameter request field
* \param[out] rxBuf : buffer to store response (also with RES_FLAGS)
* \param[in] rxBufLen : length of rxBuf
* \param[out] rcvLen : number of bytes received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcvPollerExtendedGetSystemInformation(
uint8_t flags,
const uint8_t* uid,
uint8_t requestField,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
/*!
*****************************************************************************
* \brief NFC-V Transceive Request
*
* Performs a generic transceive with an ISO15693 tag
*
* \param[in] cmd : NFC-V command
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] param : Prepend parameter on certain proprietary requests
* For default commands skip: RFAL_NFCV_PARAM_SKIP
* \param[in] uid : UID of the device to be put to be read
* if UID is provided Addressed mode will be used
* \param[in] data : command parameters append after UID
* \param[in] dataLen : command parameters Len
* \param[out] rxBuf : buffer to store response (also with RES_FLAGS)
* \param[in] rxBufLen : length of rxBuf
* \param[out] rcvLen : number of bytes received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalNfcvPollerTransceiveReq(
uint8_t cmd,
uint8_t flags,
uint8_t param,
const uint8_t* uid,
const uint8_t* data,
uint16_t dataLen,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
#endif /* RFAL_NFCV_H */
/**
* @}
*
* @}
*
* @}
*/
File diff suppressed because it is too large Load Diff
-340
View File
@@ -1,340 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_st25tb.h
*
* \author Gustavo Patricio
*
* \brief Implementation of ST25TB interface
*
*
* \addtogroup RFAL
* @{
*
* \addtogroup RFAL-AL
* \brief RFAL Abstraction Layer
* @{
*
* \addtogroup ST25TB
* \brief RFAL ST25TB Module
* @{
*
*/
#ifndef RFAL_ST25TB_H
#define RFAL_ST25TB_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
#include "st_errno.h"
#include "rfal_rf.h"
#include "rfal_nfcb.h"
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_ST25TB_CHIP_ID_LEN 1U /*!< ST25TB chip ID length */
#define RFAL_ST25TB_CRC_LEN 2U /*!< ST25TB CRC length */
#define RFAL_ST25TB_UID_LEN 8U /*!< ST25TB Unique ID length */
#define RFAL_ST25TB_BLOCK_LEN 4U /*!< ST25TB Data Block length */
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
typedef uint8_t rfalSt25tbUID[RFAL_ST25TB_UID_LEN]; /*!< ST25TB UID type */
typedef uint8_t rfalSt25tbBlock[RFAL_ST25TB_BLOCK_LEN]; /*!< ST25TB Block type */
/*! ST25TB listener device (PICC) struct */
typedef struct {
uint8_t chipID; /*!< Device's session Chip ID */
rfalSt25tbUID UID; /*!< Device's UID */
bool isDeselected; /*!< Device deselect flag */
} rfalSt25tbListenDevice;
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief Initialize ST25TB Poller mode
*
* This methods configures RFAL RF layer to perform as a
* ST25TB Poller/RW including all default timings
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalSt25tbPollerInitialize(void);
/*!
*****************************************************************************
* \brief ST25TB Poller Check Presence
*
* This method checks if a ST25TB Listen device (PICC) is present on the field
* by sending an Initiate command
*
* \param[out] chipId : if successfully retrieved, the device's chip ID
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_TIMEOUT : Timeout error, no listener device detected
* \return ERR_RF_COLLISION : Collision detected one or more device in the field
* \return ERR_PROTO : Protocol error detected
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalSt25tbPollerCheckPresence(uint8_t* chipId);
/*!
*****************************************************************************
* \brief ST25TB Poller Collision Resolution
*
* This method performs ST25TB Collision resolution, selects the each device,
* retrieves its UID and then deselects.
* In case only one device is identified the ST25TB device is left in select
* state.
*
* \param[in] devLimit : device limit value, and size st25tbDevList
* \param[out] st25tbDevList : ST35TB listener device info
* \param[out] devCnt : Devices found counter
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_TIMEOUT : Timeout error, no listener device detected
* \return ERR_RF_COLLISION : Collision detected one or more device in the field
* \return ERR_PROTO : Protocol error detected
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalSt25tbPollerCollisionResolution(
uint8_t devLimit,
rfalSt25tbListenDevice* st25tbDevList,
uint8_t* devCnt);
/*!
*****************************************************************************
* \brief ST25TB Poller Initiate
*
* This method sends an Initiate command
*
* If a single device responds the chip ID will be retrieved
*
* \param[out] chipId : chip ID of the device
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_TIMEOUT : Timeout error, no listener device detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalSt25tbPollerInitiate(uint8_t* chipId);
/*!
*****************************************************************************
* \brief ST25TB Poller Pcall
*
* This method sends a Pcall command
* If successful the device's chip ID will be retrieved
*
* \param[out] chipId : Chip ID of the device
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_TIMEOUT : Timeout error, no listener device detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalSt25tbPollerPcall(uint8_t* chipId);
/*!
*****************************************************************************
* \brief ST25TB Poller Slot Marker
*
* This method sends a Slot Marker
*
* If a single device responds the chip ID will be retrieved
*
* \param[in] slotNum : Slot Number
* \param[out] chipIdRes : Chip ID of the device
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_TIMEOUT : Timeout error, no listener device detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalSt25tbPollerSlotMarker(uint8_t slotNum, uint8_t* chipIdRes);
/*!
*****************************************************************************
* \brief ST25TB Poller Select
*
* This method sends a ST25TB Select command with the given chip ID.
*
* If the device is already in Selected state and receives an incorrect chip
* ID, it goes into Deselected state
*
* \param[in] chipId : chip ID of the device to be selected
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_TIMEOUT : Timeout error, no listener device detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalSt25tbPollerSelect(uint8_t chipId);
/*!
*****************************************************************************
* \brief ST25TB Get UID
*
* This method sends a Get_UID command
*
* If a single device responds the chip UID will be retrieved
*
* \param[out] UID : UID of the found device
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_TIMEOUT : Timeout error, no listener device detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalSt25tbPollerGetUID(rfalSt25tbUID* UID);
/*!
*****************************************************************************
* \brief ST25TB Poller Read Block
*
* This method reads a block of the ST25TB
*
* \param[in] blockAddress : address of the block to be read
* \param[out] blockData : location to place the data read from block
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_TIMEOUT : Timeout error, no listener device detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalSt25tbPollerReadBlock(uint8_t blockAddress, rfalSt25tbBlock* blockData);
/*!
*****************************************************************************
* \brief ST25TB Poller Write Block
*
* This method writes a block of the ST25TB
*
* \param[in] blockAddress : address of the block to be written
* \param[in] blockData : data to be written on the block
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_TIMEOUT : Timeout error, no listener device detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalSt25tbPollerWriteBlock(uint8_t blockAddress, const rfalSt25tbBlock* blockData);
/*!
*****************************************************************************
* \brief ST25TB Poller Completion
*
* This method sends a completion command to the ST25TB. After the
* completion the card no longer will reply to any command.
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_TIMEOUT : Timeout error, no listener device detected
* \return ERR_PROTO : Protocol error detected, invalid SENSB_RES received
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalSt25tbPollerCompletion(void);
/*!
*****************************************************************************
* \brief ST25TB Poller Reset to Inventory
*
* This method sends a Reset to Inventory command to the ST25TB.
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_TIMEOUT : Timeout error, no listener device detected
* \return ERR_PROTO : Protocol error detected, invalid SENSB_RES received
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalSt25tbPollerResetToInventory(void);
#endif /* RFAL_ST25TB_H */
/**
* @}
*
* @}
*
* @}
*/
-844
View File
@@ -1,844 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_st25xv.h
*
* \author Gustavo Patricio
*
* \brief NFC-V ST25 NFC-V Tag specific features
*
* This module provides support for ST's specific features available on
* NFC-V (ISO15693) tag families: ST25D, ST25TV, M24LR
*
*
* \addtogroup RFAL
* @{
*
* \addtogroup RFAL-AL
* \brief RFAL Abstraction Layer
* @{
*
* \addtogroup ST25xV
* \brief RFAL ST25xV Module
* @{
*
*/
#ifndef RFAL_ST25xV_H
#define RFAL_ST25xV_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
#include "st_errno.h"
#include "rfal_nfc.h"
#include "rfal_rf.h"
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_NFCV_BLOCKNUM_M24LR_LEN \
2U /*!< Block Number length of MR24LR tags: 16 bits */
#define RFAL_NFCV_ST_IC_MFG_CODE \
0x02 /*!< ST IC Mfg code (used for custom commands) */
/*!
*****************************************************************************
* \brief NFC-V Poller Read Single Block (M24LR)
*
* Reads a Single Block from a M24LR tag which has the number of blocks
* bigger than 256 (M24LR16 ; M24LR64)
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* default: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] blockNum : Number of the block to read (16 bits)
* \param[out] rxBuf : buffer to store response (also with RES_FLAGS)
* \param[in] rxBufLen : length of rxBuf
* \param[out] rcvLen : number of bytes received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerM24LRReadSingleBlock(
uint8_t flags,
const uint8_t* uid,
uint16_t blockNum,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Fast Read Single Block (M24LR)
*
* Reads a Single Block from a M24LR tag which has the number of blocks
* bigger than 256 (M24LR16 ; M24LR64) using ST Fast mode
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* default: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] blockNum : Number of the block to read (16 bits)
* \param[out] rxBuf : buffer to store response (also with RES_FLAGS)
* \param[in] rxBufLen : length of rxBuf
* \param[out] rcvLen : number of bytes received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerM24LRFastReadSingleBlock(
uint8_t flags,
const uint8_t* uid,
uint16_t blockNum,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Write Single Block (M24LR)
*
* Writes a Single Block from a M24LR tag which has the number of blocks
* bigger than 256 (M24LR16 ; M24LR64)
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be written
* if not provided Select mode will be used
* \param[in] blockNum : Number of the block to write (16 bits)
* \param[in] wrData : data to be written on the given block
* \param[in] blockLen : number of bytes of a block
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerM24LRWriteSingleBlock(
uint8_t flags,
const uint8_t* uid,
uint16_t blockNum,
const uint8_t* wrData,
uint8_t blockLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Read Multiple Blocks (M24LR)
*
* Reads Multiple Blocks from a device from a M24LR tag which has the number of blocks
* bigger than 256 (M24LR16 ; M24LR64)
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] firstBlockNum : first block to be read (16 bits)
* \param[in] numOfBlocks : number of block to read
* \param[out] rxBuf : buffer to store response (also with RES_FLAGS)
* \param[in] rxBufLen : length of rxBuf
* \param[out] rcvLen : number of bytes received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerM24LRReadMultipleBlocks(
uint8_t flags,
const uint8_t* uid,
uint16_t firstBlockNum,
uint8_t numOfBlocks,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Fast Read Multiple Blocks (M24LR)
*
* Reads Multiple Blocks from a device from a M24LR tag which has the number of blocks
* bigger than 256 (M24LR16 ; M24LR64) using ST Fast mode
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] firstBlockNum : first block to be read (16 bits)
* \param[in] numOfBlocks : number of block to read
* \param[out] rxBuf : buffer to store response (also with RES_FLAGS)
* \param[in] rxBufLen : length of rxBuf
* \param[out] rcvLen : number of bytes received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerM24LRFastReadMultipleBlocks(
uint8_t flags,
const uint8_t* uid,
uint16_t firstBlockNum,
uint8_t numOfBlocks,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Fast Read Single Block
*
* Reads a Single Block from a device (VICC) using ST Fast mode
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] blockNum : Number of the block to read
* \param[out] rxBuf : buffer to store response (also with RES_FLAGS)
* \param[in] rxBufLen : length of rxBuf
* \param[out] rcvLen : number of bytes received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerFastReadSingleBlock(
uint8_t flags,
const uint8_t* uid,
uint8_t blockNum,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Fast Read Multiple Blocks
*
* Reads Multiple Blocks from a device (VICC) using ST Fast mode
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] firstBlockNum : first block to be read
* \param[in] numOfBlocks : number of block to read
* \param[out] rxBuf : buffer to store response (also with RES_FLAGS)
* \param[in] rxBufLen : length of rxBuf
* \param[out] rcvLen : number of bytes received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerFastReadMultipleBlocks(
uint8_t flags,
const uint8_t* uid,
uint8_t firstBlockNum,
uint8_t numOfBlocks,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Fast Extended Read Single Block
*
* Reads a Single Block from a device (VICC) supporting extended commands using ST Fast mode
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] blockNum : Number of the block to read (16 bits)
* \param[out] rxBuf : buffer to store response (also with RES_FLAGS)
* \param[in] rxBufLen : length of rxBuf
* \param[out] rcvLen : number of bytes received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerFastExtendedReadSingleBlock(
uint8_t flags,
const uint8_t* uid,
uint16_t blockNum,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Fast Extended Read Multiple Blocks
*
* Reads Multiple Blocks from a device (VICC) supporting extended commands using ST Fast mode
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] firstBlockNum : first block to be read (16 bits)
* \param[in] numOfBlocks : number of consecutive blocks to read (16 bits)
* \param[out] rxBuf : buffer to store response (also with RES_FLAGS)
* \param[in] rxBufLen : length of rxBuf
* \param[out] rcvLen : number of bytes received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerFastExtReadMultipleBlocks(
uint8_t flags,
const uint8_t* uid,
uint16_t firstBlockNum,
uint16_t numOfBlocks,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Read Configuration
*
* Reads static configuration registers at the Pointer address
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] pointer : Pointer address
* \param[out] regValue : Register value
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerReadConfiguration(
uint8_t flags,
const uint8_t* uid,
uint8_t pointer,
uint8_t* regValue);
/*!
*****************************************************************************
* \brief NFC-V Poller Write Configuration
*
* Writes static configuration registers at the Pointer address
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] pointer : Pointer address
* \param[in] regValue : Register value
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerWriteConfiguration(
uint8_t flags,
const uint8_t* uid,
uint8_t pointer,
uint8_t regValue);
/*!
*****************************************************************************
* \brief NFC-V Poller Read Dynamic Configuration
*
* Reads dynamic registers at the Pointer address
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] pointer : Pointer address
* \param[out] regValue : Register value
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerReadDynamicConfiguration(
uint8_t flags,
const uint8_t* uid,
uint8_t pointer,
uint8_t* regValue);
/*!
*****************************************************************************
* \brief NFC-V Poller Write Dynamic Configuration
*
* Writes dynamic registers at the Pointer address
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] pointer : Pointer address
* \param[in] regValue : Register value
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerWriteDynamicConfiguration(
uint8_t flags,
const uint8_t* uid,
uint8_t pointer,
uint8_t regValue);
/*!
*****************************************************************************
* \brief NFC-V Poller Fast Read Dynamic Configuration
*
* Reads dynamic registers at the Pointer address using ST Fast mode
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] pointer : Pointer address
* \param[out] regValue : Register value
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerFastReadDynamicConfiguration(
uint8_t flags,
const uint8_t* uid,
uint8_t pointer,
uint8_t* regValue);
/*!
*****************************************************************************
* \brief NFC-V Poller Fast Write Dynamic Configuration
*
* Writes dynamic registers at the Pointer address using ST Fast mode
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] pointer : Pointer address
* \param[in] regValue : Register value
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerFastWriteDynamicConfiguration(
uint8_t flags,
const uint8_t* uid,
uint8_t pointer,
uint8_t regValue);
/*!
*****************************************************************************
* \brief NFC-V Poller Present Password
*
* Sends the Present Password command
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] pwdNum : Password number
* \param[in] pwd : Password
* \param[in] pwdLen : Password length
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerPresentPassword(
uint8_t flags,
const uint8_t* uid,
uint8_t pwdNum,
const uint8_t* pwd,
uint8_t pwdLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Get Random Number
*
* Returns a 16 bit random number
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[out] rxBuf : buffer to store response (also with RES_FLAGS)
* \param[in] rxBufLen : length of rxBuf
* \param[out] rcvLen : number of bytes received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerGetRandomNumber(
uint8_t flags,
const uint8_t* uid,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Read Message length
*
* Sends a Read Message Length message to retrieve the value of MB_LEN_Dyn
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[out] msgLen : Message Length
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerReadMessageLength(uint8_t flags, const uint8_t* uid, uint8_t* msgLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Fast Read Message length
*
* Sends a Fast Read Message Length message to retrieve the value of MB_LEN_Dyn using ST Fast mode.
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[out] msgLen : Message Length
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerFastReadMsgLength(uint8_t flags, const uint8_t* uid, uint8_t* msgLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Read Message
*
* Reads up to 256 bytes in the Mailbox from the location
* specified by MBpointer and sends back their value in the rxBuf response.
* First MailBox location is '00'. When Number of bytes is set to 00h
* and MBPointer is equals to 00h, the MB_LEN bytes of the full message
* are returned. Otherwise, Read Message command returns (Number of Bytes + 1) bytes
* (i.e. 01h returns 2 bytes, FFh returns 256 bytes).
* An error is reported if (Pointer + Nb of bytes + 1) is greater than the message length.
* RF Reading of the last byte of the mailbox message automatically clears b1
* of MB_CTRL_Dyn HOST_PUT_MSG, and allows RF to put a new message.
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] mbPointer : MPpointer
* \param[in] numBytes : number of bytes
* \param[out] rxBuf : buffer to store response (also with RES_FLAGS)
* \param[in] rxBufLen : length of rxBuf
* \param[out] rcvLen : number of bytes received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerReadMessage(
uint8_t flags,
const uint8_t* uid,
uint8_t mbPointer,
uint8_t numBytes,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Fast Read Message
*
* Reads up to 256 bytes in the Mailbox from the location
* specified by MBpointer and sends back their value in the rxBuf response using ST Fast mode.
* First MailBox location is '00'. When Number of bytes is set to 00h
* and MBPointer is equals to 00h, the MB_LEN bytes of the full message
* are returned. Otherwise, Read Message command returns (Number of Bytes + 1) bytes
* (i.e. 01h returns 2 bytes, FFh returns 256 bytes).
* An error is reported if (Pointer + Nb of bytes + 1) is greater than the message length.
* RF Reading of the last byte of the mailbox message automatically clears b1
* of MB_CTRL_Dyn HOST_PUT_MSG, and allows RF to put a new message.
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] mbPointer : MPpointer
* \param[in] numBytes : number of bytes
* \param[out] rxBuf : buffer to store response (also with RES_FLAGS)
* \param[in] rxBufLen : length of rxBuf
* \param[out] rcvLen : number of bytes received
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerFastReadMessage(
uint8_t flags,
const uint8_t* uid,
uint8_t mbPointer,
uint8_t numBytes,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Write Message
*
* Sends Write message Command
*
* On receiving the Write Message command, the ST25DVxxx puts the data contained
* in the request into the Mailbox buffer, update the MB_LEN_Dyn register, and
* set bit RF_PUT_MSG in MB_CTRL_Dyn register. It then reports if the write operation was successful
* in the response. The ST25DVxxx Mailbox contains up to 256 data bytes which are filled from the
* first location '00'. MSGlength parameter of the command is the number of
* Data bytes minus 1 (00 for 1 byte of data, FFh for 256 bytes of data).
* Write Message could be executed only when Mailbox is accessible by RF.
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] msgLen : MSGLen number of Data bytes minus 1
* \param[in] msgData : Message Data
* \param[out] txBuf : buffer to used to build the Write Message command
* \param[in] txBufLen : length of txBuf
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerWriteMessage(
uint8_t flags,
const uint8_t* uid,
uint8_t msgLen,
const uint8_t* msgData,
uint8_t* txBuf,
uint16_t txBufLen);
/*!
*****************************************************************************
* \brief NFC-V Poller Fast Write Message
*
* Sends Fast Write message Command using ST Fast mode
*
* On receiving the Write Message command, the ST25DVxxx puts the data contained
* in the request into the Mailbox buffer, update the MB_LEN_Dyn register, and
* set bit RF_PUT_MSG in MB_CTRL_Dyn register. It then reports if the write operation was successful
* in the response. The ST25DVxxx Mailbox contains up to 256 data bytes which are filled from the
* first location '00'. MSGlength parameter of the command is the number of
* Data bytes minus 1 (00 for 1 byte of data, FFh for 256 bytes of data).
* Write Message could be executed only when Mailbox is accessible by RF.
*
* \param[in] flags : Flags to be used: Sub-carrier; Data_rate; Option
* for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
* \param[in] uid : UID of the device to be put to be read
* if not provided Select mode will be used
* \param[in] msgLen : MSGLen number of Data bytes minus 1
* \param[in] msgData : Message Data
* \param[out] txBuf : buffer to used to build the Write Message command
* \param[in] txBufLen : length of txBuf
*
* \return ERR_WRONG_STATE : RFAL not initialized or incorrect mode
* \return ERR_PARAM : Invalid parameters
* \return ERR_IO : Generic internal error
* \return ERR_CRC : CRC error detected
* \return ERR_FRAMING : Framing error detected
* \return ERR_PROTO : Protocol error detected
* \return ERR_TIMEOUT : Timeout error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalST25xVPollerFastWriteMessage(
uint8_t flags,
const uint8_t* uid,
uint8_t msgLen,
const uint8_t* msgData,
uint8_t* txBuf,
uint16_t txBufLen);
#endif /* RFAL_ST25xV_H */
/**
* @}
*
* @}
*
* @}
*/
-178
View File
@@ -1,178 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_t1t.h
*
* \author Gustavo Patricio
*
* \brief Provides NFC-A T1T convenience methods and definitions
*
* This module provides an interface to perform as a NFC-A Reader/Writer
* to handle a Type 1 Tag T1T (Topaz)
*
*
* \addtogroup RFAL
* @{
*
* \addtogroup RFAL-AL
* \brief RFAL Abstraction Layer
* @{
*
* \addtogroup T1T
* \brief RFAL T1T Module
* @{
*
*/
#ifndef RFAL_T1T_H
#define RFAL_T1T_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
#include "st_errno.h"
#include "rfal_rf.h"
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_T1T_UID_LEN 4 /*!< T1T UID length of cascade level 1 only tag */
#define RFAL_T1T_HR_LENGTH 2 /*!< T1T HR(Header ROM) length */
#define RFAL_T1T_HR0_NDEF_MASK 0xF0 /*!< T1T HR0 NDEF capability mask T1T 1.2 2.2.2 */
#define RFAL_T1T_HR0_NDEF_SUPPORT 0x10 /*!< T1T HR0 NDEF capable value T1T 1.2 2.2.2 */
/*! NFC-A T1T (Topaz) command set */
typedef enum {
RFAL_T1T_CMD_RID = 0x78, /*!< T1T Read UID */
RFAL_T1T_CMD_RALL = 0x00, /*!< T1T Read All */
RFAL_T1T_CMD_READ = 0x01, /*!< T1T Read */
RFAL_T1T_CMD_WRITE_E = 0x53, /*!< T1T Write with erase (single byte) */
RFAL_T1T_CMD_WRITE_NE = 0x1A /*!< T1T Write with no erase (single byte) */
} rfalT1Tcmds;
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
/*! NFC-A T1T (Topaz) RID_RES Digital 1.1 10.6.2 & Table 50 */
typedef struct {
uint8_t hr0; /*!< T1T Header ROM: HR0 */
uint8_t hr1; /*!< T1T Header ROM: HR1 */
uint8_t uid[RFAL_T1T_UID_LEN]; /*!< T1T UID */
} rfalT1TRidRes;
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief Initialize NFC-A T1T Poller mode
*
* This methods configures RFAL RF layer to perform as a
* NFC-A T1T Poller/RW (Topaz) including all default timings
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalT1TPollerInitialize(void);
/*!
*****************************************************************************
* \brief NFC-A T1T Poller RID
*
* This method reads the UID of a NFC-A T1T Listener device
*
*
* \param[out] ridRes : pointer to place the RID_RES
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Invalid parameter
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalT1TPollerRid(rfalT1TRidRes* ridRes);
/*!
*****************************************************************************
* \brief NFC-A T1T Poller RALL
*
* This method send a Read All command to a NFC-A T1T Listener device
*
*
* \param[in] uid : the UID of the device to read data
* \param[out] rxBuf : pointer to place the read data
* \param[in] rxBufLen : size of rxBuf
* \param[out] rxRcvdLen : actual received data
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Invalid parameter
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode
rfalT1TPollerRall(const uint8_t* uid, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t* rxRcvdLen);
/*!
*****************************************************************************
* \brief NFC-A T1T Poller Write
*
* This method writes the given data on the address of a NFC-A T1T Listener device
*
*
* \param[in] uid : the UID of the device to read data
* \param[in] address : address to write the data
* \param[in] data : the data to be written
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Invalid parameter
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalT1TPollerWrite(const uint8_t* uid, uint8_t address, uint8_t data);
#endif /* RFAL_T1T_H */
/**
* @}
*
* @}
*
* @}
*/
-150
View File
@@ -1,150 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_t2t.h
*
* \author Gustavo Patricio
*
* \brief Provides NFC-A T2T convenience methods and definitions
*
* This module provides an interface to perform as a NFC-A Reader/Writer
* to handle a Type 2 Tag T2T
*
*
* \addtogroup RFAL
* @{
*
* \addtogroup RFAL-AL
* \brief RFAL Abstraction Layer
* @{
*
* \addtogroup T2T
* \brief RFAL T2T Module
* @{
*
*/
#ifndef RFAL_T2T_H
#define RFAL_T2T_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
#include "st_errno.h"
#include "rfal_rf.h"
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_T2T_BLOCK_LEN 4U /*!< T2T block length */
#define RFAL_T2T_READ_DATA_LEN (4U * RFAL_T2T_BLOCK_LEN) /*!< T2T READ data length */
#define RFAL_T2T_WRITE_DATA_LEN RFAL_T2T_BLOCK_LEN /*!< T2T WRITE data length */
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief NFC-A T2T Poller Read
*
* This method sends a Read command to a NFC-A T2T Listener device
*
*
* \param[in] blockNum : Number of the block to read
* \param[out] rxBuf : pointer to place the read data
* \param[in] rxBufLen : size of rxBuf (RFAL_T2T_READ_DATA_LEN)
* \param[out] rcvLen : actual received data
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Invalid parameter
* \return ERR_PROTO : Protocol error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode
rfalT2TPollerRead(uint8_t blockNum, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t* rcvLen);
/*!
*****************************************************************************
* \brief NFC-A T2T Poller Write
*
* This method sends a Write command to a NFC-A T2T Listener device
*
*
* \param[in] blockNum : Number of the block to write
* \param[in] wrData : data to be written on the given block
* size must be of RFAL_T2T_WRITE_DATA_LEN
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Invalid parameter
* \return ERR_PROTO : Protocol error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalT2TPollerWrite(uint8_t blockNum, const uint8_t* wrData);
/*!
*****************************************************************************
* \brief NFC-A T2T Poller Sector Select
*
* This method sends a Sector Select commands to a NFC-A T2T Listener device
*
* \param[in] sectorNum : Sector Number
*
* \return ERR_WRONG_STATE : RFAL not initialized or mode not set
* \return ERR_PARAM : Invalid parameter
* \return ERR_PROTO : Protocol error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalT2TPollerSectorSelect(uint8_t sectorNum);
#endif /* RFAL_T2T_H */
/**
* @}
*
* @}
*
* @}
*/
-395
View File
@@ -1,395 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_t4t.h
*
* \author Gustavo Patricio
*
* \brief Provides convenience methods and definitions for T4T (ISO7816-4)
*
* This module provides an interface to exchange T4T APDUs according to
* NFC Forum T4T and ISO7816-4
*
* This implementation was based on the following specs:
* - ISO/IEC 7816-4 3rd Edition 2013-04-15
* - NFC Forum T4T Technical Specification 1.0 2017-08-28
*
* \addtogroup RFAL
* @{
*
* \addtogroup RFAL-AL
* \brief RFAL Abstraction Layer
* @{
*
* \addtogroup T4T
* \brief RFAL T4T Module
* @{
*
*/
#ifndef RFAL_T4T_H
#define RFAL_T4T_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
#include "st_errno.h"
#include "rfal_rf.h"
#include "rfal_isoDep.h"
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_T4T_MAX_CAPDU_PROLOGUE_LEN \
4U /*!< Command-APDU prologue length (CLA INS P1 P2) */
#define RFAL_T4T_LE_LEN 1U /*!< Le Expected Response Length (short field coding) */
#define RFAL_T4T_LC_LEN 1U /*!< Lc Data field length (short field coding) */
#define RFAL_T4T_MAX_RAPDU_SW1SW2_LEN \
2U /*!< SW1 SW2 length */
#define RFAL_T4T_CLA 0x00U /*!< Class byte (contains 00h because secure message are not used) */
#define RFAL_T4T_ISO7816_P1_SELECT_BY_DF_NAME \
0x04U /*!< P1 value for Select by name */
#define RFAL_T4T_ISO7816_P1_SELECT_BY_FILEID \
0x00U /*!< P1 value for Select by file identifier */
#define RFAL_T4T_ISO7816_P2_SELECT_FIRST_OR_ONLY_OCCURENCE \
0x00U /*!< b2b1 P2 value for First or only occurrence */
#define RFAL_T4T_ISO7816_P2_SELECT_RETURN_FCI_TEMPLATE \
0x00U /*!< b4b3 P2 value for Return FCI template */
#define RFAL_T4T_ISO7816_P2_SELECT_NO_RESPONSE_DATA \
0x0CU /*!< b4b3 P2 value for No response data */
#define RFAL_T4T_ISO7816_STATUS_COMPLETE \
0x9000U /*!< Command completed \ Normal processing - No further qualification*/
/*
******************************************************************************
* GLOBAL VARIABLES
******************************************************************************
*/
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
/*! NFC-A T4T Command-APDU structure */
typedef struct {
uint8_t CLA; /*!< Class byte */
uint8_t INS; /*!< Instruction byte */
uint8_t P1; /*!< Parameter byte 1 */
uint8_t P2; /*!< Parameter byte 2 */
uint8_t Lc; /*!< Data field length */
bool LcFlag; /*!< Lc flag (append Lc when true) */
uint8_t Le; /*!< Expected Response Length */
bool LeFlag; /*!< Le flag (append Le when true) */
rfalIsoDepApduBufFormat* cApduBuf; /*!< Command-APDU buffer (Tx) */
uint16_t* cApduLen; /*!< Command-APDU Length */
} rfalT4tCApduParam;
/*! NFC-A T4T Response-APDU structure */
typedef struct {
rfalIsoDepApduBufFormat* rApduBuf; /*!< Response-APDU buffer (Rx) */
uint16_t rcvdLen; /*!< Full response length */
uint16_t rApduBodyLen; /*!< Response body length */
uint16_t statusWord; /*!< R-APDU Status Word SW1|SW2 */
} rfalT4tRApduParam;
/*! NFC-A T4T command set T4T 1.0 & ISO7816-4 2013 Table 4 */
typedef enum {
RFAL_T4T_INS_SELECT = 0xA4U, /*!< T4T Select */
RFAL_T4T_INS_READBINARY = 0xB0U, /*!< T4T ReadBinary */
RFAL_T4T_INS_UPDATEBINARY = 0xD6U, /*!< T4T UpdateBinay */
RFAL_T4T_INS_READBINARY_ODO = 0xB1U, /*!< T4T ReadBinary using ODO */
RFAL_T4T_INS_UPDATEBINARY_ODO =
0xD7U /*!< T4T UpdateBinay using ODO */
} rfalT4tCmds;
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief T4T Compose APDU
*
* This method computes a C-APDU according to NFC Forum T4T and ISO7816-4.
*
* If C-APDU contains data to be sent, it must be placed inside the buffer
* rfalT4tTxRxApduParam.txRx.cApduBuf.apdu and signaled by Lc
*
* To transceive the formed APDU the ISO-DEP layer shall be used
*
* \see rfalIsoDepStartApduTransceive()
* \see rfalIsoDepGetApduTransceiveStatus()
* \see rfalT4TPollerParseRAPDU()
*
* \warning The ISO-DEP module is used to perform the tranceive. Usually
* activation has been done via ISO-DEP activatiavtion. If not
* please call rfalIsoDepInitialize() before.
*
* \param[in,out] apduParam : APDU parameters
* apduParam.cApduLen will contain the APDU length
*
* \return ERR_PARAM : Invalid parameter
* \return ERR_PROTO : Protocol error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalT4TPollerComposeCAPDU(const rfalT4tCApduParam* apduParam);
/*!
*****************************************************************************
* \brief T4T Parse R-APDU
*
* This method parses a R-APDU according to NFC Forum T4T and ISO7816-4.
* It will extract the data length and check if the Status word is expected.
*
* \param[in,out] apduParam : APDU parameters
* apduParam.rApduBodyLen will contain the data length
* apduParam.statusWord will contain the SW1 and SW2
*
* \return ERR_REQUEST : Status word (SW1 SW2) different from 9000
* \return ERR_PARAM : Invalid parameter
* \return ERR_PROTO : Protocol error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalT4TPollerParseRAPDU(rfalT4tRApduParam* apduParam);
/*!
*****************************************************************************
* \brief T4T Compose Select Application APDU
*
* This method computes a Select Application APDU according to NFC Forum T4T
*
* To transceive the formed APDU the ISO-DEP layer shall be used
*
* \see rfalIsoDepStartApduTransceive()
* \see rfalIsoDepGetApduTransceiveStatus()
*
* \param[out] cApduBuf : buffer where the C-APDU will be placed
* \param[in] aid : Application ID to be used
* \param[in] aidLen : Application ID length
* \param[out] cApduLen : Composed C-APDU length
*
* \return ERR_PARAM : Invalid parameter
* \return ERR_PROTO : Protocol error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalT4TPollerComposeSelectAppl(
rfalIsoDepApduBufFormat* cApduBuf,
const uint8_t* aid,
uint8_t aidLen,
uint16_t* cApduLen);
/*!
*****************************************************************************
* \brief T4T Compose Select File APDU
*
* This method computes a Select File APDU according to NFC Forum T4T
*
* To transceive the formed APDU the ISO-DEP layer shall be used
*
* \see rfalIsoDepStartApduTransceive()
* \see rfalIsoDepGetApduTransceiveStatus()
*
* \param[out] cApduBuf : buffer where the C-APDU will be placed
* \param[in] fid : File ID to be used
* \param[in] fidLen : File ID length
* \param[out] cApduLen : Composed C-APDU length
*
* \return ERR_PARAM : Invalid parameter
* \return ERR_PROTO : Protocol error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalT4TPollerComposeSelectFile(
rfalIsoDepApduBufFormat* cApduBuf,
const uint8_t* fid,
uint8_t fidLen,
uint16_t* cApduLen);
/*!
*****************************************************************************
* \brief T4T Compose Select File APDU for Mapping Version 1
*
* This method computes a Select File APDU according to NFC Forum T4TOP_v1.0
*
* To transceive the formed APDU the ISO-DEP layer shall be used
*
* \see rfalIsoDepStartApduTransceive()
* \see rfalIsoDepGetApduTransceiveStatus()
*
* \param[out] cApduBuf : buffer where the C-APDU will be placed
* \param[in] fid : File ID to be used
* \param[in] fidLen : File ID length
* \param[out] cApduLen : Composed C-APDU length
*
* \return ERR_PARAM : Invalid parameter
* \return ERR_PROTO : Protocol error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalT4TPollerComposeSelectFileV1Mapping(
rfalIsoDepApduBufFormat* cApduBuf,
const uint8_t* fid,
uint8_t fidLen,
uint16_t* cApduLen);
/*!
*****************************************************************************
* \brief T4T Compose Read Data APDU
*
* This method computes a Read Data APDU according to NFC Forum T4T
*
* To transceive the formed APDU the ISO-DEP layer shall be used
*
* \see rfalIsoDepStartApduTransceive()
* \see rfalIsoDepGetApduTransceiveStatus()
*
* \param[out] cApduBuf : buffer where the C-APDU will be placed
* \param[in] offset : File offset
* \param[in] expLen : Expected length (Le)
* \param[out] cApduLen : Composed C-APDU length
*
* \return ERR_PARAM : Invalid parameter
* \return ERR_PROTO : Protocol error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalT4TPollerComposeReadData(
rfalIsoDepApduBufFormat* cApduBuf,
uint16_t offset,
uint8_t expLen,
uint16_t* cApduLen);
/*!
*****************************************************************************
* \brief T4T Compose Read Data ODO APDU
*
* This method computes a Read Data ODO APDU according to NFC Forum T4T
*
* To transceive the formed APDU the ISO-DEP layer shall be used
*
* \see rfalIsoDepStartApduTransceive()
* \see rfalIsoDepGetApduTransceiveStatus()
*
* \param[out] cApduBuf : buffer where the C-APDU will be placed
* \param[in] offset : File offset
* \param[in] expLen : Expected length (Le)
* \param[out] cApduLen : Composed C-APDU length
*
* \return ERR_PARAM : Invalid parameter
* \return ERR_PROTO : Protocol error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalT4TPollerComposeReadDataODO(
rfalIsoDepApduBufFormat* cApduBuf,
uint32_t offset,
uint8_t expLen,
uint16_t* cApduLen);
/*!
*****************************************************************************
* \brief T4T Compose Write Data APDU
*
* This method computes a Write Data APDU according to NFC Forum T4T
*
* To transceive the formed APDU the ISO-DEP layer shall be used
*
* \see rfalIsoDepStartApduTransceive()
* \see rfalIsoDepGetApduTransceiveStatus()
*
* \param[out] cApduBuf : buffer where the C-APDU will be placed
* \param[in] offset : File offset
* \param[in] data : Data to be written
* \param[in] dataLen : Data length to be written (Lc)
* \param[out] cApduLen : Composed C-APDU length
*
* \return ERR_PARAM : Invalid parameter
* \return ERR_PROTO : Protocol error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalT4TPollerComposeWriteData(
rfalIsoDepApduBufFormat* cApduBuf,
uint16_t offset,
const uint8_t* data,
uint8_t dataLen,
uint16_t* cApduLen);
/*!
*****************************************************************************
* \brief T4T Compose Write Data ODO APDU
*
* This method computes a Write Data ODO sAPDU according to NFC Forum T4T
*
* To transceive the formed APDU the ISO-DEP layer shall be used
*
* \see rfalIsoDepStartApduTransceive()
* \see rfalIsoDepGetApduTransceiveStatus()
*
* \param[out] cApduBuf : buffer where the C-APDU will be placed
* \param[in] offset : File offset
* \param[in] data : Data to be written
* \param[in] dataLen : Data length to be written (Lc)
* \param[out] cApduLen : Composed C-APDU length
*
* \return ERR_PARAM : Invalid parameter
* \return ERR_PROTO : Protocol error
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode rfalT4TPollerComposeWriteDataODO(
rfalIsoDepApduBufFormat* cApduBuf,
uint32_t offset,
const uint8_t* data,
uint8_t dataLen,
uint16_t* cApduLen);
#endif /* RFAL_T4T_H */
/**
* @}
*
* @}
*
* @}
*/
-103
View File
@@ -1,103 +0,0 @@
#include "platform.h"
#include <assert.h>
#include <furi.h>
#include <furi_hal_spi.h>
typedef struct {
FuriThread* thread;
volatile PlatformIrqCallback callback;
bool need_spi_lock;
} RfalPlatform;
static volatile RfalPlatform rfal_platform = {
.thread = NULL,
.callback = NULL,
.need_spi_lock = true,
};
void nfc_isr(void* _ctx) {
UNUSED(_ctx);
if(rfal_platform.callback && platformGpioIsHigh(ST25R_INT_PORT, ST25R_INT_PIN)) {
furi_thread_flags_set(furi_thread_get_id(rfal_platform.thread), 0x1);
}
}
int32_t rfal_platform_irq_thread(void* context) {
UNUSED(context);
while(1) {
uint32_t flags = furi_thread_flags_wait(0x1, FuriFlagWaitAny, FuriWaitForever);
if(flags & 0x1) {
rfal_platform.callback();
}
}
}
void platformEnableIrqCallback() {
furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeInterruptRise, GpioPullDown, GpioSpeedLow);
furi_hal_gpio_enable_int_callback(&gpio_nfc_irq_rfid_pull);
}
void platformDisableIrqCallback() {
furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_disable_int_callback(&gpio_nfc_irq_rfid_pull);
}
void platformSetIrqCallback(PlatformIrqCallback callback) {
rfal_platform.callback = callback;
if(!rfal_platform.thread) {
rfal_platform.thread =
furi_thread_alloc_ex("RfalIrqDriver", 1024, rfal_platform_irq_thread, NULL);
furi_thread_mark_as_service(rfal_platform.thread);
furi_thread_set_priority(rfal_platform.thread, FuriThreadPriorityIsr);
furi_thread_start(rfal_platform.thread);
}
furi_hal_gpio_add_int_callback(&gpio_nfc_irq_rfid_pull, nfc_isr, NULL);
// Disable interrupt callback as the pin is shared between 2 apps
// It is enabled in rfalLowPowerModeStop()
furi_hal_gpio_disable_int_callback(&gpio_nfc_irq_rfid_pull);
}
bool platformSpiTxRx(const uint8_t* txBuf, uint8_t* rxBuf, uint16_t len) {
bool ret = false;
if(txBuf && rxBuf) {
ret =
furi_hal_spi_bus_trx(&furi_hal_spi_bus_handle_nfc, (uint8_t*)txBuf, rxBuf, len, 1000);
} else if(txBuf) {
ret = furi_hal_spi_bus_tx(&furi_hal_spi_bus_handle_nfc, (uint8_t*)txBuf, len, 1000);
} else if(rxBuf) {
ret = furi_hal_spi_bus_rx(&furi_hal_spi_bus_handle_nfc, (uint8_t*)rxBuf, len, 1000);
}
return ret;
}
// Until we completely remove RFAL, NFC works with SPI from rfal_platform_irq_thread and nfc_worker
// threads. Some nfc features already stop using RFAL and work with SPI from nfc_worker only.
// rfal_platform_spi_acquire() and rfal_platform_spi_release() functions are used to lock SPI for a
// long term without locking it for each SPI transaction. This is needed for time critical communications.
void rfal_platform_spi_acquire() {
platformDisableIrqCallback();
rfal_platform.need_spi_lock = false;
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_nfc);
}
void rfal_platform_spi_release() {
furi_hal_spi_release(&furi_hal_spi_bus_handle_nfc);
rfal_platform.need_spi_lock = true;
platformEnableIrqCallback();
}
void platformProtectST25RComm() {
if(rfal_platform.need_spi_lock) {
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_nfc);
}
}
void platformUnprotectST25RComm() {
if(rfal_platform.need_spi_lock) {
furi_hal_spi_release(&furi_hal_spi_bus_handle_nfc);
}
}
-188
View File
@@ -1,188 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>
#include "timer.h"
#include "math.h"
#include <furi_hal_gpio.h>
#include <furi_hal_light.h>
#include <furi_hal_spi.h>
typedef void (*PlatformIrqCallback)();
void platformSetIrqCallback(PlatformIrqCallback cb);
void platformEnableIrqCallback();
void platformDisableIrqCallback();
bool platformSpiTxRx(const uint8_t* txBuf, uint8_t* rxBuf, uint16_t len);
void platformProtectST25RComm();
void platformUnprotectST25RComm();
void rfal_platform_spi_acquire();
void rfal_platform_spi_release();
#define ST25R_SS_PIN NFC_CS_Pin
#define ST25R_SS_PORT NFC_CS_GPIO_Port
#define ST25R_INT_PIN NFC_IRQ_Pin
#define ST25R_INT_PORT NFC_IRQ_GPIO_Port
#define RFAL_ANALOG_CONFIG_CUSTOM \
true /*!< Enable/Disable RFAL custom analog configuration */
#define RFAL_FEATURE_LISTEN_MODE \
true /*!< Enable/Disable RFAL support for Listen Mode */
#define RFAL_FEATURE_WAKEUP_MODE \
true /*!< Enable/Disable RFAL support for the Wake-Up mode */
#define RFAL_FEATURE_LOWPOWER_MODE \
true /*!< Enable/Disable RFAL support for the Low Power mode */
#define RFAL_FEATURE_NFCA \
true /*!< Enable/Disable RFAL support for NFC-A (ISO14443A) */
#define RFAL_FEATURE_NFCB \
true /*!< Enable/Disable RFAL support for NFC-B (ISO14443B) */
#define RFAL_FEATURE_NFCF \
true /*!< Enable/Disable RFAL support for NFC-F (FeliCa) */
#define RFAL_FEATURE_NFCV \
true /*!< Enable/Disable RFAL support for NFC-V (ISO15693) */
#define RFAL_FEATURE_T1T \
true /*!< Enable/Disable RFAL support for T1T (Topaz) */
#define RFAL_FEATURE_T2T \
true /*!< Enable/Disable RFAL support for T2T (MIFARE Ultralight) */
#define RFAL_FEATURE_T4T \
true /*!< Enable/Disable RFAL support for T4T */
#define RFAL_FEATURE_ST25TB \
true /*!< Enable/Disable RFAL support for ST25TB */
#define RFAL_FEATURE_ST25xV \
true /*!< Enable/Disable RFAL support for ST25TV/ST25DV */
#define RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG \
false /*!< Enable/Disable Analog Configs to be dynamically updated (RAM) */
#define RFAL_FEATURE_DPO \
false /*!< Enable/Disable RFAL Dynamic Power Output upport */
#define RFAL_FEATURE_ISO_DEP \
true /*!< Enable/Disable RFAL support for ISO-DEP (ISO14443-4) */
#define RFAL_FEATURE_ISO_DEP_POLL \
true /*!< Enable/Disable RFAL support for Poller mode (PCD) ISO-DEP (ISO14443-4) */
#define RFAL_FEATURE_ISO_DEP_LISTEN \
true /*!< Enable/Disable RFAL support for Listen mode (PICC) ISO-DEP (ISO14443-4) */
#define RFAL_FEATURE_NFC_DEP \
true /*!< Enable/Disable RFAL support for NFC-DEP (NFCIP1/P2P) */
#define RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN \
256U /*!< ISO-DEP I-Block max length. Please use values as defined by rfalIsoDepFSx */
#define RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN \
254U /*!< NFC-DEP Block/Payload length. Allowed values: 64, 128, 192, 254 */
#define RFAL_FEATURE_NFC_RF_BUF_LEN \
256U /*!< RF buffer length used by RFAL NFC layer */
#define RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN \
512U /*!< ISO-DEP APDU max length. */
#define RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN \
512U /*!< NFC-DEP PDU max length. */
#define platformIrqST25RSetCallback(cb) platformSetIrqCallback(cb)
#define platformProtectST25RIrqStatus() \
platformProtectST25RComm() /*!< Protect unique access to IRQ status var - IRQ disable on single thread environment (MCU) ; Mutex lock on a multi thread environment */
#define platformUnprotectST25RIrqStatus() \
platformUnprotectST25RComm() /*!< Unprotect the IRQ status var - IRQ enable on a single thread environment (MCU) ; Mutex unlock on a multi thread environment */
#define platformGpioSet(port, pin) \
furi_hal_gpio_write_port_pin( \
port, pin, true) /*!< Turns the given GPIO High */
#define platformGpioClear(port, pin) \
furi_hal_gpio_write_port_pin( \
port, pin, false) /*!< Turns the given GPIO Low */
#define platformGpioIsHigh(port, pin) \
(furi_hal_gpio_read_port_pin(port, pin) == \
true) /*!< Checks if the given LED is High */
#define platformGpioIsLow(port, pin) \
(!platformGpioIsHigh(port, pin)) /*!< Checks if the given LED is Low */
#define platformTimerCreate(t) \
timerCalculateTimer(t) /*!< Create a timer with the given time (ms) */
#define platformTimerIsExpired(timer) \
timerIsExpired(timer) /*!< Checks if the given timer is expired */
#define platformDelay(t) furi_delay_ms(t) /*!< Performs a delay for the given time (ms) */
#define platformGetSysTick() furi_get_tick() /*!< Get System Tick (1 tick = 1 ms) */
#define platformAssert(exp) assert_param(exp) /*!< Asserts whether the given expression is true*/
#define platformSpiSelect() \
platformGpioClear( \
ST25R_SS_PORT, ST25R_SS_PIN) /*!< SPI SS\CS: Chip|Slave Select */
#define platformSpiDeselect() \
platformGpioSet( \
ST25R_SS_PORT, ST25R_SS_PIN) /*!< SPI SS\CS: Chip|Slave Deselect */
#define platformI2CTx(txBuf, len, last, txOnly) /*!< I2C Transmit */
#define platformI2CRx(txBuf, len) /*!< I2C Receive */
#define platformI2CStart() /*!< I2C Start condition */
#define platformI2CStop() /*!< I2C Stop condition */
#define platformI2CRepeatStart() /*!< I2C Repeat Start */
#define platformI2CSlaveAddrWR(add) /*!< I2C Slave address for Write operation */
#define platformI2CSlaveAddrRD(add) /*!< I2C Slave address for Read operation */
#define platformLog(...) /*!< Log method */
/*
******************************************************************************
* RFAL OPTIONAL MACROS (Do not change)
******************************************************************************
*/
#ifndef platformProtectST25RIrqStatus
#define platformProtectST25RIrqStatus() /*!< Protect unique access to IRQ status var - IRQ disable on single thread environment (MCU) ; Mutex lock on a multi thread environment */
#endif /* platformProtectST25RIrqStatus */
#ifndef platformUnprotectST25RIrqStatus
#define platformUnprotectST25RIrqStatus() /*!< Unprotect the IRQ status var - IRQ enable on a single thread environment (MCU) ; Mutex unlock on a multi thread environment */
#endif /* platformUnprotectST25RIrqStatus */
#ifndef platformProtectWorker
#define platformProtectWorker() /* Protect RFAL Worker/Task/Process from concurrent execution on multi thread platforms */
#endif /* platformProtectWorker */
#ifndef platformUnprotectWorker
#define platformUnprotectWorker() /* Unprotect RFAL Worker/Task/Process from concurrent execution on multi thread platforms */
#endif /* platformUnprotectWorker */
#ifndef platformIrqST25RPinInitialize
#define platformIrqST25RPinInitialize() /*!< Initializes ST25R IRQ pin */
#endif /* platformIrqST25RPinInitialize */
#ifndef platformIrqST25RSetCallback
#define platformIrqST25RSetCallback(cb) /*!< Sets ST25R ISR callback */
#endif /* platformIrqST25RSetCallback */
#ifndef platformLedsInitialize
#define platformLedsInitialize() /*!< Initializes the pins used as LEDs to outputs */
#endif /* platformLedsInitialize */
#ifndef platformLedOff
#define platformLedOff(port, pin) /*!< Turns the given LED Off */
#endif /* platformLedOff */
#ifndef platformLedOn
#define platformLedOn(port, pin) /*!< Turns the given LED On */
#endif /* platformLedOn */
#ifndef platformLedToogle
#define platformLedToogle(port, pin) /*!< Toggles the given LED */
#endif /* platformLedToogle */
#ifndef platformGetSysTick
#define platformGetSysTick() /*!< Get System Tick (1 tick = 1 ms) */
#endif /* platformGetSysTick */
#ifndef platformTimerDestroy
#define platformTimerDestroy(timer) /*!< Stops and released the given timer */
#endif /* platformTimerDestroy */
#ifndef platformAssert
#define platformAssert(exp) /*!< Asserts whether the given expression is true */
#endif /* platformAssert */
#ifndef platformErrorHandle
#define platformErrorHandle() /*!< Global error handler or trap */
#endif /* platformErrorHandle */
@@ -1,777 +0,0 @@
#include "rfal_analogConfigTbl.h"
const uint8_t rfalAnalogConfigCustomSettings[] = {
/****** Default Analog Configuration for Chip-Specific Reset ******/
MODE_ENTRY_16_REG(
(RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_INIT),
ST25R3916_REG_IO_CONF1,
(ST25R3916_REG_IO_CONF1_out_cl_mask | ST25R3916_REG_IO_CONF1_lf_clk_off),
0x07 /* Disable MCU_CLK */
,
ST25R3916_REG_IO_CONF2,
(ST25R3916_REG_IO_CONF2_miso_pd1 | ST25R3916_REG_IO_CONF2_miso_pd2),
0x18 /* SPI Pull downs */
// , ST25R3916_REG_IO_CONF2, ST25R3916_REG_IO_CONF2_aat_en, ST25R3916_REG_IO_CONF2_aat_en /* Enable AAT */
,
ST25R3916_REG_TX_DRIVER,
ST25R3916_REG_TX_DRIVER_d_res_mask,
0x00 /* Set RFO resistance Active Tx */
,
ST25R3916_REG_RES_AM_MOD,
0xFF,
0x80 /* Use minimum non-overlap */
,
ST25R3916_REG_FIELD_THRESHOLD_ACTV,
ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_mask,
ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_105mV /* Lower activation threshold (higher than deactivation)*/
,
ST25R3916_REG_FIELD_THRESHOLD_ACTV,
ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_mask,
ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_105mV /* Lower activation threshold (higher than deactivation)*/
,
ST25R3916_REG_FIELD_THRESHOLD_DEACTV,
ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_mask,
ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_75mV /* Lower deactivation threshold */
,
ST25R3916_REG_FIELD_THRESHOLD_DEACTV,
ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_mask,
ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_75mV /* Lower deactivation threshold */
,
ST25R3916_REG_AUX_MOD,
ST25R3916_REG_AUX_MOD_lm_ext,
ST25R3916_REG_AUX_MOD_lm_ext /* Disable External Load Modulation */
,
ST25R3916_REG_AUX_MOD,
ST25R3916_REG_AUX_MOD_lm_dri,
ST25R3916_REG_AUX_MOD_lm_dri /* Use internal Load Modulation */
,
ST25R3916_REG_PASSIVE_TARGET,
ST25R3916_REG_PASSIVE_TARGET_fdel_mask,
(5U
<< ST25R3916_REG_PASSIVE_TARGET_fdel_shift) /* Adjust the FDT to be aligned with the bitgrid */
,
ST25R3916_REG_PT_MOD,
(ST25R3916_REG_PT_MOD_ptm_res_mask | ST25R3916_REG_PT_MOD_pt_res_mask),
0x0f /* Reduce RFO resistance in Modulated state */
,
ST25R3916_REG_EMD_SUP_CONF,
ST25R3916_REG_EMD_SUP_CONF_rx_start_emv,
ST25R3916_REG_EMD_SUP_CONF_rx_start_emv_on /* Enable start on first 4 bits */
,
ST25R3916_REG_ANT_TUNE_A,
0xFF,
0x82 /* Set Antenna Tuning (Poller): ANTL */
,
ST25R3916_REG_ANT_TUNE_B,
0xFF,
0x82 /* Set Antenna Tuning (Poller): ANTL */
,
0x84U,
0x10,
0x10 /* Avoid chip internal overheat protection */
)
/****** Default Analog Configuration for Chip-Specific Poll Common ******/
,
MODE_ENTRY_9_REG(
(RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_POLL_COMMON),
ST25R3916_REG_MODE,
ST25R3916_REG_MODE_tr_am,
ST25R3916_REG_MODE_tr_am_am /* Use AM modulation */
,
ST25R3916_REG_TX_DRIVER,
ST25R3916_REG_TX_DRIVER_am_mod_mask,
ST25R3916_REG_TX_DRIVER_am_mod_12percent /* Set Modulation index */
,
ST25R3916_REG_AUX_MOD,
(ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am),
0x00 /* Use AM via regulator */
,
ST25R3916_REG_ANT_TUNE_A,
0xFF,
0x82 /* Set Antenna Tuning (Poller): ANTL */
,
ST25R3916_REG_ANT_TUNE_B,
0xFF,
0x82 /* Set Antenna Tuning (Poller): ANTL */
,
ST25R3916_REG_OVERSHOOT_CONF1,
0xFF,
0x00 /* Disable Overshoot Protection */
,
ST25R3916_REG_OVERSHOOT_CONF2,
0xFF,
0x00 /* Disable Overshoot Protection */
,
ST25R3916_REG_UNDERSHOOT_CONF1,
0xFF,
0x00 /* Disable Undershoot Protection */
,
ST25R3916_REG_UNDERSHOOT_CONF2,
0xFF,
0x00 /* Disable Undershoot Protection */
)
/****** Default Analog Configuration for Poll NFC-A Rx Common ******/
,
MODE_ENTRY_1_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA |
RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX),
ST25R3916_REG_AUX,
ST25R3916_REG_AUX_dis_corr,
ST25R3916_REG_AUX_dis_corr_correlator /* Use Correlator Receiver */
)
/****** Default Analog Configuration for Poll NFC-A Tx 106 ******/
,
MODE_ENTRY_5_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_106 |
RFAL_ANALOG_CONFIG_TX),
ST25R3916_REG_MODE,
ST25R3916_REG_MODE_tr_am,
ST25R3916_REG_MODE_tr_am_ook /* Use OOK */
,
ST25R3916_REG_OVERSHOOT_CONF1,
0xFF,
0x40 /* Set default Overshoot Protection */
,
ST25R3916_REG_OVERSHOOT_CONF2,
0xFF,
0x03 /* Set default Overshoot Protection */
,
ST25R3916_REG_UNDERSHOOT_CONF1,
0xFF,
0x40 /* Set default Undershoot Protection */
,
ST25R3916_REG_UNDERSHOOT_CONF2,
0xFF,
0x03 /* Set default Undershoot Protection */
)
/****** Default Analog Configuration for Poll NFC-A Rx 106 ******/
,
MODE_ENTRY_6_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_106 |
RFAL_ANALOG_CONFIG_RX),
ST25R3916_REG_RX_CONF1,
0xFF,
0x08,
ST25R3916_REG_RX_CONF2,
0xFF,
0x2D,
ST25R3916_REG_RX_CONF3,
0xFF,
0x00,
ST25R3916_REG_RX_CONF4,
0xFF,
0x00,
ST25R3916_REG_CORR_CONF1,
0xFF,
0x51,
ST25R3916_REG_CORR_CONF2,
0xFF,
0x00)
/****** Default Analog Configuration for Poll NFC-A Tx 212 ******/
,
MODE_ENTRY_7_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_212 |
RFAL_ANALOG_CONFIG_TX),
ST25R3916_REG_MODE,
ST25R3916_REG_MODE_tr_am,
ST25R3916_REG_MODE_tr_am_am /* Use AM modulation */
,
ST25R3916_REG_AUX_MOD,
(ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am),
0x88 /* Use Resistive AM */
,
ST25R3916_REG_RES_AM_MOD,
ST25R3916_REG_RES_AM_MOD_md_res_mask,
0x7F /* Set Resistive modulation */
,
ST25R3916_REG_OVERSHOOT_CONF1,
0xFF,
0x40 /* Set default Overshoot Protection */
,
ST25R3916_REG_OVERSHOOT_CONF2,
0xFF,
0x03 /* Set default Overshoot Protection */
,
ST25R3916_REG_UNDERSHOOT_CONF1,
0xFF,
0x40 /* Set default Undershoot Protection */
,
ST25R3916_REG_UNDERSHOOT_CONF2,
0xFF,
0x03 /* Set default Undershoot Protection */
)
/****** Default Analog Configuration for Poll NFC-A Rx 212 ******/
,
MODE_ENTRY_6_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_212 |
RFAL_ANALOG_CONFIG_RX),
ST25R3916_REG_RX_CONF1,
0xFF,
0x02,
ST25R3916_REG_RX_CONF2,
0xFF,
0x3D,
ST25R3916_REG_RX_CONF3,
0xFF,
0x00,
ST25R3916_REG_RX_CONF4,
0xFF,
0x00,
ST25R3916_REG_CORR_CONF1,
0xFF,
0x14,
ST25R3916_REG_CORR_CONF2,
0xFF,
0x00)
/****** Default Analog Configuration for Poll NFC-A Tx 424 ******/
,
MODE_ENTRY_7_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_424 |
RFAL_ANALOG_CONFIG_TX),
ST25R3916_REG_MODE,
ST25R3916_REG_MODE_tr_am,
ST25R3916_REG_MODE_tr_am_am /* Use AM modulation */
,
ST25R3916_REG_AUX_MOD,
(ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am),
0x88 /* Use Resistive AM */
,
ST25R3916_REG_RES_AM_MOD,
ST25R3916_REG_RES_AM_MOD_md_res_mask,
0x7F /* Set Resistive modulation */
,
ST25R3916_REG_OVERSHOOT_CONF1,
0xFF,
0x40 /* Set default Overshoot Protection */
,
ST25R3916_REG_OVERSHOOT_CONF2,
0xFF,
0x03 /* Set default Overshoot Protection */
,
ST25R3916_REG_UNDERSHOOT_CONF1,
0xFF,
0x40 /* Set default Undershoot Protection */
,
ST25R3916_REG_UNDERSHOOT_CONF2,
0xFF,
0x03 /* Set default Undershoot Protection */
)
/****** Default Analog Configuration for Poll NFC-A Rx 424 ******/
,
MODE_ENTRY_6_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_424 |
RFAL_ANALOG_CONFIG_RX),
ST25R3916_REG_RX_CONF1,
0xFF,
0x42,
ST25R3916_REG_RX_CONF2,
0xFF,
0x3D,
ST25R3916_REG_RX_CONF3,
0xFF,
0x00,
ST25R3916_REG_RX_CONF4,
0xFF,
0x00,
ST25R3916_REG_CORR_CONF1,
0xFF,
0x54,
ST25R3916_REG_CORR_CONF2,
0xFF,
0x00)
/****** Default Analog Configuration for Poll NFC-A Tx 848 ******/
,
MODE_ENTRY_7_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_848 |
RFAL_ANALOG_CONFIG_TX),
ST25R3916_REG_MODE,
ST25R3916_REG_MODE_tr_am,
ST25R3916_REG_MODE_tr_am_am /* Use AM modulation */
,
ST25R3916_REG_TX_DRIVER,
ST25R3916_REG_TX_DRIVER_am_mod_mask,
ST25R3916_REG_TX_DRIVER_am_mod_40percent /* Set Modulation index */
,
ST25R3916_REG_AUX_MOD,
(ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am),
0x00 /* Use AM via regulator */
,
ST25R3916_REG_OVERSHOOT_CONF1,
0xFF,
0x00 /* Disable Overshoot Protection */
,
ST25R3916_REG_OVERSHOOT_CONF2,
0xFF,
0x00 /* Disable Overshoot Protection */
,
ST25R3916_REG_UNDERSHOOT_CONF1,
0xFF,
0x00 /* Disable Undershoot Protection */
,
ST25R3916_REG_UNDERSHOOT_CONF2,
0xFF,
0x00 /* Disable Undershoot Protection */
)
/****** Default Analog Configuration for Poll NFC-A Rx 848 ******/
,
MODE_ENTRY_6_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_848 |
RFAL_ANALOG_CONFIG_RX),
ST25R3916_REG_RX_CONF1,
0xFF,
0x42,
ST25R3916_REG_RX_CONF2,
0xFF,
0x3D,
ST25R3916_REG_RX_CONF3,
0xFF,
0x00,
ST25R3916_REG_RX_CONF4,
0xFF,
0x00,
ST25R3916_REG_CORR_CONF1,
0xFF,
0x44,
ST25R3916_REG_CORR_CONF2,
0xFF,
0x00)
/****** Default Analog Configuration for Poll NFC-A Anticolision setting ******/
,
MODE_ENTRY_1_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA |
RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_ANTICOL),
ST25R3916_REG_CORR_CONF1,
ST25R3916_REG_CORR_CONF1_corr_s6,
0x00 /* Set collision detection level different from data */
)
#ifdef RFAL_USE_COHE
/****** Default Analog Configuration for Poll NFC-B Rx Common ******/
,
MODE_ENTRY_1_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB |
RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX),
ST25R3916_REG_AUX,
ST25R3916_REG_AUX_dis_corr,
ST25R3916_REG_AUX_dis_corr_coherent /* Use Coherent Receiver */
)
#else
/****** Default Analog Configuration for Poll NFC-B Rx Common ******/
,
MODE_ENTRY_1_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB |
RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX),
ST25R3916_REG_AUX,
ST25R3916_REG_AUX_dis_corr,
ST25R3916_REG_AUX_dis_corr_correlator /* Use Correlator Receiver */
)
#endif /*RFAL_USE_COHE*/
/****** Default Analog Configuration for Poll NFC-B Rx 106 ******/
,
MODE_ENTRY_6_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_106 |
RFAL_ANALOG_CONFIG_RX),
ST25R3916_REG_RX_CONF1,
0xFF,
0x04,
ST25R3916_REG_RX_CONF2,
0xFF,
0x3D,
ST25R3916_REG_RX_CONF3,
0xFF,
0x00,
ST25R3916_REG_RX_CONF4,
0xFF,
0x00,
ST25R3916_REG_CORR_CONF1,
0xFF,
0x1B,
ST25R3916_REG_CORR_CONF2,
0xFF,
0x00)
/****** Default Analog Configuration for Poll NFC-B Rx 212 ******/
,
MODE_ENTRY_6_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_212 |
RFAL_ANALOG_CONFIG_RX),
ST25R3916_REG_RX_CONF1,
0xFF,
0x02,
ST25R3916_REG_RX_CONF2,
0xFF,
0x3D,
ST25R3916_REG_RX_CONF3,
0xFF,
0x00,
ST25R3916_REG_RX_CONF4,
0xFF,
0x00,
ST25R3916_REG_CORR_CONF1,
0xFF,
0x14,
ST25R3916_REG_CORR_CONF2,
0xFF,
0x00)
/****** Default Analog Configuration for Poll NFC-B Rx 424 ******/
,
MODE_ENTRY_6_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_424 |
RFAL_ANALOG_CONFIG_RX),
ST25R3916_REG_RX_CONF1,
0xFF,
0x42,
ST25R3916_REG_RX_CONF2,
0xFF,
0x3D,
ST25R3916_REG_RX_CONF3,
0xFF,
0x00,
ST25R3916_REG_RX_CONF4,
0xFF,
0x00,
ST25R3916_REG_CORR_CONF1,
0xFF,
0x54,
ST25R3916_REG_CORR_CONF2,
0xFF,
0x00)
/****** Default Analog Configuration for Poll NFC-B Rx 848 ******/
,
MODE_ENTRY_6_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_848 |
RFAL_ANALOG_CONFIG_RX),
ST25R3916_REG_RX_CONF1,
0xFF,
0x42,
ST25R3916_REG_RX_CONF2,
0xFF,
0x3D,
ST25R3916_REG_RX_CONF3,
0xFF,
0x00,
ST25R3916_REG_RX_CONF4,
0xFF,
0x00,
ST25R3916_REG_CORR_CONF1,
0xFF,
0x44,
ST25R3916_REG_CORR_CONF2,
0xFF,
0x00)
#ifdef RFAL_USE_COHE
/****** Default Analog Configuration for Poll NFC-F Rx Common ******/
,
MODE_ENTRY_7_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCF |
RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX),
ST25R3916_REG_AUX,
ST25R3916_REG_AUX_dis_corr,
ST25R3916_REG_AUX_dis_corr_coherent /* Use Pulse Receiver */
,
ST25R3916_REG_RX_CONF1,
0xFF,
0x13,
ST25R3916_REG_RX_CONF2,
0xFF,
0x3D,
ST25R3916_REG_RX_CONF3,
0xFF,
0x00,
ST25R3916_REG_RX_CONF4,
0xFF,
0x00,
ST25R3916_REG_CORR_CONF1,
0xFF,
0x54,
ST25R3916_REG_CORR_CONF2,
0xFF,
0x00)
#else
/****** Default Analog Configuration for Poll NFC-F Rx Common ******/
,
MODE_ENTRY_7_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCF |
RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX),
ST25R3916_REG_AUX,
ST25R3916_REG_AUX_dis_corr,
ST25R3916_REG_AUX_dis_corr_correlator /* Use Correlator Receiver */
,
ST25R3916_REG_RX_CONF1,
0xFF,
0x13,
ST25R3916_REG_RX_CONF2,
0xFF,
0x3D,
ST25R3916_REG_RX_CONF3,
0xFF,
0x00,
ST25R3916_REG_RX_CONF4,
0xFF,
0x00,
ST25R3916_REG_CORR_CONF1,
0xFF,
0x54,
ST25R3916_REG_CORR_CONF2,
0xFF,
0x00)
#endif /*RFAL_USE_COHE*/
,
MODE_ENTRY_1_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | RFAL_ANALOG_CONFIG_BITRATE_1OF4 |
RFAL_ANALOG_CONFIG_TX),
ST25R3916_REG_MODE,
ST25R3916_REG_MODE_tr_am,
ST25R3916_REG_MODE_tr_am_ook /* Use OOK */
)
#ifdef RFAL_USE_COHE
/****** Default Analog Configuration for Poll NFC-V Rx Common ******/
,
MODE_ENTRY_7_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV |
RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX),
ST25R3916_REG_AUX,
ST25R3916_REG_AUX_dis_corr,
ST25R3916_REG_AUX_dis_corr_coherent /* Use Pulse Receiver */
,
ST25R3916_REG_RX_CONF1,
0xFF,
0x13,
ST25R3916_REG_RX_CONF2,
0xFF,
0x2D,
ST25R3916_REG_RX_CONF3,
0xFF,
0x00,
ST25R3916_REG_RX_CONF4,
0xFF,
0x00,
ST25R3916_REG_CORR_CONF1,
0xFF,
0x13,
ST25R3916_REG_CORR_CONF2,
0xFF,
0x01)
#else
/****** Default Analog Configuration for Poll NFC-V Rx Common ******/
,
MODE_ENTRY_7_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV |
RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX),
ST25R3916_REG_AUX,
ST25R3916_REG_AUX_dis_corr,
ST25R3916_REG_AUX_dis_corr_correlator /* Use Correlator Receiver */
,
ST25R3916_REG_RX_CONF1,
0xFF,
0x13,
ST25R3916_REG_RX_CONF2,
0xFF,
0x2D,
ST25R3916_REG_RX_CONF3,
0xFF,
0x00,
ST25R3916_REG_RX_CONF4,
0xFF,
0x00,
ST25R3916_REG_CORR_CONF1,
0xFF,
0x13,
ST25R3916_REG_CORR_CONF2,
0xFF,
0x01)
#endif /*RFAL_USE_COHE*/
/****** Default Analog Configuration for Poll AP2P Tx 106 ******/
,
MODE_ENTRY_5_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P | RFAL_ANALOG_CONFIG_BITRATE_106 |
RFAL_ANALOG_CONFIG_TX),
ST25R3916_REG_MODE,
ST25R3916_REG_MODE_tr_am,
ST25R3916_REG_MODE_tr_am_ook /* Use OOK modulation */
,
ST25R3916_REG_OVERSHOOT_CONF1,
0xFF,
0x40 /* Set default Overshoot Protection */
,
ST25R3916_REG_OVERSHOOT_CONF2,
0xFF,
0x03 /* Set default Overshoot Protection */
,
ST25R3916_REG_UNDERSHOOT_CONF1,
0xFF,
0x40 /* Set default Undershoot Protection */
,
ST25R3916_REG_UNDERSHOOT_CONF2,
0xFF,
0x03 /* Set default Undershoot Protection */
)
/****** Default Analog Configuration for Poll AP2P Tx 212 ******/
,
MODE_ENTRY_1_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P | RFAL_ANALOG_CONFIG_BITRATE_212 |
RFAL_ANALOG_CONFIG_TX),
ST25R3916_REG_MODE,
ST25R3916_REG_MODE_tr_am,
ST25R3916_REG_MODE_tr_am_am /* Use AM modulation */
)
/****** Default Analog Configuration for Poll AP2P Tx 424 ******/
,
MODE_ENTRY_1_REG(
(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P | RFAL_ANALOG_CONFIG_BITRATE_424 |
RFAL_ANALOG_CONFIG_TX),
ST25R3916_REG_MODE,
ST25R3916_REG_MODE_tr_am,
ST25R3916_REG_MODE_tr_am_am /* Use AM modulation */
)
/****** Default Analog Configuration for Chip-Specific Listen On ******/
,
MODE_ENTRY_6_REG(
(RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LISTEN_ON),
ST25R3916_REG_ANT_TUNE_A,
0xFF,
0x00 /* Set Antenna Tuning (Listener): ANTL */
,
ST25R3916_REG_ANT_TUNE_B,
0xFF,
0xff /* Set Antenna Tuning (Listener): ANTL */
,
ST25R3916_REG_OVERSHOOT_CONF1,
0xFF,
0x00 /* Disable Overshoot Protection */
,
ST25R3916_REG_OVERSHOOT_CONF2,
0xFF,
0x00 /* Disable Overshoot Protection */
,
ST25R3916_REG_UNDERSHOOT_CONF1,
0xFF,
0x00 /* Disable Undershoot Protection */
,
ST25R3916_REG_UNDERSHOOT_CONF2,
0xFF,
0x00 /* Disable Undershoot Protection */
)
/****** Default Analog Configuration for Listen AP2P Tx Common ******/
,
MODE_ENTRY_7_REG(
(RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P |
RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX),
ST25R3916_REG_ANT_TUNE_A,
0xFF,
0x82 /* Set Antenna Tuning (Poller): ANTL */
,
ST25R3916_REG_ANT_TUNE_B,
0xFF,
0x82 /* Set Antenna Tuning (Poller): ANTL */
,
ST25R3916_REG_TX_DRIVER,
ST25R3916_REG_TX_DRIVER_am_mod_mask,
ST25R3916_REG_TX_DRIVER_am_mod_12percent /* Set Modulation index */
,
ST25R3916_REG_OVERSHOOT_CONF1,
0xFF,
0x00 /* Disable Overshoot Protection */
,
ST25R3916_REG_OVERSHOOT_CONF2,
0xFF,
0x00 /* Disable Overshoot Protection */
,
ST25R3916_REG_UNDERSHOOT_CONF1,
0xFF,
0x00 /* Disable Undershoot Protection */
,
ST25R3916_REG_UNDERSHOOT_CONF2,
0xFF,
0x00 /* Disable Undershoot Protection */
)
/****** Default Analog Configuration for Listen AP2P Rx Common ******/
,
MODE_ENTRY_3_REG(
(RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P |
RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX),
ST25R3916_REG_RX_CONF1,
ST25R3916_REG_RX_CONF1_lp_mask,
ST25R3916_REG_RX_CONF1_lp_1200khz /* Set Rx filter configuration */
,
ST25R3916_REG_RX_CONF1,
ST25R3916_REG_RX_CONF1_hz_mask,
ST25R3916_REG_RX_CONF1_hz_12_200khz /* Set Rx filter configuration */
,
ST25R3916_REG_RX_CONF2,
ST25R3916_REG_RX_CONF2_amd_sel,
ST25R3916_REG_RX_CONF2_amd_sel_mixer /* AM demodulator: mixer */
)
/****** Default Analog Configuration for Listen AP2P Tx 106 ******/
,
MODE_ENTRY_5_REG(
(RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P |
RFAL_ANALOG_CONFIG_BITRATE_106 | RFAL_ANALOG_CONFIG_TX),
ST25R3916_REG_MODE,
ST25R3916_REG_MODE_tr_am,
ST25R3916_REG_MODE_tr_am_ook /* Use OOK modulation */
,
ST25R3916_REG_OVERSHOOT_CONF1,
0xFF,
0x40 /* Set default Overshoot Protection */
,
ST25R3916_REG_OVERSHOOT_CONF2,
0xFF,
0x03 /* Set default Overshoot Protection */
,
ST25R3916_REG_UNDERSHOOT_CONF1,
0xFF,
0x40 /* Set default Undershoot Protection */
,
ST25R3916_REG_UNDERSHOOT_CONF2,
0xFF,
0x03 /* Set default Undershoot Protection */
)
/****** Default Analog Configuration for Listen AP2P Tx 212 ******/
,
MODE_ENTRY_1_REG(
(RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P |
RFAL_ANALOG_CONFIG_BITRATE_212 | RFAL_ANALOG_CONFIG_TX),
ST25R3916_REG_MODE,
ST25R3916_REG_MODE_tr_am,
ST25R3916_REG_MODE_tr_am_am /* Use AM modulation */
)
/****** Default Analog Configuration for Listen AP2P Tx 424 ******/
,
MODE_ENTRY_1_REG(
(RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P |
RFAL_ANALOG_CONFIG_BITRATE_424 | RFAL_ANALOG_CONFIG_TX),
ST25R3916_REG_MODE,
ST25R3916_REG_MODE_tr_am,
ST25R3916_REG_MODE_tr_am_am /* Use AM modulation */
)
};
const uint16_t rfalAnalogConfigCustomSettingsLength = sizeof(rfalAnalogConfigCustomSettings);
-476
View File
@@ -1,476 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_analogConfig.c
*
* \author bkam
*
* \brief Functions to manage and set analog settings.
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "rfal_analogConfig.h"
#include "rfal_chip.h"
#include "st_errno.h"
#include "platform.h"
#include "utils.h"
/* Check whether the Default Analog settings are to be used or custom ones */
#ifdef RFAL_ANALOG_CONFIG_CUSTOM
extern const uint8_t* rfalAnalogConfigCustomSettings;
extern const uint16_t rfalAnalogConfigCustomSettingsLength;
#else
#include "rfal_analogConfigTbl.h"
#endif
/*
******************************************************************************
* DEFINES
******************************************************************************
*/
#define RFAL_TEST_REG 0x0080U /*!< Test Register indicator */
/*
******************************************************************************
* MACROS
******************************************************************************
*/
/*
******************************************************************************
* LOCAL DATA TYPES
******************************************************************************
*/
#if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG
static uint8_t
gRfalAnalogConfig[RFAL_ANALOG_CONFIG_TBL_SIZE]; /*!< Analog Configuration Settings List */
#endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */
/*! Struct for Analog Config Look Up Table Update */
typedef struct {
const uint8_t*
currentAnalogConfigTbl; /*!< Reference to start of current Analog Configuration */
uint16_t configTblSize; /*!< Total size of Analog Configuration */
bool ready; /*!< Indicate if Look Up Table is complete and ready for use */
} rfalAnalogConfigMgmt;
static rfalAnalogConfigMgmt gRfalAnalogConfigMgmt; /*!< Analog Configuration LUT management */
/*
******************************************************************************
* LOCAL TABLES
******************************************************************************
*/
/*
******************************************************************************
* LOCAL FUNCTION PROTOTYPES
******************************************************************************
*/
static rfalAnalogConfigNum
rfalAnalogConfigSearch(rfalAnalogConfigId configId, uint16_t* configOffset);
#if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG
static void rfalAnalogConfigPtrUpdate(const uint8_t* analogConfigTbl);
#endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */
/*
******************************************************************************
* GLOBAL VARIABLE DEFINITIONS
******************************************************************************
*/
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
void rfalAnalogConfigInitialize(void) {
/* Use default Analog configuration settings in Flash by default. */
/* Check whether the Default Analog settings are to be used or custom ones */
#ifdef RFAL_ANALOG_CONFIG_CUSTOM
gRfalAnalogConfigMgmt.currentAnalogConfigTbl = (const uint8_t*)&rfalAnalogConfigCustomSettings;
gRfalAnalogConfigMgmt.configTblSize = rfalAnalogConfigCustomSettingsLength;
#else
gRfalAnalogConfigMgmt.currentAnalogConfigTbl =
(const uint8_t*)&rfalAnalogConfigDefaultSettings;
gRfalAnalogConfigMgmt.configTblSize = sizeof(rfalAnalogConfigDefaultSettings);
#endif
gRfalAnalogConfigMgmt.ready = true;
} /* rfalAnalogConfigInitialize() */
bool rfalAnalogConfigIsReady(void) {
return gRfalAnalogConfigMgmt.ready;
}
ReturnCode rfalAnalogConfigListWriteRaw(const uint8_t* configTbl, uint16_t configTblSize) {
#if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG
/* Check if the Configuration Table exceed the Table size */
if(configTblSize >= RFAL_ANALOG_CONFIG_TBL_SIZE) {
rfalAnalogConfigInitialize(); /* Revert to default Analog Configuration */
return ERR_NOMEM;
}
/* Check for invalid parameters */
if((configTbl == NULL) || (configTblSize == 0U)) {
return ERR_PARAM;
}
/* NOTE: Function does not check for the validity of the Table contents (conf IDs, conf sets, register address) */
ST_MEMCPY(gRfalAnalogConfig, configTbl, configTblSize);
/* Update the total size of configuration settings */
gRfalAnalogConfigMgmt.configTblSize = configTblSize;
rfalAnalogConfigPtrUpdate(gRfalAnalogConfig);
return ERR_NONE;
#else
// If Analog Configuration Update is to be disabled
NO_WARNING(configTbl);
NO_WARNING(configTblSize);
return ERR_REQUEST;
#endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */
}
ReturnCode rfalAnalogConfigListWrite(uint8_t more, const rfalAnalogConfig* config) {
#if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG
rfalAnalogConfigId configId;
rfalAnalogConfigNum numConfig;
uint8_t configSize;
if(true == gRfalAnalogConfigMgmt.ready) { /* First Update to the Configuration list. */
gRfalAnalogConfigMgmt.ready = false; // invalidate the config List
gRfalAnalogConfigMgmt.configTblSize = 0; // Clear the config List
}
configId = GETU16(config->id);
/* Check validity of the Configuration ID. */
if((RFAL_ANALOG_CONFIG_TECH_RFU <= RFAL_ANALOG_CONFIG_ID_GET_TECH(configId)) ||
((RFAL_ANALOG_CONFIG_BITRATE_6780 < RFAL_ANALOG_CONFIG_ID_GET_BITRATE(configId)) &&
(RFAL_ANALOG_CONFIG_BITRATE_1OF4 > RFAL_ANALOG_CONFIG_ID_GET_BITRATE(configId))) ||
(RFAL_ANALOG_CONFIG_BITRATE_1OF256 < RFAL_ANALOG_CONFIG_ID_GET_BITRATE(configId))) {
rfalAnalogConfigInitialize(); /* Revert to default Analog Configuration */
return ERR_PARAM;
}
numConfig = config->num;
configSize =
(uint8_t)(sizeof(rfalAnalogConfigId) + sizeof(rfalAnalogConfigNum) + (numConfig * sizeof(rfalAnalogConfigRegAddrMaskVal)));
/* Check if the Configuration Set exceed the Table size. */
if(RFAL_ANALOG_CONFIG_TBL_SIZE <= (gRfalAnalogConfigMgmt.configTblSize + configSize)) {
rfalAnalogConfigInitialize(); /* Revert to default Analog Configuration */
return ERR_NOMEM;
}
/* NOTE: Function does not check for the validity of the Register Address. */
ST_MEMCPY(
&gRfalAnalogConfig[gRfalAnalogConfigMgmt.configTblSize],
(const uint8_t*)config,
configSize);
/* Increment the total size of configuration settings. */
gRfalAnalogConfigMgmt.configTblSize += configSize;
/* Check if it is the last Analog Configuration to load. */
if(RFAL_ANALOG_CONFIG_UPDATE_LAST ==
more) { /* Update the Analog Configuration to the new settings. */
rfalAnalogConfigPtrUpdate(gRfalAnalogConfig);
}
return ERR_NONE;
#else
// If Analog Configuration Update is to be disabled
NO_WARNING(config);
NO_WARNING(more);
return ERR_DISABLED;
#endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */
} /* rfalAnalogConfigListUpdate() */
ReturnCode
rfalAnalogConfigListReadRaw(uint8_t* tblBuf, uint16_t tblBufLen, uint16_t* configTblSize) {
/* Check if the the current table will fit into the given buffer */
if(tblBufLen < gRfalAnalogConfigMgmt.configTblSize) {
return ERR_NOMEM;
}
/* Check for invalid parameters */
if(configTblSize == NULL) {
return ERR_PARAM;
}
/* Copy the whole Table to the given buffer */
if(gRfalAnalogConfigMgmt.configTblSize > 0U) /* MISRA 21.18 */
{
ST_MEMCPY(
tblBuf,
gRfalAnalogConfigMgmt.currentAnalogConfigTbl,
gRfalAnalogConfigMgmt.configTblSize);
}
*configTblSize = gRfalAnalogConfigMgmt.configTblSize;
return ERR_NONE;
}
ReturnCode rfalAnalogConfigListRead(
rfalAnalogConfigOffset* configOffset,
uint8_t* more,
rfalAnalogConfig* config,
rfalAnalogConfigNum numConfig) {
uint16_t configSize;
rfalAnalogConfigOffset offset = *configOffset;
rfalAnalogConfigNum numConfigSet;
/* Check if the number of register-mask-value settings for the respective Configuration ID will fit into the buffer passed in. */
if(gRfalAnalogConfigMgmt.currentAnalogConfigTbl[offset + sizeof(rfalAnalogConfigId)] >
numConfig) {
return ERR_NOMEM;
}
/* Get the number of Configuration set */
numConfigSet =
gRfalAnalogConfigMgmt.currentAnalogConfigTbl[offset + sizeof(rfalAnalogConfigId)];
/* Pass Configuration Register-Mask-Value sets */
configSize =
(sizeof(rfalAnalogConfigId) + sizeof(rfalAnalogConfigNum) +
(uint16_t)(numConfigSet * sizeof(rfalAnalogConfigRegAddrMaskVal)));
ST_MEMCPY((uint8_t*)config, &gRfalAnalogConfigMgmt.currentAnalogConfigTbl[offset], configSize);
*configOffset = offset + configSize;
/* Check if it is the last Analog Configuration in the Table.*/
*more =
(uint8_t)((*configOffset >= gRfalAnalogConfigMgmt.configTblSize) ? RFAL_ANALOG_CONFIG_UPDATE_LAST : RFAL_ANALOG_CONFIG_UPDATE_MORE);
return ERR_NONE;
} /* rfalAnalogConfigListRead() */
ReturnCode rfalSetAnalogConfig(rfalAnalogConfigId configId) {
rfalAnalogConfigOffset configOffset = 0;
rfalAnalogConfigNum numConfigSet;
const rfalAnalogConfigRegAddrMaskVal* configTbl;
ReturnCode retCode = ERR_NONE;
rfalAnalogConfigNum i;
if(true != gRfalAnalogConfigMgmt.ready) {
return ERR_REQUEST;
}
/* Search LUT for the specific Configuration ID. */
while(true) {
numConfigSet = rfalAnalogConfigSearch(configId, &configOffset);
if(RFAL_ANALOG_CONFIG_LUT_NOT_FOUND == numConfigSet) {
break;
}
configTbl =
(rfalAnalogConfigRegAddrMaskVal*)((uint32_t)gRfalAnalogConfigMgmt.currentAnalogConfigTbl + (uint32_t)configOffset);
/* Increment the offset to the next index to search from. */
configOffset += (uint16_t)(numConfigSet * sizeof(rfalAnalogConfigRegAddrMaskVal));
if((gRfalAnalogConfigMgmt.configTblSize + 1U) <
configOffset) { /* Error check make sure that the we do not access outside the configuration Table Size */
return ERR_NOMEM;
}
for(i = 0; i < numConfigSet; i++) {
if((GETU16(configTbl[i].addr) & RFAL_TEST_REG) != 0U) {
EXIT_ON_ERR(
retCode,
rfalChipChangeTestRegBits(
(GETU16(configTbl[i].addr) & ~RFAL_TEST_REG),
configTbl[i].mask,
configTbl[i].val));
} else {
EXIT_ON_ERR(
retCode,
rfalChipChangeRegBits(
GETU16(configTbl[i].addr), configTbl[i].mask, configTbl[i].val));
}
}
} /* while(found Analog Config Id) */
return retCode;
} /* rfalSetAnalogConfig() */
uint16_t rfalAnalogConfigGenModeID(rfalMode md, rfalBitRate br, uint16_t dir) {
uint16_t id;
/* Assign Poll/Listen Mode */
id = ((md >= RFAL_MODE_LISTEN_NFCA) ? RFAL_ANALOG_CONFIG_LISTEN : RFAL_ANALOG_CONFIG_POLL);
/* Assign Technology */
switch(md) {
case RFAL_MODE_POLL_NFCA:
case RFAL_MODE_POLL_NFCA_T1T:
case RFAL_MODE_LISTEN_NFCA:
id |= RFAL_ANALOG_CONFIG_TECH_NFCA;
break;
case RFAL_MODE_POLL_NFCB:
case RFAL_MODE_POLL_B_PRIME:
case RFAL_MODE_POLL_B_CTS:
case RFAL_MODE_LISTEN_NFCB:
id |= RFAL_ANALOG_CONFIG_TECH_NFCB;
break;
case RFAL_MODE_POLL_NFCF:
case RFAL_MODE_LISTEN_NFCF:
id |= RFAL_ANALOG_CONFIG_TECH_NFCF;
break;
case RFAL_MODE_POLL_NFCV:
case RFAL_MODE_POLL_PICOPASS:
id |= RFAL_ANALOG_CONFIG_TECH_NFCV;
break;
case RFAL_MODE_POLL_ACTIVE_P2P:
case RFAL_MODE_LISTEN_ACTIVE_P2P:
id |= RFAL_ANALOG_CONFIG_TECH_AP2P;
break;
default:
id = RFAL_ANALOG_CONFIG_TECH_CHIP;
break;
}
/* Assign Bitrate */
id |=
(((((uint16_t)(br) >= (uint16_t)RFAL_BR_52p97) ? (uint16_t)(br) : ((uint16_t)(br) + 1U))
<< RFAL_ANALOG_CONFIG_BITRATE_SHIFT) &
RFAL_ANALOG_CONFIG_BITRATE_MASK);
/* Assign Direction */
id |= ((dir << RFAL_ANALOG_CONFIG_DIRECTION_SHIFT) & RFAL_ANALOG_CONFIG_DIRECTION_MASK);
return id;
} /* rfalAnalogConfigGenModeID() */
/*
******************************************************************************
* LOCAL FUNCTIONS
******************************************************************************
*/
/*!
*****************************************************************************
* \brief Update the link to Analog Configuration LUT
*
* Update the link to the Analog Configuration LUT for the subsequent search
* of Analog Settings.
*
* \param[in] analogConfigTbl: reference to the start of the new Analog Configuration Table
*
*****************************************************************************
*/
#if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG
static void rfalAnalogConfigPtrUpdate(const uint8_t* analogConfigTbl) {
gRfalAnalogConfigMgmt.currentAnalogConfigTbl = analogConfigTbl;
gRfalAnalogConfigMgmt.ready = true;
} /* rfalAnalogConfigPtrUpdate() */
#endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */
/*!
*****************************************************************************
* \brief Search the Analog Configuration LUT for a specific Configuration ID.
*
* Search the Analog Configuration LUT for the Configuration ID.
*
* \param[in] configId: Configuration ID to search for.
* \param[in] configOffset: Configuration Offset in Table
*
* \return number of Configuration Sets
* \return #RFAL_ANALOG_CONFIG_LUT_NOT_FOUND in case Configuration ID is not found.
*****************************************************************************
*/
static rfalAnalogConfigNum
rfalAnalogConfigSearch(rfalAnalogConfigId configId, uint16_t* configOffset) {
rfalAnalogConfigId foundConfigId;
rfalAnalogConfigId configIdMaskVal;
const uint8_t* configTbl;
const uint8_t* currentConfigTbl;
uint16_t i;
currentConfigTbl = gRfalAnalogConfigMgmt.currentAnalogConfigTbl;
configIdMaskVal =
((RFAL_ANALOG_CONFIG_POLL_LISTEN_MODE_MASK | RFAL_ANALOG_CONFIG_BITRATE_MASK) |
((RFAL_ANALOG_CONFIG_TECH_CHIP == RFAL_ANALOG_CONFIG_ID_GET_TECH(configId)) ?
(RFAL_ANALOG_CONFIG_TECH_MASK | RFAL_ANALOG_CONFIG_CHIP_SPECIFIC_MASK) :
configId) |
((RFAL_ANALOG_CONFIG_NO_DIRECTION == RFAL_ANALOG_CONFIG_ID_GET_DIRECTION(configId)) ?
RFAL_ANALOG_CONFIG_DIRECTION_MASK :
configId));
/* When specific ConfigIDs are to be used, override search mask */
if((RFAL_ANALOG_CONFIG_ID_GET_DIRECTION(configId) == RFAL_ANALOG_CONFIG_DPO)) {
configIdMaskVal =
(RFAL_ANALOG_CONFIG_POLL_LISTEN_MODE_MASK | RFAL_ANALOG_CONFIG_TECH_MASK |
RFAL_ANALOG_CONFIG_BITRATE_MASK | RFAL_ANALOG_CONFIG_DIRECTION_MASK);
}
i = *configOffset;
while(i < gRfalAnalogConfigMgmt.configTblSize) {
configTbl = &currentConfigTbl[i];
foundConfigId = GETU16(configTbl);
if(configId == (foundConfigId & configIdMaskVal)) {
*configOffset =
(uint16_t)(i + sizeof(rfalAnalogConfigId) + sizeof(rfalAnalogConfigNum));
return configTbl[sizeof(rfalAnalogConfigId)];
}
/* If Config Id does not match, increment to next Configuration Id */
i +=
(uint16_t)(sizeof(rfalAnalogConfigId) + sizeof(rfalAnalogConfigNum) + (configTbl[sizeof(rfalAnalogConfigId)] * sizeof(rfalAnalogConfigRegAddrMaskVal)));
} /* for */
return RFAL_ANALOG_CONFIG_LUT_NOT_FOUND;
} /* rfalAnalogConfigSearch() */
-82
View File
@@ -1,82 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_crc.c
*
* \author Oliver Regenfelder
*
* \brief CRC calculation implementation
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "rfal_crc.h"
/*
******************************************************************************
* LOCAL FUNCTION PROTOTYPES
******************************************************************************
*/
static uint16_t rfalCrcUpdateCcitt(uint16_t crcSeed, uint8_t dataByte);
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
uint16_t rfalCrcCalculateCcitt(uint16_t preloadValue, const uint8_t* buf, uint16_t length) {
uint16_t crc = preloadValue;
uint16_t index;
for(index = 0; index < length; index++) {
crc = rfalCrcUpdateCcitt(crc, buf[index]);
}
return crc;
}
/*
******************************************************************************
* LOCAL FUNCTIONS
******************************************************************************
*/
static uint16_t rfalCrcUpdateCcitt(uint16_t crcSeed, uint8_t dataByte) {
uint16_t crc = crcSeed;
uint8_t dat = dataByte;
dat ^= (uint8_t)(crc & 0xFFU);
dat ^= (dat << 4);
crc = (crc >> 8) ^ (((uint16_t)dat) << 8) ^ (((uint16_t)dat) << 3) ^ (((uint16_t)dat) >> 4);
return crc;
}
-232
View File
@@ -1,232 +0,0 @@
/******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* $Revision: $
* LANGUAGE: ISO C99
*/
/*! \file rfal_dpo.c
*
* \author Martin Zechleitner
*
* \brief Functions to manage and set dynamic power settings.
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "rfal_dpoTbl.h"
#include "rfal_dpo.h"
#include "platform.h"
#include "rfal_rf.h"
#include "rfal_chip.h"
#include "rfal_analogConfig.h"
#include "utils.h"
/*
******************************************************************************
* ENABLE SWITCH
******************************************************************************
*/
#ifndef RFAL_FEATURE_DPO
#define RFAL_FEATURE_DPO \
false /* Dynamic Power Module configuration missing. Disabled by default */
#endif
#if RFAL_FEATURE_DPO
/*
******************************************************************************
* DEFINES
******************************************************************************
*/
#define RFAL_DPO_ANALOGCONFIG_SHIFT 13U
#define RFAL_DPO_ANALOGCONFIG_MASK 0x6000U
/*
******************************************************************************
* LOCAL DATA TYPES
******************************************************************************
*/
static bool gRfalDpoIsEnabled = false;
static uint8_t* gRfalCurrentDpo;
static uint8_t gRfalDpoTableEntries;
static uint8_t gRfalDpo[RFAL_DPO_TABLE_SIZE_MAX];
static uint8_t gRfalDpoTableEntry;
static rfalDpoMeasureFunc gRfalDpoMeasureCallback = NULL;
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
void rfalDpoInitialize(void) {
/* Use the default Dynamic Power values */
gRfalCurrentDpo = (uint8_t*)rfalDpoDefaultSettings;
gRfalDpoTableEntries = (sizeof(rfalDpoDefaultSettings) / RFAL_DPO_TABLE_PARAMETER);
ST_MEMCPY(gRfalDpo, gRfalCurrentDpo, sizeof(rfalDpoDefaultSettings));
/* by default use amplitude measurement */
gRfalDpoMeasureCallback = rfalChipMeasureAmplitude;
/* by default DPO is disabled */
gRfalDpoIsEnabled = false;
gRfalDpoTableEntry = 0;
}
void rfalDpoSetMeasureCallback(rfalDpoMeasureFunc pMeasureFunc) {
gRfalDpoMeasureCallback = pMeasureFunc;
}
/*******************************************************************************/
ReturnCode rfalDpoTableWrite(rfalDpoEntry* powerTbl, uint8_t powerTblEntries) {
uint8_t entry = 0;
/* check if the table size parameter is too big */
if((powerTblEntries * RFAL_DPO_TABLE_PARAMETER) > RFAL_DPO_TABLE_SIZE_MAX) {
return ERR_NOMEM;
}
/* check if the first increase entry is 0xFF */
if((powerTblEntries == 0) || (powerTbl == NULL)) {
return ERR_PARAM;
}
/* check if the entries of the dynamic power table are valid */
for(entry = 0; entry < powerTblEntries; entry++) {
if(powerTbl[entry].inc < powerTbl[entry].dec) {
return ERR_PARAM;
}
}
/* copy the data set */
ST_MEMCPY(gRfalDpo, powerTbl, (powerTblEntries * RFAL_DPO_TABLE_PARAMETER));
gRfalCurrentDpo = gRfalDpo;
gRfalDpoTableEntries = powerTblEntries;
if(gRfalDpoTableEntry > powerTblEntries) {
/* is always greater then zero, otherwise we already returned ERR_PARAM */
gRfalDpoTableEntry = (powerTblEntries - 1);
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode rfalDpoTableRead(rfalDpoEntry* tblBuf, uint8_t tblBufEntries, uint8_t* tableEntries) {
/* wrong request */
if((tblBuf == NULL) || (tblBufEntries < gRfalDpoTableEntries) || (tableEntries == NULL)) {
return ERR_PARAM;
}
/* Copy the whole Table to the given buffer */
ST_MEMCPY(tblBuf, gRfalCurrentDpo, (tblBufEntries * RFAL_DPO_TABLE_PARAMETER));
*tableEntries = gRfalDpoTableEntries;
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode rfalDpoAdjust(void) {
uint8_t refValue = 0;
uint16_t modeID;
rfalBitRate br;
rfalDpoEntry* dpoTable = (rfalDpoEntry*)gRfalCurrentDpo;
/* Check if the Power Adjustment is disabled and *
* if the callback to the measurement method is properly set */
if((gRfalCurrentDpo == NULL) || (!gRfalDpoIsEnabled) || (gRfalDpoMeasureCallback == NULL)) {
return ERR_PARAM;
}
/* Ensure that the current mode is Passive Poller */
if(!rfalIsModePassivePoll(rfalGetMode())) {
return ERR_WRONG_STATE;
}
/* Ensure a proper measure reference value */
if(ERR_NONE != gRfalDpoMeasureCallback(&refValue)) {
return ERR_IO;
}
if(refValue >= dpoTable[gRfalDpoTableEntry].inc) { /* Increase the output power */
/* the top of the table represents the highest amplitude value*/
if(gRfalDpoTableEntry == 0) {
/* maximum driver value has been reached */
} else {
/* go up in the table to decrease the driver resistance */
gRfalDpoTableEntry--;
}
} else if(refValue <= dpoTable[gRfalDpoTableEntry].dec) { /* decrease the output power */
/* The bottom is the highest possible value */
if((gRfalDpoTableEntry + 1) >= gRfalDpoTableEntries) {
/* minimum driver value has been reached */
} else {
/* go down in the table to increase the driver resistance */
gRfalDpoTableEntry++;
}
} else {
/* Fall through to always write dpo and its associated analog configs */
}
/* Get the new value for RFO resistance form the table and apply the new RFO resistance setting */
rfalChipSetRFO(dpoTable[gRfalDpoTableEntry].rfoRes);
/* Apply the DPO Analog Config according to this treshold */
/* Technology field is being extended for DPO: 2msb are used for treshold step (only 4 allowed) */
rfalGetBitRate(&br, NULL); /* Obtain current Tx bitrate */
modeID = rfalAnalogConfigGenModeID(
rfalGetMode(), br, RFAL_ANALOG_CONFIG_DPO); /* Generate Analog Config mode ID */
modeID |=
((gRfalDpoTableEntry << RFAL_DPO_ANALOGCONFIG_SHIFT) &
RFAL_DPO_ANALOGCONFIG_MASK); /* Add DPO treshold step|level */
rfalSetAnalogConfig(modeID); /* Apply DPO Analog Config */
return ERR_NONE;
}
/*******************************************************************************/
rfalDpoEntry* rfalDpoGetCurrentTableEntry(void) {
rfalDpoEntry* dpoTable = (rfalDpoEntry*)gRfalCurrentDpo;
return &dpoTable[gRfalDpoTableEntry];
}
/*******************************************************************************/
void rfalDpoSetEnabled(bool enable) {
gRfalDpoIsEnabled = enable;
}
/*******************************************************************************/
bool rfalDpoIsEnabled(void) {
return gRfalDpoIsEnabled;
}
#endif /* RFAL_FEATURE_DPO */
-514
View File
@@ -1,514 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_iso15693_2.c
*
* \author Ulrich Herrmann
*
* \brief Implementation of ISO-15693-2
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "rfal_iso15693_2.h"
#include "rfal_crc.h"
#include "utils.h"
/*
******************************************************************************
* ENABLE SWITCH
******************************************************************************
*/
#ifndef RFAL_FEATURE_NFCV
#define RFAL_FEATURE_NFCV false /* NFC-V module configuration missing. Disabled by default */
#endif
#if RFAL_FEATURE_NFCV
/*
******************************************************************************
* LOCAL MACROS
******************************************************************************
*/
#define ISO_15693_DEBUG(...) /*!< Macro for the log method */
/*
******************************************************************************
* LOCAL DEFINES
******************************************************************************
*/
#define ISO15693_DAT_SOF_1_4 0x21 /* LSB constants */
#define ISO15693_DAT_EOF_1_4 0x04
#define ISO15693_DAT_00_1_4 0x02
#define ISO15693_DAT_01_1_4 0x08
#define ISO15693_DAT_10_1_4 0x20
#define ISO15693_DAT_11_1_4 0x80
#define ISO15693_DAT_SOF_1_256 0x81
#define ISO15693_DAT_EOF_1_256 0x04
#define ISO15693_DAT_SLOT0_1_256 0x02
#define ISO15693_DAT_SLOT1_1_256 0x08
#define ISO15693_DAT_SLOT2_1_256 0x20
#define ISO15693_DAT_SLOT3_1_256 0x80
#define ISO15693_PHY_DAT_MANCHESTER_1 0xaaaa
#define ISO15693_PHY_BIT_BUFFER_SIZE \
1000 /*!< size of the receiving buffer. Might be adjusted if longer datastreams are expected. */
/*
******************************************************************************
* LOCAL VARIABLES
******************************************************************************
*/
static iso15693PhyConfig_t iso15693PhyConfig; /*!< current phy configuration */
/*
******************************************************************************
* LOCAL FUNCTION PROTOTYPES
******************************************************************************
*/
static ReturnCode iso15693PhyVCDCode1Of4(
const uint8_t data,
uint8_t* outbuffer,
uint16_t maxOutBufLen,
uint16_t* outBufLen);
static ReturnCode iso15693PhyVCDCode1Of256(
const uint8_t data,
uint8_t* outbuffer,
uint16_t maxOutBufLen,
uint16_t* outBufLen);
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
ReturnCode iso15693PhyConfigure(
const iso15693PhyConfig_t* config,
const struct iso15693StreamConfig** needed_stream_config) {
static struct iso15693StreamConfig stream_config = {
/* MISRA 8.9 */
.useBPSK = 0, /* 0: subcarrier, 1:BPSK */
.din = 5, /* 2^5*fc = 423750 Hz: divider for the in subcarrier frequency */
.dout = 7, /*!< 2^7*fc = 105937 : divider for the in subcarrier frequency */
.report_period_length = 3, /*!< 8=2^3 the length of the reporting period */
};
/* make a copy of the configuration */
ST_MEMCPY((uint8_t*)&iso15693PhyConfig, (const uint8_t*)config, sizeof(iso15693PhyConfig_t));
if(config->speedMode <= 3U) { /* If valid speed mode adjust report period accordingly */
stream_config.report_period_length = (3U - (uint8_t)config->speedMode);
} else { /* If invalid default to normal (high) speed */
stream_config.report_period_length = 3;
}
*needed_stream_config = &stream_config;
return ERR_NONE;
}
ReturnCode iso15693PhyGetConfiguration(iso15693PhyConfig_t* config) {
ST_MEMCPY(config, &iso15693PhyConfig, sizeof(iso15693PhyConfig_t));
return ERR_NONE;
}
ReturnCode iso15693VCDCode(
uint8_t* buffer,
uint16_t length,
bool sendCrc,
bool sendFlags,
bool picopassMode,
uint16_t* subbit_total_length,
uint16_t* offset,
uint8_t* outbuf,
uint16_t outBufSize,
uint16_t* actOutBufSize) {
ReturnCode err = ERR_NONE;
uint8_t eof, sof;
uint8_t transbuf[2];
uint16_t crc = 0;
ReturnCode (*txFunc)(
const uint8_t data, uint8_t* outbuffer, uint16_t maxOutBufLen, uint16_t* outBufLen);
uint8_t crc_len;
uint8_t* outputBuf;
uint16_t outputBufSize;
crc_len = (uint8_t)((sendCrc) ? 2 : 0);
*actOutBufSize = 0;
if(ISO15693_VCD_CODING_1_4 == iso15693PhyConfig.coding) {
sof = ISO15693_DAT_SOF_1_4;
eof = ISO15693_DAT_EOF_1_4;
txFunc = iso15693PhyVCDCode1Of4;
*subbit_total_length =
((1U /* SOF */
+ ((length + (uint16_t)crc_len) * 4U) + 1U) /* EOF */
);
if(outBufSize < 5U) { /* 5 should be safe: enough for sof + 1byte data in 1of4 */
return ERR_NOMEM;
}
} else {
sof = ISO15693_DAT_SOF_1_256;
eof = ISO15693_DAT_EOF_1_256;
txFunc = iso15693PhyVCDCode1Of256;
*subbit_total_length =
((1U /* SOF */
+ ((length + (uint16_t)crc_len) * 64U) + 1U) /* EOF */
);
if(*offset != 0U) {
if(outBufSize < 64U) { /* 64 should be safe: enough a single byte data in 1of256 */
return ERR_NOMEM;
}
} else {
if(outBufSize <
65U) { /* At beginning of a frame we need at least 65 bytes to start: enough for sof + 1byte data in 1of256 */
return ERR_NOMEM;
}
}
}
if(length == 0U) {
*subbit_total_length = 1;
}
if((length != 0U) && (0U == *offset) && sendFlags && !picopassMode) {
/* set high datarate flag */
buffer[0] |= (uint8_t)ISO15693_REQ_FLAG_HIGH_DATARATE;
/* clear sub-carrier flag - we only support single sub-carrier */
buffer[0] = (uint8_t)(buffer[0] & ~ISO15693_REQ_FLAG_TWO_SUBCARRIERS); /* MISRA 10.3 */
}
outputBuf = outbuf; /* MISRA 17.8: Use intermediate variable */
outputBufSize = outBufSize; /* MISRA 17.8: Use intermediate variable */
/* Send SOF if at 0 offset */
if((length != 0U) && (0U == *offset)) {
*outputBuf = sof;
(*actOutBufSize)++;
outputBufSize--;
outputBuf++;
}
while((*offset < length) && (err == ERR_NONE)) {
uint16_t filled_size;
/* send data */
err = txFunc(buffer[*offset], outputBuf, outputBufSize, &filled_size);
(*actOutBufSize) += filled_size;
outputBuf = &outputBuf[filled_size]; /* MISRA 18.4: Avoid pointer arithmetic */
outputBufSize -= filled_size;
if(err == ERR_NONE) {
(*offset)++;
}
}
if(err != ERR_NONE) {
return ERR_AGAIN;
}
while((err == ERR_NONE) && sendCrc && (*offset < (length + 2U))) {
uint16_t filled_size;
if(0U == crc) {
crc = rfalCrcCalculateCcitt(
(uint16_t)((picopassMode) ? 0xE012U : 0xFFFFU), /* In PicoPass Mode a different Preset Value is used */
((picopassMode) ?
(buffer + 1U) :
buffer), /* CMD byte is not taken into account in PicoPass mode */
((picopassMode) ?
(length - 1U) :
length)); /* CMD byte is not taken into account in PicoPass mode */
crc = (uint16_t)((picopassMode) ? crc : ~crc);
}
/* send crc */
transbuf[0] = (uint8_t)(crc & 0xffU);
transbuf[1] = (uint8_t)((crc >> 8) & 0xffU);
err = txFunc(transbuf[*offset - length], outputBuf, outputBufSize, &filled_size);
(*actOutBufSize) += filled_size;
outputBuf = &outputBuf[filled_size]; /* MISRA 18.4: Avoid pointer arithmetic */
outputBufSize -= filled_size;
if(err == ERR_NONE) {
(*offset)++;
}
}
if(err != ERR_NONE) {
return ERR_AGAIN;
}
if((!sendCrc && (*offset == length)) || (sendCrc && (*offset == (length + 2U)))) {
*outputBuf = eof;
(*actOutBufSize)++;
outputBufSize--;
outputBuf++;
} else {
return ERR_AGAIN;
}
return err;
}
ReturnCode iso15693VICCDecode(
const uint8_t* inBuf,
uint16_t inBufLen,
uint8_t* outBuf,
uint16_t outBufLen,
uint16_t* outBufPos,
uint16_t* bitsBeforeCol,
uint16_t ignoreBits,
bool picopassMode) {
ReturnCode err = ERR_NONE;
uint16_t crc;
uint16_t mp; /* Current bit position in manchester bit inBuf*/
uint16_t bp; /* Current bit position in outBuf */
*bitsBeforeCol = 0;
*outBufPos = 0;
/* first check for valid SOF. Since it starts with 3 unmodulated pulses it is 0x17. */
if((inBuf[0] & 0x1fU) != 0x17U) {
ISO_15693_DEBUG("0x%x\n", iso15693PhyBitBuffer[0]);
return ERR_FRAMING;
}
ISO_15693_DEBUG("SOF\n");
if(outBufLen == 0U) {
return ERR_NONE;
}
mp = 5; /* 5 bits were SOF, now manchester starts: 2 bits per payload bit */
bp = 0;
ST_MEMSET(outBuf, 0, outBufLen);
if(inBufLen == 0U) {
return ERR_CRC;
}
for(; mp < ((inBufLen * 8U) - 2U); mp += 2U) {
bool isEOF = false;
uint8_t man;
man = (inBuf[mp / 8U] >> (mp % 8U)) & 0x1U;
man |= ((inBuf[(mp + 1U) / 8U] >> ((mp + 1U) % 8U)) & 0x1U) << 1;
if(1U == man) {
bp++;
}
if(2U == man) {
outBuf[bp / 8U] = (uint8_t)(outBuf[bp / 8U] | (1U << (bp % 8U))); /* MISRA 10.3 */
bp++;
}
if((bp % 8U) == 0U) { /* Check for EOF */
ISO_15693_DEBUG("ceof %hhx %hhx\n", inBuf[mp / 8U], inBuf[mp / 8 + 1]);
if(((inBuf[mp / 8U] & 0xe0U) == 0xa0U) &&
(inBuf[(mp / 8U) + 1U] == 0x03U)) { /* Now we know that it was 10111000 = EOF */
ISO_15693_DEBUG("EOF\n");
isEOF = true;
}
}
if(((0U == man) || (3U == man)) && !isEOF) {
if(bp >= ignoreBits) {
err = ERR_RF_COLLISION;
} else {
/* ignored collision: leave as 0 */
bp++;
}
}
if((bp >= (outBufLen * 8U)) || (err == ERR_RF_COLLISION) ||
isEOF) { /* Don't write beyond the end */
break;
}
}
*outBufPos = (bp / 8U);
*bitsBeforeCol = bp;
if(err != ERR_NONE) {
return err;
}
if((bp % 8U) != 0U) {
return ERR_CRC;
}
if(*outBufPos > 2U) {
/* finally, check crc */
ISO_15693_DEBUG("Calculate CRC, val: 0x%x, outBufLen: ", *outBuf);
ISO_15693_DEBUG("0x%x ", *outBufPos - 2);
crc = rfalCrcCalculateCcitt(((picopassMode) ? 0xE012U : 0xFFFFU), outBuf, *outBufPos - 2U);
crc = (uint16_t)((picopassMode) ? crc : ~crc);
if(((crc & 0xffU) == outBuf[*outBufPos - 2U]) &&
(((crc >> 8U) & 0xffU) == outBuf[*outBufPos - 1U])) {
err = ERR_NONE;
ISO_15693_DEBUG("OK\n");
} else {
ISO_15693_DEBUG("error! Expected: 0x%x, got ", crc);
ISO_15693_DEBUG("0x%hhx 0x%hhx\n", outBuf[*outBufPos - 2], outBuf[*outBufPos - 1]);
err = ERR_CRC;
}
} else {
err = ERR_CRC;
}
return err;
}
/*
******************************************************************************
* LOCAL FUNCTIONS
******************************************************************************
*/
/*!
*****************************************************************************
* \brief Perform 1 of 4 coding and send coded data
*
* This function takes \a length bytes from \a buffer, perform 1 of 4 coding
* (see ISO15693-2 specification) and sends the data using stream mode.
*
* \param[in] sendSof : send SOF prior to data.
* \param[in] buffer : data to send.
* \param[in] length : number of bytes to send.
*
* \return ERR_IO : Error during communication.
* \return ERR_NONE : No error.
*
*****************************************************************************
*/
static ReturnCode iso15693PhyVCDCode1Of4(
const uint8_t data,
uint8_t* outbuffer,
uint16_t maxOutBufLen,
uint16_t* outBufLen) {
uint8_t tmp;
ReturnCode err = ERR_NONE;
uint16_t a;
uint8_t* outbuf = outbuffer;
*outBufLen = 0;
if(maxOutBufLen < 4U) {
return ERR_NOMEM;
}
tmp = data;
for(a = 0; a < 4U; a++) {
switch(tmp & 0x3U) {
case 0:
*outbuf = ISO15693_DAT_00_1_4;
break;
case 1:
*outbuf = ISO15693_DAT_01_1_4;
break;
case 2:
*outbuf = ISO15693_DAT_10_1_4;
break;
case 3:
*outbuf = ISO15693_DAT_11_1_4;
break;
default:
/* MISRA 16.4: mandatory default statement */
break;
}
outbuf++;
(*outBufLen)++;
tmp >>= 2;
}
return err;
}
/*!
*****************************************************************************
* \brief Perform 1 of 256 coding and send coded data
*
* This function takes \a length bytes from \a buffer, perform 1 of 256 coding
* (see ISO15693-2 specification) and sends the data using stream mode.
* \note This function sends SOF prior to the data.
*
* \param[in] sendSof : send SOF prior to data.
* \param[in] buffer : data to send.
* \param[in] length : number of bytes to send.
*
* \return ERR_IO : Error during communication.
* \return ERR_NONE : No error.
*
*****************************************************************************
*/
static ReturnCode iso15693PhyVCDCode1Of256(
const uint8_t data,
uint8_t* outbuffer,
uint16_t maxOutBufLen,
uint16_t* outBufLen) {
uint8_t tmp;
ReturnCode err = ERR_NONE;
uint16_t a;
uint8_t* outbuf = outbuffer;
*outBufLen = 0;
if(maxOutBufLen < 64U) {
return ERR_NOMEM;
}
tmp = data;
for(a = 0; a < 64U; a++) {
switch(tmp) {
case 0:
*outbuf = ISO15693_DAT_SLOT0_1_256;
break;
case 1:
*outbuf = ISO15693_DAT_SLOT1_1_256;
break;
case 2:
*outbuf = ISO15693_DAT_SLOT2_1_256;
break;
case 3:
*outbuf = ISO15693_DAT_SLOT3_1_256;
break;
default:
*outbuf = 0;
break;
}
outbuf++;
(*outBufLen)++;
tmp -= 4U;
}
return err;
}
#endif /* RFAL_FEATURE_NFCV */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-886
View File
@@ -1,886 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_nfca.c
*
* \author Gustavo Patricio
*
* \brief Provides several NFC-A convenience methods and definitions
*
* It provides a Poller (ISO14443A PCD) interface and as well as
* some NFC-A Listener (ISO14443A PICC) helpers.
*
* The definitions and helpers methods provided by this module are only
* up to ISO14443-3 layer
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "rfal_nfca.h"
#include "utils.h"
/*
******************************************************************************
* ENABLE SWITCH
******************************************************************************
*/
#ifndef RFAL_FEATURE_NFCA
#define RFAL_FEATURE_NFCA false /* NFC-A module configuration missing. Disabled by default */
#endif
#if RFAL_FEATURE_NFCA
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_NFCA_SLP_FWT \
rfalConvMsTo1fc(1) /*!< Check 1ms for any modulation ISO14443-3 6.4.3 */
#define RFAL_NFCA_SLP_CMD 0x50U /*!< SLP cmd (byte1) Digital 1.1 6.9.1 & Table 20 */
#define RFAL_NFCA_SLP_BYTE2 0x00U /*!< SLP byte2 Digital 1.1 6.9.1 & Table 20 */
#define RFAL_NFCA_SLP_CMD_POS 0U /*!< SLP cmd position Digital 1.1 6.9.1 & Table 20 */
#define RFAL_NFCA_SLP_BYTE2_POS 1U /*!< SLP byte2 position Digital 1.1 6.9.1 & Table 20 */
#define RFAL_NFCA_SDD_CT 0x88U /*!< Cascade Tag value Digital 1.1 6.7.2 */
#define RFAL_NFCA_SDD_CT_LEN 1U /*!< Cascade Tag length */
#define RFAL_NFCA_SLP_REQ_LEN 2U /*!< SLP_REQ length */
#define RFAL_NFCA_SEL_CMD_LEN 1U /*!< SEL_CMD length */
#define RFAL_NFCA_SEL_PAR_LEN 1U /*!< SEL_PAR length */
#define RFAL_NFCA_SEL_SELPAR \
rfalNfcaSelPar(7U, 0U) /*!< SEL_PAR on Select is always with 4 data/nfcid */
#define RFAL_NFCA_BCC_LEN 1U /*!< BCC length */
#define RFAL_NFCA_SDD_REQ_LEN \
(RFAL_NFCA_SEL_CMD_LEN + RFAL_NFCA_SEL_PAR_LEN) /*!< SDD_REQ length */
#define RFAL_NFCA_SDD_RES_LEN \
(RFAL_NFCA_CASCADE_1_UID_LEN + RFAL_NFCA_BCC_LEN) /*!< SDD_RES length */
#define RFAL_NFCA_T_RETRANS 5U /*!< t RETRANSMISSION [3, 33]ms EMVCo 2.6 A.5 */
#define RFAL_NFCA_N_RETRANS 2U /*!< Number of retries EMVCo 2.6 9.6.1.3 */
/*! SDD_REQ (Select) Cascade Levels */
enum {
RFAL_NFCA_SEL_CASCADE_L1 = 0, /*!< SDD_REQ Cascade Level 1 */
RFAL_NFCA_SEL_CASCADE_L2 = 1, /*!< SDD_REQ Cascade Level 2 */
RFAL_NFCA_SEL_CASCADE_L3 = 2 /*!< SDD_REQ Cascade Level 3 */
};
/*! SDD_REQ (Select) request Cascade Level command Digital 1.1 Table 15 */
enum {
RFAL_NFCA_CMD_SEL_CL1 = 0x93, /*!< SDD_REQ command Cascade Level 1 */
RFAL_NFCA_CMD_SEL_CL2 = 0x95, /*!< SDD_REQ command Cascade Level 2 */
RFAL_NFCA_CMD_SEL_CL3 = 0x97, /*!< SDD_REQ command Cascade Level 3 */
};
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
#define rfalNfcaSelPar(nBy, nbi) \
(uint8_t)( \
(((nBy) << 4U) & 0xF0U) | \
((nbi)&0x0FU)) /*!< Calculates SEL_PAR with the bytes/bits to be sent */
#define rfalNfcaCLn2SELCMD(cl) \
(uint8_t)( \
(uint8_t)(RFAL_NFCA_CMD_SEL_CL1) + \
(2U * (cl))) /*!< Calculates SEL_CMD with the given cascade level */
#define rfalNfcaNfcidLen2CL(len) \
((len) / 5U) /*!< Calculates cascade level by the NFCID length */
#define rfalNfcaRunBlocking(e, fn) \
do { \
(e) = (fn); \
rfalWorker(); \
} while((e) == ERR_BUSY) /*!< Macro used for the blocking methods */
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
/*! Colission Resolution states */
typedef enum {
RFAL_NFCA_CR_IDLE, /*!< IDLE state */
RFAL_NFCA_CR_CL, /*!< New Cascading Level state */
RFAL_NFCA_CR_SDD, /*!< Perform anticollsion state */
RFAL_NFCA_CR_SEL, /*!< Perform CL Selection state */
RFAL_NFCA_CR_DONE /*!< Collision Resolution done state */
} colResState;
/*! Colission Resolution context */
typedef struct {
uint8_t devLimit; /*!< Device limit to be used */
rfalComplianceMode compMode; /*!< Compliancy mode to be used */
rfalNfcaListenDevice*
nfcaDevList; /*!< Location of the device list */
uint8_t* devCnt; /*!< Location of the device counter */
bool collPending; /*!< Collision pending flag */
bool* collPend; /*!< Location of collision pending flag (Single CR) */
rfalNfcaSelReq selReq; /*!< SelReqused during anticollision (Single CR) */
rfalNfcaSelRes* selRes; /*!< Location to place of the SEL_RES(SAK) (Single CR) */
uint8_t* nfcId1; /*!< Location to place the NFCID1 (Single CR) */
uint8_t* nfcId1Len; /*!< Location to place the NFCID1 length (Single CR) */
uint8_t cascadeLv; /*!< Current Cascading Level (Single CR) */
colResState state; /*!< Single Collision Resolution state (Single CR) */
uint8_t bytesTxRx; /*!< TxRx bytes used during anticollision loop (Single CR) */
uint8_t bitsTxRx; /*!< TxRx bits used during anticollision loop (Single CR) */
uint16_t rxLen;
uint32_t tmrFDT; /*!< FDT timer used between SED_REQs (Single CR) */
uint8_t retries; /*!< Retries to be performed upon a timeout error (Single CR)*/
uint8_t backtrackCnt; /*!< Backtrack retries (Single CR) */
bool doBacktrack; /*!< Backtrack flag (Single CR) */
} colResParams;
/*! RFAL NFC-A instance */
typedef struct {
colResParams CR; /*!< Collision Resolution context */
} rfalNfca;
/*! SLP_REQ (HLTA) format Digital 1.1 6.9.1 & Table 20 */
typedef struct {
uint8_t frame[RFAL_NFCA_SLP_REQ_LEN]; /*!< SLP: 0x50 0x00 */
} rfalNfcaSlpReq;
/*
******************************************************************************
* LOCAL VARIABLES
******************************************************************************
*/
static rfalNfca gNfca; /*!< RFAL NFC-A instance */
/*
******************************************************************************
* LOCAL FUNCTION PROTOTYPES
******************************************************************************
*/
static uint8_t rfalNfcaCalculateBcc(const uint8_t* buf, uint8_t bufLen);
static ReturnCode rfalNfcaPollerStartSingleCollisionResolution(
uint8_t devLimit,
bool* collPending,
rfalNfcaSelRes* selRes,
uint8_t* nfcId1,
uint8_t* nfcId1Len);
static ReturnCode rfalNfcaPollerGetSingleCollisionResolutionStatus(void);
/*
******************************************************************************
* LOCAL FUNCTIONS
******************************************************************************
*/
static uint8_t rfalNfcaCalculateBcc(const uint8_t* buf, uint8_t bufLen) {
uint8_t i;
uint8_t BCC;
BCC = 0;
/* BCC is XOR over first 4 bytes of the SDD_RES Digital 1.1 6.7.2 */
for(i = 0; i < bufLen; i++) {
BCC ^= buf[i];
}
return BCC;
}
/*******************************************************************************/
static ReturnCode rfalNfcaPollerStartSingleCollisionResolution(
uint8_t devLimit,
bool* collPending,
rfalNfcaSelRes* selRes,
uint8_t* nfcId1,
uint8_t* nfcId1Len) {
/* Check parameters */
if((collPending == NULL) || (selRes == NULL) || (nfcId1 == NULL) || (nfcId1Len == NULL)) {
return ERR_PARAM;
}
/* Initialize output parameters */
*collPending = false; /* Activity 1.1 9.3.4.6 */
*nfcId1Len = 0;
ST_MEMSET(nfcId1, 0x00, RFAL_NFCA_CASCADE_3_UID_LEN);
/* Save parameters */
gNfca.CR.devLimit = devLimit;
gNfca.CR.collPend = collPending;
gNfca.CR.selRes = selRes;
gNfca.CR.nfcId1 = nfcId1;
gNfca.CR.nfcId1Len = nfcId1Len;
platformTimerDestroy(gNfca.CR.tmrFDT);
gNfca.CR.tmrFDT = 0U;
gNfca.CR.retries = RFAL_NFCA_N_RETRANS;
gNfca.CR.cascadeLv = (uint8_t)RFAL_NFCA_SEL_CASCADE_L1;
gNfca.CR.state = RFAL_NFCA_CR_CL;
gNfca.CR.doBacktrack = false;
gNfca.CR.backtrackCnt = 3U;
return ERR_NONE;
}
/*******************************************************************************/
static ReturnCode rfalNfcaPollerGetSingleCollisionResolutionStatus(void) {
ReturnCode ret;
uint8_t collBit = 1U; /* standards mandate or recommend collision bit to be set to One. */
/* Check if FDT timer is still running */
if(!platformTimerIsExpired(gNfca.CR.tmrFDT) && (gNfca.CR.tmrFDT != 0U)) {
return ERR_BUSY;
}
/*******************************************************************************/
/* Go through all Cascade Levels Activity 1.1 9.3.4 */
if(gNfca.CR.cascadeLv > (uint8_t)RFAL_NFCA_SEL_CASCADE_L3) {
return ERR_INTERNAL;
}
switch(gNfca.CR.state) {
/*******************************************************************************/
case RFAL_NFCA_CR_CL:
/* Initialize the SDD_REQ to send for the new cascade level */
ST_MEMSET((uint8_t*)&gNfca.CR.selReq, 0x00, sizeof(rfalNfcaSelReq));
gNfca.CR.bytesTxRx = RFAL_NFCA_SDD_REQ_LEN;
gNfca.CR.bitsTxRx = 0U;
gNfca.CR.state = RFAL_NFCA_CR_SDD;
/* fall through */
/*******************************************************************************/
case RFAL_NFCA_CR_SDD: /* PRQA S 2003 # MISRA 16.3 - Intentional fall through */
/* Calculate SEL_CMD and SEL_PAR with the bytes/bits to be sent */
gNfca.CR.selReq.selCmd = rfalNfcaCLn2SELCMD(gNfca.CR.cascadeLv);
gNfca.CR.selReq.selPar = rfalNfcaSelPar(gNfca.CR.bytesTxRx, gNfca.CR.bitsTxRx);
/* Send SDD_REQ (Anticollision frame) */
ret = rfalISO14443ATransceiveAnticollisionFrame(
(uint8_t*)&gNfca.CR.selReq,
&gNfca.CR.bytesTxRx,
&gNfca.CR.bitsTxRx,
&gNfca.CR.rxLen,
RFAL_NFCA_FDTMIN);
/* Retry upon timeout EMVCo 2.6 9.6.1.3 */
if((ret == ERR_TIMEOUT) && (gNfca.CR.devLimit == 0U) && (gNfca.CR.retries != 0U)) {
gNfca.CR.retries--;
platformTimerDestroy(gNfca.CR.tmrFDT);
gNfca.CR.tmrFDT = platformTimerCreate(RFAL_NFCA_T_RETRANS);
break;
}
/* Covert rxLen into bytes */
gNfca.CR.rxLen = rfalConvBitsToBytes(gNfca.CR.rxLen);
if((ret == ERR_TIMEOUT) && (gNfca.CR.backtrackCnt != 0U) && (!gNfca.CR.doBacktrack) &&
!((RFAL_NFCA_SDD_REQ_LEN == gNfca.CR.bytesTxRx) && (0U == gNfca.CR.bitsTxRx))) {
/* In multiple card scenarios it may always happen that some
* collisions of a weaker tag go unnoticed. If then a later
* collision is recognized and the strong tag has a 0 at the
* collision position then no tag will respond. Catch this
* corner case and then try with the bit being sent as zero. */
rfalNfcaSensRes sensRes;
ret = ERR_RF_COLLISION;
rfalNfcaPollerCheckPresence(RFAL_14443A_SHORTFRAME_CMD_REQA, &sensRes);
/* Algorithm below does a post-increment, decrement to go back to current position */
if(0U == gNfca.CR.bitsTxRx) {
gNfca.CR.bitsTxRx = 7;
gNfca.CR.bytesTxRx--;
} else {
gNfca.CR.bitsTxRx--;
}
collBit =
(uint8_t)(((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] & (1U << gNfca.CR.bitsTxRx));
collBit = (uint8_t)((0U == collBit) ? 1U : 0U); // invert the collision bit
gNfca.CR.doBacktrack = true;
gNfca.CR.backtrackCnt--;
} else {
gNfca.CR.doBacktrack = false;
}
if(ret == ERR_RF_COLLISION) {
/* Check received length */
if((gNfca.CR.bytesTxRx + ((gNfca.CR.bitsTxRx != 0U) ? 1U : 0U)) >
(RFAL_NFCA_SDD_RES_LEN + RFAL_NFCA_SDD_REQ_LEN)) {
return ERR_PROTO;
}
if(((gNfca.CR.bytesTxRx + ((gNfca.CR.bitsTxRx != 0U) ? 1U : 0U)) >
(RFAL_NFCA_CASCADE_1_UID_LEN + RFAL_NFCA_SDD_REQ_LEN)) &&
(gNfca.CR.backtrackCnt != 0U)) { /* Collision in BCC: Anticollide only UID part */
gNfca.CR.backtrackCnt--;
gNfca.CR.bytesTxRx = RFAL_NFCA_CASCADE_1_UID_LEN + RFAL_NFCA_SDD_REQ_LEN - 1U;
gNfca.CR.bitsTxRx = 7;
collBit =
(uint8_t)(((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] & (1U << gNfca.CR.bitsTxRx)); /* Not a real collision, extract the actual bit for the subsequent code */
}
if((gNfca.CR.devLimit == 0U) && !(*gNfca.CR.collPend)) {
/* Activity 1.0 & 1.1 9.3.4.12: If CON_DEVICES_LIMIT has a value of 0, then
* NFC Forum Device is configured to perform collision detection only */
*gNfca.CR.collPend = true;
return ERR_IGNORE;
}
*gNfca.CR.collPend = true;
/* Set and select the collision bit, with the number of bytes/bits successfully TxRx */
if(collBit != 0U) {
((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] =
(uint8_t)(((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] | (1U << gNfca.CR.bitsTxRx)); /* MISRA 10.3 */
} else {
((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] =
(uint8_t)(((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] & ~(1U << gNfca.CR.bitsTxRx)); /* MISRA 10.3 */
}
gNfca.CR.bitsTxRx++;
/* Check if number of bits form a byte */
if(gNfca.CR.bitsTxRx == RFAL_BITS_IN_BYTE) {
gNfca.CR.bitsTxRx = 0;
gNfca.CR.bytesTxRx++;
}
break;
}
/*******************************************************************************/
/* Check if Collision loop has failed */
if(ret != ERR_NONE) {
return ret;
}
/* If collisions are to be reported check whether the response is complete */
if((gNfca.CR.devLimit == 0U) && (gNfca.CR.rxLen != sizeof(rfalNfcaSddRes))) {
return ERR_PROTO;
}
/* Check if the received BCC match */
if(gNfca.CR.selReq.bcc !=
rfalNfcaCalculateBcc(gNfca.CR.selReq.nfcid1, RFAL_NFCA_CASCADE_1_UID_LEN)) {
return ERR_PROTO;
}
/*******************************************************************************/
/* Anticollision OK, Select this Cascade Level */
gNfca.CR.selReq.selPar = RFAL_NFCA_SEL_SELPAR;
gNfca.CR.retries = RFAL_NFCA_N_RETRANS;
gNfca.CR.state = RFAL_NFCA_CR_SEL;
break;
/*******************************************************************************/
case RFAL_NFCA_CR_SEL:
/* Send SEL_REQ (Select command) - Retry upon timeout EMVCo 2.6 9.6.1.3 */
ret = rfalTransceiveBlockingTxRx(
(uint8_t*)&gNfca.CR.selReq,
sizeof(rfalNfcaSelReq),
(uint8_t*)gNfca.CR.selRes,
sizeof(rfalNfcaSelRes),
&gNfca.CR.rxLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_NFCA_FDTMIN);
/* Retry upon timeout EMVCo 2.6 9.6.1.3 */
if((ret == ERR_TIMEOUT) && (gNfca.CR.devLimit == 0U) && (gNfca.CR.retries != 0U)) {
gNfca.CR.retries--;
platformTimerDestroy(gNfca.CR.tmrFDT);
gNfca.CR.tmrFDT = platformTimerCreate(RFAL_NFCA_T_RETRANS);
break;
}
if(ret != ERR_NONE) {
return ret;
}
/* Ensure proper response length */
if(gNfca.CR.rxLen != sizeof(rfalNfcaSelRes)) {
return ERR_PROTO;
}
/*******************************************************************************/
/* Check cascade byte, if cascade tag then go next cascade level */
if(*gNfca.CR.selReq.nfcid1 == RFAL_NFCA_SDD_CT) {
/* Cascade Tag present, store nfcid1 bytes (excluding cascade tag) and continue for next CL */
ST_MEMCPY(
&gNfca.CR.nfcId1[*gNfca.CR.nfcId1Len],
&((uint8_t*)&gNfca.CR.selReq.nfcid1)[RFAL_NFCA_SDD_CT_LEN],
(RFAL_NFCA_CASCADE_1_UID_LEN - RFAL_NFCA_SDD_CT_LEN));
*gNfca.CR.nfcId1Len += (RFAL_NFCA_CASCADE_1_UID_LEN - RFAL_NFCA_SDD_CT_LEN);
/* Go to next cascade level */
gNfca.CR.state = RFAL_NFCA_CR_CL;
gNfca.CR.cascadeLv++;
} else {
/* UID Selection complete, Stop Cascade Level loop */
ST_MEMCPY(
&gNfca.CR.nfcId1[*gNfca.CR.nfcId1Len],
(uint8_t*)&gNfca.CR.selReq.nfcid1,
RFAL_NFCA_CASCADE_1_UID_LEN);
*gNfca.CR.nfcId1Len += RFAL_NFCA_CASCADE_1_UID_LEN;
gNfca.CR.state = RFAL_NFCA_CR_DONE;
break; /* Only flag operation complete on the next execution */
}
break;
/*******************************************************************************/
case RFAL_NFCA_CR_DONE:
return ERR_NONE;
/*******************************************************************************/
default:
return ERR_WRONG_STATE;
}
return ERR_BUSY;
}
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
/*******************************************************************************/
ReturnCode rfalNfcaPollerInitialize(void) {
ReturnCode ret;
EXIT_ON_ERR(ret, rfalSetMode(RFAL_MODE_POLL_NFCA, RFAL_BR_106, RFAL_BR_106));
rfalSetErrorHandling(RFAL_ERRORHANDLING_NFC);
rfalSetGT(RFAL_GT_NFCA);
rfalSetFDTListen(RFAL_FDT_LISTEN_NFCA_POLLER);
rfalSetFDTPoll(RFAL_FDT_POLL_NFCA_POLLER);
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode rfalNfcaPollerCheckPresence(rfal14443AShortFrameCmd cmd, rfalNfcaSensRes* sensRes) {
ReturnCode ret;
uint16_t rcvLen;
/* Digital 1.1 6.10.1.3 For Commands ALL_REQ, SENS_REQ, SDD_REQ, and SEL_REQ, the NFC Forum Device *
* MUST treat receipt of a Listen Frame at a time after FDT(Listen, min) as a Timeour Error */
ret = rfalISO14443ATransceiveShortFrame(
cmd,
(uint8_t*)sensRes,
(uint8_t)rfalConvBytesToBits(sizeof(rfalNfcaSensRes)),
&rcvLen,
RFAL_NFCA_FDTMIN);
if((ret == ERR_RF_COLLISION) || (ret == ERR_CRC) || (ret == ERR_NOMEM) ||
(ret == ERR_FRAMING) || (ret == ERR_PAR)) {
ret = ERR_NONE;
}
return ret;
}
/*******************************************************************************/
ReturnCode
rfalNfcaPollerTechnologyDetection(rfalComplianceMode compMode, rfalNfcaSensRes* sensRes) {
ReturnCode ret;
EXIT_ON_ERR(
ret,
rfalNfcaPollerCheckPresence(
((compMode == RFAL_COMPLIANCE_MODE_EMV) ? RFAL_14443A_SHORTFRAME_CMD_WUPA :
RFAL_14443A_SHORTFRAME_CMD_REQA),
sensRes));
/* Send SLP_REQ as Activity 1.1 9.2.3.6 and EMVCo 2.6 9.2.1.3 */
if(compMode != RFAL_COMPLIANCE_MODE_ISO) {
rfalNfcaPollerSleep();
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode rfalNfcaPollerSingleCollisionResolution(
uint8_t devLimit,
bool* collPending,
rfalNfcaSelRes* selRes,
uint8_t* nfcId1,
uint8_t* nfcId1Len) {
ReturnCode ret;
EXIT_ON_ERR(
ret,
rfalNfcaPollerStartSingleCollisionResolution(
devLimit, collPending, selRes, nfcId1, nfcId1Len));
rfalNfcaRunBlocking(ret, rfalNfcaPollerGetSingleCollisionResolutionStatus());
return ret;
}
/*******************************************************************************/
ReturnCode rfalNfcaPollerStartFullCollisionResolution(
rfalComplianceMode compMode,
uint8_t devLimit,
rfalNfcaListenDevice* nfcaDevList,
uint8_t* devCnt) {
ReturnCode ret;
rfalNfcaSensRes sensRes;
uint16_t rcvLen;
if((nfcaDevList == NULL) || (devCnt == NULL)) {
return ERR_PARAM;
}
*devCnt = 0;
ret = ERR_NONE;
/*******************************************************************************/
/* Send ALL_REQ before Anticollision if a Sleep was sent before Activity 1.1 9.3.4.1 and EMVco 2.6 9.3.2.1 */
if(compMode != RFAL_COMPLIANCE_MODE_ISO) {
ret = rfalISO14443ATransceiveShortFrame(
RFAL_14443A_SHORTFRAME_CMD_WUPA,
(uint8_t*)&nfcaDevList->sensRes,
(uint8_t)rfalConvBytesToBits(sizeof(rfalNfcaSensRes)),
&rcvLen,
RFAL_NFCA_FDTMIN);
if(ret != ERR_NONE) {
if((compMode == RFAL_COMPLIANCE_MODE_EMV) ||
((ret != ERR_RF_COLLISION) && (ret != ERR_CRC) && (ret != ERR_FRAMING) &&
(ret != ERR_PAR))) {
return ret;
}
}
/* Check proper SENS_RES/ATQA size */
if((ret == ERR_NONE) && (rfalConvBytesToBits(sizeof(rfalNfcaSensRes)) != rcvLen)) {
return ERR_PROTO;
}
}
/*******************************************************************************/
/* Store the SENS_RES from Technology Detection or from WUPA */
sensRes = nfcaDevList->sensRes;
if(devLimit > 0U) /* MISRA 21.18 */
{
ST_MEMSET(nfcaDevList, 0x00, (sizeof(rfalNfcaListenDevice) * devLimit));
}
/* Restore the prev SENS_RES, assuming that the SENS_RES received is from first device
* When only one device is detected it's not woken up then we'll have no SENS_RES (ATQA) */
nfcaDevList->sensRes = sensRes;
/* Save parameters */
gNfca.CR.devCnt = devCnt;
gNfca.CR.devLimit = devLimit;
gNfca.CR.nfcaDevList = nfcaDevList;
gNfca.CR.compMode = compMode;
#if RFAL_FEATURE_T1T
/*******************************************************************************/
/* Only check for T1T if previous SENS_RES was received without a transmission *
* error. When collisions occur bits in the SENS_RES may look like a T1T */
/* If T1T Anticollision is not supported Activity 1.1 9.3.4.3 */
if(rfalNfcaIsSensResT1T(&nfcaDevList->sensRes) && (devLimit != 0U) && (ret == ERR_NONE) &&
(compMode != RFAL_COMPLIANCE_MODE_EMV)) {
/* RID_REQ shall be performed Activity 1.1 9.3.4.24 */
rfalT1TPollerInitialize();
EXIT_ON_ERR(ret, rfalT1TPollerRid(&nfcaDevList->ridRes));
*devCnt = 1U;
nfcaDevList->isSleep = false;
nfcaDevList->type = RFAL_NFCA_T1T;
nfcaDevList->nfcId1Len = RFAL_NFCA_CASCADE_1_UID_LEN;
ST_MEMCPY(&nfcaDevList->nfcId1, &nfcaDevList->ridRes.uid, RFAL_NFCA_CASCADE_1_UID_LEN);
return ERR_NONE;
}
#endif /* RFAL_FEATURE_T1T */
return rfalNfcaPollerStartSingleCollisionResolution(
devLimit,
&gNfca.CR.collPending,
&nfcaDevList->selRes,
(uint8_t*)&nfcaDevList->nfcId1,
&nfcaDevList->nfcId1Len);
}
/*******************************************************************************/
ReturnCode rfalNfcaPollerGetFullCollisionResolutionStatus(void) {
ReturnCode ret;
uint8_t newDevType;
if((gNfca.CR.nfcaDevList == NULL) || (gNfca.CR.devCnt == NULL)) {
return ERR_WRONG_STATE;
}
/*******************************************************************************/
/* Check whether a T1T has already been detected */
if(rfalNfcaIsSensResT1T(&gNfca.CR.nfcaDevList->sensRes) &&
(gNfca.CR.nfcaDevList->type == RFAL_NFCA_T1T)) {
/* T1T doesn't support Anticollision */
return ERR_NONE;
}
/*******************************************************************************/
EXIT_ON_ERR(ret, rfalNfcaPollerGetSingleCollisionResolutionStatus());
/* Assign Listen Device */
newDevType = ((uint8_t)gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].selRes.sak) &
RFAL_NFCA_SEL_RES_CONF_MASK; /* MISRA 10.8 */
/* PRQA S 4342 1 # MISRA 10.5 - Guaranteed that no invalid enum values are created: see guard_eq_RFAL_NFCA_T2T, .... */
gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].type = (rfalNfcaListenDeviceType)newDevType;
gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].isSleep = false;
(*gNfca.CR.devCnt)++;
/* If a collision was detected and device counter is lower than limit Activity 1.1 9.3.4.21 */
if((*gNfca.CR.devCnt < gNfca.CR.devLimit) && (gNfca.CR.collPending)) {
/* Put this device to Sleep Activity 1.1 9.3.4.22 */
rfalNfcaPollerSleep();
gNfca.CR.nfcaDevList[(*gNfca.CR.devCnt - 1U)].isSleep = true;
/* Send a new SENS_REQ to check for other cards Activity 1.1 9.3.4.23 */
ret = rfalNfcaPollerCheckPresence(
RFAL_14443A_SHORTFRAME_CMD_REQA, &gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].sensRes);
if(ret == ERR_TIMEOUT) {
/* No more devices found, exit */
gNfca.CR.collPending = false;
} else {
/* Another device found, continue loop */
gNfca.CR.collPending = true;
}
} else {
/* Exit loop */
gNfca.CR.collPending = false;
}
/*******************************************************************************/
/* Check if collision resolution shall continue */
if((*gNfca.CR.devCnt < gNfca.CR.devLimit) && (gNfca.CR.collPending)) {
EXIT_ON_ERR(
ret,
rfalNfcaPollerStartSingleCollisionResolution(
gNfca.CR.devLimit,
&gNfca.CR.collPending,
&gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].selRes,
(uint8_t*)&gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].nfcId1,
&gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].nfcId1Len));
return ERR_BUSY;
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode rfalNfcaPollerFullCollisionResolution(
rfalComplianceMode compMode,
uint8_t devLimit,
rfalNfcaListenDevice* nfcaDevList,
uint8_t* devCnt) {
ReturnCode ret;
EXIT_ON_ERR(
ret, rfalNfcaPollerStartFullCollisionResolution(compMode, devLimit, nfcaDevList, devCnt));
rfalNfcaRunBlocking(ret, rfalNfcaPollerGetFullCollisionResolutionStatus());
return ret;
}
ReturnCode rfalNfcaPollerSleepFullCollisionResolution(
uint8_t devLimit,
rfalNfcaListenDevice* nfcaDevList,
uint8_t* devCnt) {
bool firstRound;
uint8_t tmpDevCnt;
ReturnCode ret;
if((nfcaDevList == NULL) || (devCnt == NULL)) {
return ERR_PARAM;
}
/* Only use ALL_REQ (WUPA) on the first round */
firstRound = true;
*devCnt = 0;
/* Perform collision resolution until no new device is found */
do {
tmpDevCnt = 0;
ret = rfalNfcaPollerFullCollisionResolution(
(firstRound ? RFAL_COMPLIANCE_MODE_NFC : RFAL_COMPLIANCE_MODE_ISO),
(devLimit - *devCnt),
&nfcaDevList[*devCnt],
&tmpDevCnt);
if((ret == ERR_NONE) && (tmpDevCnt > 0U)) {
*devCnt += tmpDevCnt;
/* Check whether to seacrh for more devices */
if(*devCnt < devLimit) {
/* Set last found device to sleep (all others are slept already) */
rfalNfcaPollerSleep();
nfcaDevList[((*devCnt) - 1U)].isSleep = true;
/* Check if any other device is present */
ret = rfalNfcaPollerCheckPresence(
RFAL_14443A_SHORTFRAME_CMD_REQA, &nfcaDevList[*devCnt].sensRes);
if(ret == ERR_NONE) {
firstRound = false;
continue;
}
}
}
break;
} while(true);
return ((*devCnt > 0U) ? ERR_NONE : ret);
}
/*******************************************************************************/
ReturnCode rfalNfcaPollerSelect(const uint8_t* nfcid1, uint8_t nfcidLen, rfalNfcaSelRes* selRes) {
uint8_t i;
uint8_t cl;
uint8_t nfcidOffset;
uint16_t rxLen;
ReturnCode ret;
rfalNfcaSelReq selReq;
if((nfcid1 == NULL) || (nfcidLen > RFAL_NFCA_CASCADE_3_UID_LEN) || (selRes == NULL)) {
return ERR_PARAM;
}
/* Calculate Cascate Level */
cl = rfalNfcaNfcidLen2CL(nfcidLen);
nfcidOffset = 0;
/*******************************************************************************/
/* Go through all Cascade Levels Activity 1.1 9.4.4 */
for(i = RFAL_NFCA_SEL_CASCADE_L1; i <= cl; i++) {
/* Assign SEL_CMD according to the CLn and SEL_PAR*/
selReq.selCmd = rfalNfcaCLn2SELCMD(i);
selReq.selPar = RFAL_NFCA_SEL_SELPAR;
/* Compute NFCID/Data on the SEL_REQ command Digital 1.1 Table 18 */
if(cl != i) {
*selReq.nfcid1 = RFAL_NFCA_SDD_CT;
ST_MEMCPY(
&selReq.nfcid1[RFAL_NFCA_SDD_CT_LEN],
&nfcid1[nfcidOffset],
(RFAL_NFCA_CASCADE_1_UID_LEN - RFAL_NFCA_SDD_CT_LEN));
nfcidOffset += (RFAL_NFCA_CASCADE_1_UID_LEN - RFAL_NFCA_SDD_CT_LEN);
} else {
ST_MEMCPY(selReq.nfcid1, &nfcid1[nfcidOffset], RFAL_NFCA_CASCADE_1_UID_LEN);
}
/* Calculate nfcid's BCC */
selReq.bcc = rfalNfcaCalculateBcc((uint8_t*)&selReq.nfcid1, sizeof(selReq.nfcid1));
/*******************************************************************************/
/* Send SEL_REQ */
EXIT_ON_ERR(
ret,
rfalTransceiveBlockingTxRx(
(uint8_t*)&selReq,
sizeof(rfalNfcaSelReq),
(uint8_t*)selRes,
sizeof(rfalNfcaSelRes),
&rxLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_NFCA_FDTMIN));
/* Ensure proper response length */
if(rxLen != sizeof(rfalNfcaSelRes)) {
return ERR_PROTO;
}
}
/* REMARK: Could check if NFCID1 is complete */
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode rfalNfcaPollerSleep(void) {
rfalNfcaSlpReq slpReq;
uint8_t rxBuf; /* dummy buffer, just to perform Rx */
slpReq.frame[RFAL_NFCA_SLP_CMD_POS] = RFAL_NFCA_SLP_CMD;
slpReq.frame[RFAL_NFCA_SLP_BYTE2_POS] = RFAL_NFCA_SLP_BYTE2;
rfalTransceiveBlockingTxRx(
(uint8_t*)&slpReq,
sizeof(rfalNfcaSlpReq),
&rxBuf,
sizeof(rxBuf),
NULL,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_NFCA_SLP_FWT);
/* ISO14443-3 6.4.3 HLTA - If PICC responds with any modulation during 1 ms this response shall be interpreted as not acknowledge
Digital 2.0 6.9.2.1 & EMVCo 3.0 5.6.2.1 - consider the HLTA command always acknowledged
No check to be compliant with NFC and EMVCo, and to improve interoprability (Kovio RFID Tag)
*/
return ERR_NONE;
}
/*******************************************************************************/
bool rfalNfcaListenerIsSleepReq(const uint8_t* buf, uint16_t bufLen) {
/* Check if length and payload match */
if((bufLen != sizeof(rfalNfcaSlpReq)) || (buf[RFAL_NFCA_SLP_CMD_POS] != RFAL_NFCA_SLP_CMD) ||
(buf[RFAL_NFCA_SLP_BYTE2_POS] != RFAL_NFCA_SLP_BYTE2)) {
return false;
}
return true;
}
/* If the guards here don't compile then the code above cannot work anymore. */
extern uint8_t guard_eq_RFAL_NFCA_T2T
[((RFAL_NFCA_SEL_RES_CONF_MASK & (uint8_t)RFAL_NFCA_T2T) == (uint8_t)RFAL_NFCA_T2T) ? 1 : (-1)];
extern uint8_t guard_eq_RFAL_NFCA_T4T
[((RFAL_NFCA_SEL_RES_CONF_MASK & (uint8_t)RFAL_NFCA_T4T) == (uint8_t)RFAL_NFCA_T4T) ? 1 : (-1)];
extern uint8_t guard_eq_RFAL_NFCA_NFCDEP
[((RFAL_NFCA_SEL_RES_CONF_MASK & (uint8_t)RFAL_NFCA_NFCDEP) == (uint8_t)RFAL_NFCA_NFCDEP) ?
1 :
(-1)];
extern uint8_t guard_eq_RFAL_NFCA_T4T_NFCDEP
[((RFAL_NFCA_SEL_RES_CONF_MASK & (uint8_t)RFAL_NFCA_T4T_NFCDEP) ==
(uint8_t)RFAL_NFCA_T4T_NFCDEP) ?
1 :
(-1)];
#endif /* RFAL_FEATURE_NFCA */
-519
View File
@@ -1,519 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_nfcb.c
*
* \author Gustavo Patricio
*
* \brief Implementation of NFC-B (ISO14443B) helpers
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "rfal_nfcb.h"
#include "utils.h"
/*
******************************************************************************
* ENABLE SWITCH
******************************************************************************
*/
#ifndef RFAL_FEATURE_NFCB
#define RFAL_FEATURE_NFCB false /* NFC-B module configuration missing. Disabled by default */
#endif
#if RFAL_FEATURE_NFCB
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_NFCB_SENSB_REQ_EXT_SENSB_RES_SUPPORTED \
0x10U /*!< Bit mask for Extended SensB Response support in SENSB_REQ */
#define RFAL_NFCB_SENSB_RES_PROT_TYPE_RFU \
0x08U /*!< Bit mask for Protocol Type RFU in SENSB_RES */
#define RFAL_NFCB_SLOT_MARKER_SC_SHIFT \
4U /*!< Slot Code position on SLOT_MARKER APn */
#define RFAL_NFCB_SLOTMARKER_SLOTCODE_MIN \
1U /*!< SLOT_MARKER Slot Code minimum Digital 1.1 Table 37 */
#define RFAL_NFCB_SLOTMARKER_SLOTCODE_MAX \
16U /*!< SLOT_MARKER Slot Code maximum Digital 1.1 Table 37 */
#define RFAL_NFCB_ACTIVATION_FWT \
(RFAL_NFCB_FWTSENSB + RFAL_NFCB_DTPOLL_20) /*!< FWT(SENSB) + dTbPoll Digital 2.0 7.9.1.3 */
/*! Advanced and Extended bit mask in Parameter of SENSB_REQ */
#define RFAL_NFCB_SENSB_REQ_PARAM \
(RFAL_NFCB_SENSB_REQ_ADV_FEATURE | RFAL_NFCB_SENSB_REQ_EXT_SENSB_RES_SUPPORTED)
/*! NFC-B commands definition */
enum {
RFAL_NFCB_CMD_SENSB_REQ = 0x05, /*!< SENSB_REQ (REQB) & SLOT_MARKER Digital 1.1 Table 24 */
RFAL_NFCB_CMD_SENSB_RES = 0x50, /*!< SENSB_RES (ATQB) & SLOT_MARKER Digital 1.1 Table 27 */
RFAL_NFCB_CMD_SLPB_REQ = 0x50, /*!< SLPB_REQ (HLTB command) Digital 1.1 Table 38 */
RFAL_NFCB_CMD_SLPB_RES = 0x00 /*!< SLPB_RES (HLTB Answer) Digital 1.1 Table 39 */
};
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
#define rfalNfcbNI2NumberOfSlots(ni) \
(uint8_t)(1U << (ni)) /*!< Converts the Number of slots Identifier to slot number */
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
/*! ALLB_REQ (WUPB) and SENSB_REQ (REQB) Command Format Digital 1.1 7.6.1 */
typedef struct {
uint8_t cmd; /*!< xxxxB_REQ: 05h */
uint8_t AFI; /*!< NFC Identifier */
uint8_t PARAM; /*!< Application Data */
} rfalNfcbSensbReq;
/*! SLOT_MARKER Command format Digital 1.1 7.7.1 */
typedef struct {
uint8_t APn; /*!< Slot number 2..16 | 0101b */
} rfalNfcbSlotMarker;
/*! SLPB_REQ (HLTB) Command Format Digital 1.1 7.8.1 */
typedef struct {
uint8_t cmd; /*!< SLPB_REQ: 50h */
uint8_t nfcid0[RFAL_NFCB_NFCID0_LEN]; /*!< NFC Identifier (PUPI)*/
} rfalNfcbSlpbReq;
/*! SLPB_RES (HLTB) Response Format Digital 1.1 7.8.2 */
typedef struct {
uint8_t cmd; /*!< SLPB_RES: 00h */
} rfalNfcbSlpbRes;
/*! RFAL NFC-B instance */
typedef struct {
uint8_t AFI; /*!< AFI to be used */
uint8_t PARAM; /*!< PARAM to be used */
} rfalNfcb;
/*
******************************************************************************
* LOCAL FUNCTION PROTOTYPES
******************************************************************************
*/
static ReturnCode rfalNfcbCheckSensbRes(const rfalNfcbSensbRes* sensbRes, uint8_t sensbResLen);
/*
******************************************************************************
* LOCAL VARIABLES
******************************************************************************
*/
static rfalNfcb gRfalNfcb; /*!< RFAL NFC-B Instance */
/*
******************************************************************************
* LOCAL FUNCTIONS
******************************************************************************
*/
/*******************************************************************************/
static ReturnCode rfalNfcbCheckSensbRes(const rfalNfcbSensbRes* sensbRes, uint8_t sensbResLen) {
/* Check response length */
if(((sensbResLen != RFAL_NFCB_SENSB_RES_LEN) &&
(sensbResLen != RFAL_NFCB_SENSB_RES_EXT_LEN))) {
return ERR_PROTO;
}
/* Check SENSB_RES and Protocol Type Digital 1.1 7.6.2.19 */
if(((sensbRes->protInfo.FsciProType & RFAL_NFCB_SENSB_RES_PROT_TYPE_RFU) != 0U) ||
(sensbRes->cmd != (uint8_t)RFAL_NFCB_CMD_SENSB_RES)) {
return ERR_PROTO;
}
return ERR_NONE;
}
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
/*******************************************************************************/
ReturnCode rfalNfcbPollerInitialize(void) {
ReturnCode ret;
EXIT_ON_ERR(ret, rfalSetMode(RFAL_MODE_POLL_NFCB, RFAL_BR_106, RFAL_BR_106));
rfalSetErrorHandling(RFAL_ERRORHANDLING_NFC);
rfalSetGT(RFAL_GT_NFCB);
rfalSetFDTListen(RFAL_FDT_LISTEN_NFCB_POLLER);
rfalSetFDTPoll(RFAL_FDT_POLL_NFCB_POLLER);
gRfalNfcb.AFI = RFAL_NFCB_AFI;
gRfalNfcb.PARAM = RFAL_NFCB_PARAM;
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode rfalNfcbPollerInitializeWithParams(uint8_t AFI, uint8_t PARAM) {
ReturnCode ret;
EXIT_ON_ERR(ret, rfalNfcbPollerInitialize());
gRfalNfcb.AFI = AFI;
gRfalNfcb.PARAM = (PARAM & RFAL_NFCB_SENSB_REQ_PARAM);
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode rfalNfcbPollerCheckPresence(
rfalNfcbSensCmd cmd,
rfalNfcbSlots slots,
rfalNfcbSensbRes* sensbRes,
uint8_t* sensbResLen) {
uint16_t rxLen;
ReturnCode ret;
rfalNfcbSensbReq sensbReq;
/* Check if the command requested and given the slot number are valid */
if(((RFAL_NFCB_SENS_CMD_SENSB_REQ != cmd) && (RFAL_NFCB_SENS_CMD_ALLB_REQ != cmd)) ||
(slots > RFAL_NFCB_SLOT_NUM_16) || (sensbRes == NULL) || (sensbResLen == NULL)) {
return ERR_PARAM;
}
*sensbResLen = 0;
ST_MEMSET(sensbRes, 0x00, sizeof(rfalNfcbSensbRes));
/* Compute SENSB_REQ */
sensbReq.cmd = RFAL_NFCB_CMD_SENSB_REQ;
sensbReq.AFI = gRfalNfcb.AFI;
sensbReq.PARAM =
(((uint8_t)gRfalNfcb.PARAM & RFAL_NFCB_SENSB_REQ_PARAM) | (uint8_t)cmd | (uint8_t)slots);
/* Send SENSB_REQ and disable AGC to detect collisions */
ret = rfalTransceiveBlockingTxRx(
(uint8_t*)&sensbReq,
sizeof(rfalNfcbSensbReq),
(uint8_t*)sensbRes,
sizeof(rfalNfcbSensbRes),
&rxLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_NFCB_FWTSENSB);
*sensbResLen = (uint8_t)rxLen;
/* Check if a transmission error was detected */
if((ret == ERR_CRC) || (ret == ERR_FRAMING)) {
/* Invalidate received frame as an error was detected (CollisionResolution checks if valid) */
*sensbResLen = 0;
return ERR_NONE;
}
if(ret == ERR_NONE) {
return rfalNfcbCheckSensbRes(sensbRes, *sensbResLen);
}
return ret;
}
/*******************************************************************************/
ReturnCode rfalNfcbPollerSleep(const uint8_t* nfcid0) {
uint16_t rxLen;
ReturnCode ret;
rfalNfcbSlpbReq slpbReq;
rfalNfcbSlpbRes slpbRes;
if(nfcid0 == NULL) {
return ERR_PARAM;
}
/* Compute SLPB_REQ */
slpbReq.cmd = RFAL_NFCB_CMD_SLPB_REQ;
ST_MEMCPY(slpbReq.nfcid0, nfcid0, RFAL_NFCB_NFCID0_LEN);
EXIT_ON_ERR(
ret,
rfalTransceiveBlockingTxRx(
(uint8_t*)&slpbReq,
sizeof(rfalNfcbSlpbReq),
(uint8_t*)&slpbRes,
sizeof(rfalNfcbSlpbRes),
&rxLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_NFCB_ACTIVATION_FWT));
/* Check SLPB_RES */
if((rxLen != sizeof(rfalNfcbSlpbRes)) || (slpbRes.cmd != (uint8_t)RFAL_NFCB_CMD_SLPB_RES)) {
return ERR_PROTO;
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode
rfalNfcbPollerSlotMarker(uint8_t slotCode, rfalNfcbSensbRes* sensbRes, uint8_t* sensbResLen) {
ReturnCode ret;
rfalNfcbSlotMarker slotMarker;
uint16_t rxLen;
/* Check parameters */
if((sensbRes == NULL) || (sensbResLen == NULL) ||
(slotCode < RFAL_NFCB_SLOTMARKER_SLOTCODE_MIN) ||
(slotCode > RFAL_NFCB_SLOTMARKER_SLOTCODE_MAX)) {
return ERR_PARAM;
}
/* Compose and send SLOT_MARKER with disabled AGC to detect collisions */
slotMarker.APn =
((slotCode << RFAL_NFCB_SLOT_MARKER_SC_SHIFT) | (uint8_t)RFAL_NFCB_CMD_SENSB_REQ);
ret = rfalTransceiveBlockingTxRx(
(uint8_t*)&slotMarker,
sizeof(rfalNfcbSlotMarker),
(uint8_t*)sensbRes,
sizeof(rfalNfcbSensbRes),
&rxLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_NFCB_ACTIVATION_FWT);
*sensbResLen = (uint8_t)rxLen;
/* Check if a transmission error was detected */
if((ret == ERR_CRC) || (ret == ERR_FRAMING)) {
return ERR_RF_COLLISION;
}
if(ret == ERR_NONE) {
return rfalNfcbCheckSensbRes(sensbRes, *sensbResLen);
}
return ret;
}
ReturnCode rfalNfcbPollerTechnologyDetection(
rfalComplianceMode compMode,
rfalNfcbSensbRes* sensbRes,
uint8_t* sensbResLen) {
NO_WARNING(compMode);
return rfalNfcbPollerCheckPresence(
RFAL_NFCB_SENS_CMD_SENSB_REQ, RFAL_NFCB_SLOT_NUM_1, sensbRes, sensbResLen);
}
/*******************************************************************************/
ReturnCode rfalNfcbPollerCollisionResolution(
rfalComplianceMode compMode,
uint8_t devLimit,
rfalNfcbListenDevice* nfcbDevList,
uint8_t* devCnt) {
bool colPending; /* dummy */
return rfalNfcbPollerSlottedCollisionResolution(
compMode,
devLimit,
RFAL_NFCB_SLOT_NUM_1,
RFAL_NFCB_SLOT_NUM_16,
nfcbDevList,
devCnt,
&colPending);
}
/*******************************************************************************/
ReturnCode rfalNfcbPollerSlottedCollisionResolution(
rfalComplianceMode compMode,
uint8_t devLimit,
rfalNfcbSlots initSlots,
rfalNfcbSlots endSlots,
rfalNfcbListenDevice* nfcbDevList,
uint8_t* devCnt,
bool* colPending) {
ReturnCode ret;
uint8_t slotsNum;
uint8_t slotCode;
uint8_t curDevCnt;
/* Check parameters. In ISO | Activity 1.0 mode the initial slots must be 1 as continuation of Technology Detection */
if((nfcbDevList == NULL) || (devCnt == NULL) || (colPending == NULL) ||
(initSlots > RFAL_NFCB_SLOT_NUM_16) || (endSlots > RFAL_NFCB_SLOT_NUM_16) ||
((compMode == RFAL_COMPLIANCE_MODE_ISO) && (initSlots != RFAL_NFCB_SLOT_NUM_1))) {
return ERR_PARAM;
}
/* Initialise as no error in case Activity 1.0 where the previous SENSB_RES from technology detection should be used */
ret = ERR_NONE;
*devCnt = 0;
curDevCnt = 0;
*colPending = false;
/* Send ALLB_REQ Activity 1.1 9.3.5.2 and 9.3.5.3 (Symbol 1 and 2) */
if(compMode != RFAL_COMPLIANCE_MODE_ISO) {
ret = rfalNfcbPollerCheckPresence(
RFAL_NFCB_SENS_CMD_ALLB_REQ,
initSlots,
&nfcbDevList->sensbRes,
&nfcbDevList->sensbResLen);
if((ret != ERR_NONE) && (initSlots == RFAL_NFCB_SLOT_NUM_1)) {
return ret;
}
}
/* Check if there was a transmission error on WUPB EMVCo 2.6 9.3.3.1 */
if((compMode == RFAL_COMPLIANCE_MODE_EMV) && (nfcbDevList->sensbResLen == 0U)) {
return ERR_FRAMING;
}
for(slotsNum = (uint8_t)initSlots; slotsNum <= (uint8_t)endSlots; slotsNum++) {
do {
/* Activity 1.1 9.3.5.23 - Symbol 22 */
if((compMode == RFAL_COMPLIANCE_MODE_NFC) && (curDevCnt != 0U)) {
rfalNfcbPollerSleep(nfcbDevList[((*devCnt) - (uint8_t)1U)].sensbRes.nfcid0);
nfcbDevList[((*devCnt) - (uint8_t)1U)].isSleep = true;
}
/* Send SENSB_REQ with number of slots if not the first Activity 1.1 9.3.5.24 - Symbol 23 */
if((slotsNum != (uint8_t)initSlots) || *colPending) {
/* PRQA S 4342 1 # MISRA 10.5 - Layout of rfalNfcbSlots and above loop guarantee that no invalid enum values are created. */
ret = rfalNfcbPollerCheckPresence(
RFAL_NFCB_SENS_CMD_SENSB_REQ,
(rfalNfcbSlots)slotsNum,
&nfcbDevList[*devCnt].sensbRes,
&nfcbDevList[*devCnt].sensbResLen);
}
/* Activity 1.1 9.3.5.6 - Symbol 5 */
slotCode = 0;
curDevCnt = 0;
*colPending = false;
do {
/* Activity 1.1 9.3.5.26 - Symbol 25 */
if(slotCode != 0U) {
ret = rfalNfcbPollerSlotMarker(
slotCode,
&nfcbDevList[*devCnt].sensbRes,
&nfcbDevList[*devCnt].sensbResLen);
}
/* Activity 1.1 9.3.5.7 and 9.3.5.8 - Symbol 6 */
if(ret != ERR_TIMEOUT) {
/* Activity 1.1 9.3.5.8 - Symbol 7 */
if((rfalNfcbCheckSensbRes(
&nfcbDevList[*devCnt].sensbRes, nfcbDevList[*devCnt].sensbResLen) ==
ERR_NONE) &&
(ret == ERR_NONE)) {
nfcbDevList[*devCnt].isSleep = false;
if(compMode == RFAL_COMPLIANCE_MODE_EMV) {
(*devCnt)++;
return ret;
} else if(compMode == RFAL_COMPLIANCE_MODE_ISO) {
/* Activity 1.0 9.3.5.8 - Symbol 7 */
(*devCnt)++;
curDevCnt++;
/* Activity 1.0 9.3.5.10 - Symbol 9 */
if((*devCnt >= devLimit) ||
(slotsNum == (uint8_t)RFAL_NFCB_SLOT_NUM_1)) {
return ret;
}
/* Activity 1.0 9.3.5.11 - Symbol 10 */
rfalNfcbPollerSleep(nfcbDevList[*devCnt - 1U].sensbRes.nfcid0);
nfcbDevList[*devCnt - 1U].isSleep = true;
} else if(compMode == RFAL_COMPLIANCE_MODE_NFC) {
/* Activity 1.1 9.3.5.10 and 9.3.5.11 - Symbol 9 and Symbol 11*/
if(curDevCnt != 0U) {
rfalNfcbPollerSleep(
nfcbDevList[(*devCnt) - (uint8_t)1U].sensbRes.nfcid0);
nfcbDevList[(*devCnt) - (uint8_t)1U].isSleep = true;
}
/* Activity 1.1 9.3.5.12 - Symbol 11 */
(*devCnt)++;
curDevCnt++;
/* Activity 1.1 9.3.5.6 - Symbol 13 */
if((*devCnt >= devLimit) ||
(slotsNum == (uint8_t)RFAL_NFCB_SLOT_NUM_1)) {
return ret;
}
} else {
/* MISRA 15.7 - Empty else */
}
} else {
/* If deviceLimit is set to 0 the NFC Forum Device is configured to perform collision detection only Activity 1.0 and 1.1 9.3.5.5 - Symbol 4 */
if((devLimit == 0U) && (slotsNum == (uint8_t)RFAL_NFCB_SLOT_NUM_1)) {
return ERR_RF_COLLISION;
}
/* Activity 1.1 9.3.5.9 - Symbol 8 */
*colPending = true;
}
}
/* Activity 1.1 9.3.5.15 - Symbol 14 */
slotCode++;
} while(slotCode < rfalNfcbNI2NumberOfSlots(slotsNum));
/* Activity 1.1 9.3.5.17 - Symbol 16 */
if(!(*colPending)) {
return ERR_NONE;
}
/* Activity 1.1 9.3.5.18 - Symbol 17 */
} while(
curDevCnt !=
0U); /* If a collision is detected and card(s) were found on this loop keep the same number of available slots */
}
return ERR_NONE;
}
/*******************************************************************************/
uint32_t rfalNfcbTR2ToFDT(uint8_t tr2Code) {
/*******************************************************************************/
/* MISRA 8.9 An object should be defined at block scope if its identifier only appears in a single function */
/*! TR2 Table according to Digital 1.1 Table 33 */
const uint16_t rfalNfcbTr2Table[] = {1792, 3328, 5376, 9472};
/*******************************************************************************/
return rfalNfcbTr2Table[(tr2Code & RFAL_NFCB_SENSB_RES_PROTO_TR2_MASK)];
}
#endif /* RFAL_FEATURE_NFCB */
-585
View File
@@ -1,585 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_nfcf.c
*
* \author Gustavo Patricio
*
* \brief Implementation of NFC-F Poller (FeliCa PCD) device
*
* The definitions and helpers methods provided by this module are
* aligned with NFC-F (FeliCa - JIS X6319-4)
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "rfal_nfcf.h"
#include "utils.h"
/*
******************************************************************************
* ENABLE SWITCH
******************************************************************************
*/
#ifndef RFAL_FEATURE_NFCF
#define RFAL_FEATURE_NFCF false /* NFC-F module configuration missing. Disabled by default */
#endif
#if RFAL_FEATURE_NFCF
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_NFCF_SENSF_REQ_LEN_MIN \
5U /*!< SENSF_RES minimum length */
#define RFAL_NFCF_READ_WO_ENCRYPTION_MIN_LEN \
15U /*!< Minimum length for a Check Command T3T 5.4.1 */
#define RFAL_NFCF_WRITE_WO_ENCRYPTION_MIN_LEN \
31U /*!< Minimum length for an Update Command T3T 5.5.1 */
#define RFAL_NFCF_CHECK_RES_MIN_LEN \
11U /*!< CHECK Response minimum length T3T 1.0 Table 8 */
#define RFAL_NFCF_UPDATE_RES_MIN_LEN \
11U /*!< UPDATE Response minimum length T3T 1.0 Table 8 */
#define RFAL_NFCF_CHECK_REQ_MAX_LEN \
86U /*!< Max length of a Check request T3T 1.0 Table 7 */
#define RFAL_NFCF_CHECK_REQ_MAX_SERV \
15U /*!< Max Services number on Check request T3T 1.0 5.4.1.5 */
#define RFAL_NFCF_CHECK_REQ_MAX_BLOCK \
15U /*!< Max Blocks number on Check request T3T 1.0 5.4.1.10 */
#define RFAL_NFCF_UPDATE_REQ_MAX_SERV \
15U /*!< Max Services number Update request T3T 1.0 5.4.1.5 */
#define RFAL_NFCF_UPDATE_REQ_MAX_BLOCK \
13U /*!< Max Blocks number on Update request T3T 1.0 5.4.1.10 */
/*! MRT Check | Uupdate = (Tt3t x ((A+1) + n (B+1)) x 4^E) + dRWTt3t T3T 5.8
Max values used: A = 7 ; B = 7 ; E = 3 ; n = 15 (NFC Forum n = 15, JIS n = 32)
*/
#define RFAL_NFCF_MRT_CHECK_UPDATE ((4096 * (8 + (15 * 8)) * 64) + 16)
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
#define rfalNfcfSlots2CardNum(s) \
((uint8_t)(s) + 1U) /*!< Converts Time Slot Number (TSN) into num of slots */
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
/*! Structure/Buffer to hold the SENSF_RES with LEN byte prepended */
typedef struct {
uint8_t LEN; /*!< NFC-F LEN byte */
rfalNfcfSensfRes SENSF_RES; /*!< SENSF_RES */
} rfalNfcfSensfResBuf;
/*! Greedy collection for NFCF GRE_POLL_F Activity 1.0 Table 10 */
typedef struct {
uint8_t pollFound; /*!< Number of devices found by the Poll */
uint8_t pollCollision; /*!< Number of collisions detected */
rfalFeliCaPollRes POLL_F[RFAL_NFCF_POLL_MAXCARDS]; /*!< GRE_POLL_F Activity 1.0 Table 10 */
} rfalNfcfGreedyF;
/*! NFC-F SENSF_REQ format Digital 1.1 8.6.1 */
typedef struct {
uint8_t CMD; /*!< Command code: 00h */
uint8_t SC[RFAL_NFCF_SENSF_SC_LEN]; /*!< System Code */
uint8_t RC; /*!< Request Code */
uint8_t TSN; /*!< Time Slot Number */
} rfalNfcfSensfReq;
/*
******************************************************************************
* LOCAL VARIABLES
******************************************************************************
*/
static rfalNfcfGreedyF gRfalNfcfGreedyF; /*!< Activity's NFCF Greedy collection */
/*
******************************************************************************
* LOCAL FUNCTION PROTOTYPES
******************************************************************************
*/
static void rfalNfcfComputeValidSENF(
rfalNfcfListenDevice* outDevInfo,
uint8_t* curDevIdx,
uint8_t devLimit,
bool overwrite,
bool* nfcDepFound);
/*
******************************************************************************
* LOCAL VARIABLES
******************************************************************************
*/
/*******************************************************************************/
static void rfalNfcfComputeValidSENF(
rfalNfcfListenDevice* outDevInfo,
uint8_t* curDevIdx,
uint8_t devLimit,
bool overwrite,
bool* nfcDepFound) {
uint8_t tmpIdx;
bool duplicate;
const rfalNfcfSensfResBuf* sensfBuf;
rfalNfcfSensfResBuf sensfCopy;
/*******************************************************************************/
/* Go through all responses check if valid and duplicates */
/*******************************************************************************/
while((gRfalNfcfGreedyF.pollFound > 0U) && ((*curDevIdx) < devLimit)) {
duplicate = false;
gRfalNfcfGreedyF.pollFound--;
/* MISRA 11.3 - Cannot point directly into different object type, use local copy */
ST_MEMCPY(
(uint8_t*)&sensfCopy,
(uint8_t*)&gRfalNfcfGreedyF.POLL_F[gRfalNfcfGreedyF.pollFound],
sizeof(rfalNfcfSensfResBuf));
/* Point to received SENSF_RES */
sensfBuf = &sensfCopy;
/* Check for devices that are already in device list */
for(tmpIdx = 0; tmpIdx < (*curDevIdx); tmpIdx++) {
if(ST_BYTECMP(
sensfBuf->SENSF_RES.NFCID2,
outDevInfo[tmpIdx].sensfRes.NFCID2,
RFAL_NFCF_NFCID2_LEN) == 0) {
duplicate = true;
break;
}
}
/* If is a duplicate skip this (and not to overwrite)*/
if(duplicate && !overwrite) {
continue;
}
/* Check if response length is OK */
if(((sensfBuf->LEN - RFAL_NFCF_HEADER_LEN) < RFAL_NFCF_SENSF_RES_LEN_MIN) ||
((sensfBuf->LEN - RFAL_NFCF_HEADER_LEN) > RFAL_NFCF_SENSF_RES_LEN_MAX)) {
continue;
}
/* Check if the response is a SENSF_RES / Polling response */
if(sensfBuf->SENSF_RES.CMD != (uint8_t)RFAL_NFCF_CMD_POLLING_RES) {
continue;
}
/* Check if is an overwrite request or new device*/
if(duplicate && overwrite) {
/* overwrite deviceInfo/GRE_SENSF_RES with SENSF_RES */
outDevInfo[tmpIdx].sensfResLen = (sensfBuf->LEN - RFAL_NFCF_LENGTH_LEN);
ST_MEMCPY(
&outDevInfo[tmpIdx].sensfRes,
&sensfBuf->SENSF_RES,
outDevInfo[tmpIdx].sensfResLen);
continue;
} else {
/* fill deviceInfo/GRE_SENSF_RES with new SENSF_RES */
outDevInfo[(*curDevIdx)].sensfResLen = (sensfBuf->LEN - RFAL_NFCF_LENGTH_LEN);
ST_MEMCPY(
&outDevInfo[(*curDevIdx)].sensfRes,
&sensfBuf->SENSF_RES,
outDevInfo[(*curDevIdx)].sensfResLen);
}
/* Check if this device supports NFC-DEP and signal it (ACTIVITY 1.1 9.3.6.63) */
*nfcDepFound = rfalNfcfIsNfcDepSupported(&outDevInfo[(*curDevIdx)]);
(*curDevIdx)++;
}
}
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
/*******************************************************************************/
ReturnCode rfalNfcfPollerInitialize(rfalBitRate bitRate) {
ReturnCode ret;
if((bitRate != RFAL_BR_212) && (bitRate != RFAL_BR_424)) {
return ERR_PARAM;
}
EXIT_ON_ERR(ret, rfalSetMode(RFAL_MODE_POLL_NFCF, bitRate, bitRate));
rfalSetErrorHandling(RFAL_ERRORHANDLING_NFC);
rfalSetGT(RFAL_GT_NFCF);
rfalSetFDTListen(RFAL_FDT_LISTEN_NFCF_POLLER);
rfalSetFDTPoll(RFAL_FDT_POLL_NFCF_POLLER);
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode rfalNfcfPollerPoll(
rfalFeliCaPollSlots slots,
uint16_t sysCode,
uint8_t reqCode,
rfalFeliCaPollRes* cardList,
uint8_t* devCnt,
uint8_t* collisions) {
return rfalFeliCaPoll(
slots, sysCode, reqCode, cardList, rfalNfcfSlots2CardNum(slots), devCnt, collisions);
}
/*******************************************************************************/
ReturnCode rfalNfcfPollerCheckPresence(void) {
gRfalNfcfGreedyF.pollFound = 0;
gRfalNfcfGreedyF.pollCollision = 0;
/* ACTIVITY 1.0 & 1.1 - 9.2.3.17 SENSF_REQ must be with number of slots equal to 4
* SC must be 0xFFFF
* RC must be 0x00 (No system code info required) */
return rfalFeliCaPoll(
RFAL_FELICA_4_SLOTS,
RFAL_NFCF_SYSTEMCODE,
RFAL_FELICA_POLL_RC_NO_REQUEST,
gRfalNfcfGreedyF.POLL_F,
rfalNfcfSlots2CardNum(RFAL_FELICA_4_SLOTS),
&gRfalNfcfGreedyF.pollFound,
&gRfalNfcfGreedyF.pollCollision);
}
/*******************************************************************************/
ReturnCode rfalNfcfPollerCollisionResolution(
rfalComplianceMode compMode,
uint8_t devLimit,
rfalNfcfListenDevice* nfcfDevList,
uint8_t* devCnt) {
ReturnCode ret;
bool nfcDepFound;
if((nfcfDevList == NULL) || (devCnt == NULL)) {
return ERR_PARAM;
}
*devCnt = 0;
nfcDepFound = false;
/*******************************************************************************************/
/* ACTIVITY 1.0 - 9.3.6.3 Copy valid SENSF_RES in GRE_POLL_F into GRE_SENSF_RES */
/* ACTIVITY 1.0 - 9.3.6.6 The NFC Forum Device MUST remove all entries from GRE_SENSF_RES[]*/
/* ACTIVITY 1.1 - 9.3.63.59 Populate GRE_SENSF_RES with data from GRE_POLL_F */
/* */
/* CON_DEVICES_LIMIT = 0 Just check if devices from Tech Detection exceeds -> always true */
/* Allow the number of slots open on Technology Detection */
/*******************************************************************************************/
rfalNfcfComputeValidSENF(
nfcfDevList,
devCnt,
((devLimit == 0U) ? rfalNfcfSlots2CardNum(RFAL_FELICA_4_SLOTS) : devLimit),
false,
&nfcDepFound);
/*******************************************************************************/
/* ACTIVITY 1.0 - 9.3.6.4 */
/* ACTIVITY 1.1 - 9.3.63.60 Check if devices found are lower than the limit */
/* and send a SENSF_REQ if so */
/*******************************************************************************/
if(*devCnt < devLimit) {
/* ACTIVITY 1.0 - 9.3.6.5 Copy valid SENSF_RES and then to remove it
* ACTIVITY 1.1 - 9.3.6.65 Copy and filter duplicates
* For now, due to some devices keep generating different nfcid2, we use 1.0
* Phones detected: Samsung Galaxy Nexus,Samsung Galaxy S3,Samsung Nexus S */
*devCnt = 0;
ret = rfalNfcfPollerPoll(
RFAL_FELICA_16_SLOTS,
RFAL_NFCF_SYSTEMCODE,
RFAL_FELICA_POLL_RC_NO_REQUEST,
gRfalNfcfGreedyF.POLL_F,
&gRfalNfcfGreedyF.pollFound,
&gRfalNfcfGreedyF.pollCollision);
if(ret == ERR_NONE) {
rfalNfcfComputeValidSENF(nfcfDevList, devCnt, devLimit, false, &nfcDepFound);
}
/*******************************************************************************/
/* ACTIVITY 1.1 - 9.3.6.63 Check if any device supports NFC DEP */
/*******************************************************************************/
if(nfcDepFound && (compMode == RFAL_COMPLIANCE_MODE_NFC)) {
ret = rfalNfcfPollerPoll(
RFAL_FELICA_16_SLOTS,
RFAL_NFCF_SYSTEMCODE,
RFAL_FELICA_POLL_RC_SYSTEM_CODE,
gRfalNfcfGreedyF.POLL_F,
&gRfalNfcfGreedyF.pollFound,
&gRfalNfcfGreedyF.pollCollision);
if(ret == ERR_NONE) {
rfalNfcfComputeValidSENF(nfcfDevList, devCnt, devLimit, true, &nfcDepFound);
}
}
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode rfalNfcfPollerCheck(
const uint8_t* nfcid2,
const rfalNfcfServBlockListParam* servBlock,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvdLen) {
uint8_t txBuf[RFAL_NFCF_CHECK_REQ_MAX_LEN];
uint8_t msgIt;
uint8_t i;
ReturnCode ret;
const uint8_t* checkRes;
/* Check parameters */
if((nfcid2 == NULL) || (rxBuf == NULL) || (servBlock == NULL) || (servBlock->numBlock == 0U) ||
(servBlock->numBlock > RFAL_NFCF_CHECK_REQ_MAX_BLOCK) || (servBlock->numServ == 0U) ||
(servBlock->numServ > RFAL_NFCF_CHECK_REQ_MAX_SERV) ||
(rxBufLen < (RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CHECK_RES_MIN_LEN))) {
return ERR_PARAM;
}
msgIt = 0;
/*******************************************************************************/
/* Compose CHECK command/request */
txBuf[msgIt++] = RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION; /* Command Code */
ST_MEMCPY(&txBuf[msgIt], nfcid2, RFAL_NFCF_NFCID2_LEN); /* NFCID2 */
msgIt += RFAL_NFCF_NFCID2_LEN;
txBuf[msgIt++] = servBlock->numServ; /* NoS */
for(i = 0; i < servBlock->numServ; i++) {
txBuf[msgIt++] = (uint8_t)((servBlock->servList[i] >> 0U) & 0xFFU); /* Service Code */
txBuf[msgIt++] = (uint8_t)((servBlock->servList[i] >> 8U) & 0xFFU);
}
txBuf[msgIt++] = servBlock->numBlock; /* NoB */
for(i = 0; i < servBlock->numBlock; i++) {
txBuf[msgIt++] =
servBlock->blockList[i].conf; /* Block list element conf (Flag|Access|Service) */
if((servBlock->blockList[i].conf & 0x80U) !=
0U) /* Check if 2 or 3 byte block list element */
{
txBuf[msgIt++] =
(uint8_t)(servBlock->blockList[i].blockNum & 0xFFU); /* 1byte Block Num */
} else {
txBuf[msgIt++] =
(uint8_t)((servBlock->blockList[i].blockNum >> 0U) & 0xFFU); /* 2byte Block Num */
txBuf[msgIt++] = (uint8_t)((servBlock->blockList[i].blockNum >> 8U) & 0xFFU);
}
}
/*******************************************************************************/
/* Transceive CHECK command/request */
ret = rfalTransceiveBlockingTxRx(
txBuf,
msgIt,
rxBuf,
rxBufLen,
rcvdLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_NFCF_MRT_CHECK_UPDATE);
if(ret == ERR_NONE) {
/* Skip LEN byte */
checkRes = (rxBuf + RFAL_NFCF_LENGTH_LEN);
/* Check response length */
if(*rcvdLen < (RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CHECKUPDATE_RES_ST2_POS)) {
ret = ERR_PROTO;
}
/* Check for a valid response */
else if(
(checkRes[RFAL_NFCF_CMD_POS] != (uint8_t)RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION_RES) ||
(checkRes[RFAL_NFCF_CHECKUPDATE_RES_ST1_POS] != RFAL_NFCF_STATUS_FLAG_SUCCESS) ||
(checkRes[RFAL_NFCF_CHECKUPDATE_RES_ST2_POS] != RFAL_NFCF_STATUS_FLAG_SUCCESS)) {
ret = ERR_REQUEST;
}
/* CHECK succesfull, remove header */
else {
(*rcvdLen) -= (RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CHECKUPDATE_RES_NOB_POS);
if(*rcvdLen > 0U) {
ST_MEMMOVE(rxBuf, &checkRes[RFAL_NFCF_CHECKUPDATE_RES_NOB_POS], (*rcvdLen));
}
}
}
return ret;
}
/*******************************************************************************/
ReturnCode rfalNfcfPollerUpdate(
const uint8_t* nfcid2,
const rfalNfcfServBlockListParam* servBlock,
uint8_t* txBuf,
uint16_t txBufLen,
const uint8_t* blockData,
uint8_t* rxBuf,
uint16_t rxBufLen) {
uint8_t i;
uint16_t msgIt;
uint16_t rcvdLen;
uint16_t auxLen;
const uint8_t* updateRes;
ReturnCode ret;
/* Check parameters */
if((nfcid2 == NULL) || (rxBuf == NULL) || (servBlock == NULL) || (txBuf == NULL) ||
(servBlock->numBlock == 0U) || (servBlock->numBlock > RFAL_NFCF_UPDATE_REQ_MAX_BLOCK) ||
(servBlock->numServ == 0U) || (servBlock->numServ > RFAL_NFCF_UPDATE_REQ_MAX_SERV) ||
(rxBufLen < (RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_UPDATE_RES_MIN_LEN))) {
return ERR_PARAM;
}
/* Calculate required txBuffer lenth */
auxLen = (uint16_t)( RFAL_NFCF_CMD_LEN + RFAL_NFCF_NFCID2_LEN + ( servBlock->numServ * sizeof(rfalNfcfServ) ) +
(servBlock->numBlock * sizeof(rfalNfcfBlockListElem)) + (uint16_t)((uint16_t)servBlock->numBlock * RFAL_NFCF_BLOCK_LEN) );
/* Check whether the provided buffer is sufficient for this request */
if(txBufLen < auxLen) {
return ERR_PARAM;
}
msgIt = 0;
/*******************************************************************************/
/* Compose UPDATE command/request */
txBuf[msgIt++] = RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION; /* Command Code */
ST_MEMCPY(&txBuf[msgIt], nfcid2, RFAL_NFCF_NFCID2_LEN); /* NFCID2 */
msgIt += RFAL_NFCF_NFCID2_LEN;
txBuf[msgIt++] = servBlock->numServ; /* NoS */
for(i = 0; i < servBlock->numServ; i++) {
txBuf[msgIt++] = (uint8_t)((servBlock->servList[i] >> 0U) & 0xFFU); /* Service Code */
txBuf[msgIt++] = (uint8_t)((servBlock->servList[i] >> 8U) & 0xFFU);
}
txBuf[msgIt++] = servBlock->numBlock; /* NoB */
for(i = 0; i < servBlock->numBlock; i++) {
txBuf[msgIt++] =
servBlock->blockList[i].conf; /* Block list element conf (Flag|Access|Service) */
if((servBlock->blockList[i].conf & 0x80U) !=
0U) /* Check if 2 or 3 byte block list element */
{
txBuf[msgIt++] =
(uint8_t)(servBlock->blockList[i].blockNum & 0xFFU); /* 1byte Block Num */
} else {
txBuf[msgIt++] =
(uint8_t)((servBlock->blockList[i].blockNum >> 0U) & 0xFFU); /* 2byte Block Num */
txBuf[msgIt++] = (uint8_t)((servBlock->blockList[i].blockNum >> 8U) & 0xFFU);
}
}
auxLen = ((uint16_t)servBlock->numBlock * RFAL_NFCF_BLOCK_LEN);
ST_MEMCPY(&txBuf[msgIt], blockData, auxLen); /* Block Data */
msgIt += auxLen;
/*******************************************************************************/
/* Transceive UPDATE command/request */
ret = rfalTransceiveBlockingTxRx(
txBuf,
msgIt,
rxBuf,
rxBufLen,
&rcvdLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_NFCF_MRT_CHECK_UPDATE);
if(ret == ERR_NONE) {
/* Skip LEN byte */
updateRes = (rxBuf + RFAL_NFCF_LENGTH_LEN);
/* Check response length */
if(rcvdLen < (RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CHECKUPDATE_RES_ST2_POS)) {
ret = ERR_PROTO;
}
/* Check for a valid response */
else if(
(updateRes[RFAL_NFCF_CMD_POS] !=
(uint8_t)RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION_RES) ||
(updateRes[RFAL_NFCF_CHECKUPDATE_RES_ST1_POS] != RFAL_NFCF_STATUS_FLAG_SUCCESS) ||
(updateRes[RFAL_NFCF_CHECKUPDATE_RES_ST2_POS] != RFAL_NFCF_STATUS_FLAG_SUCCESS)) {
ret = ERR_REQUEST;
} else {
/* MISRA 15.7 - Empty else */
}
}
return ret;
}
/*******************************************************************************/
bool rfalNfcfListenerIsT3TReq(const uint8_t* buf, uint16_t bufLen, uint8_t* nfcid2) {
/* Check cmd byte */
switch(*buf) {
case RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION:
if(bufLen < RFAL_NFCF_READ_WO_ENCRYPTION_MIN_LEN) {
return false;
}
break;
case RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION:
if(bufLen < RFAL_NFCF_WRITE_WO_ENCRYPTION_MIN_LEN) {
return false;
}
break;
default:
return false;
}
/* Output NFID2 if requested */
if(nfcid2 != NULL) {
ST_MEMCPY(nfcid2, &buf[RFAL_NFCF_CMD_LEN], RFAL_NFCF_NFCID2_LEN);
}
return true;
}
#endif /* RFAL_FEATURE_NFCF */
File diff suppressed because it is too large Load Diff
-563
View File
@@ -1,563 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_st25tb.c
*
* \author Gustavo Patricio
*
* \brief Implementation of ST25TB interface
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "rfal_st25tb.h"
#include "utils.h"
/*
******************************************************************************
* ENABLE SWITCH
******************************************************************************
*/
#ifndef RFAL_FEATURE_ST25TB
#define RFAL_FEATURE_ST25TB false /* ST25TB module configuration missing. Disabled by default */
#endif
#if RFAL_FEATURE_ST25TB
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_ST25TB_CMD_LEN 1U /*!< ST25TB length of a command */
#define RFAL_ST25TB_SLOTS 16U /*!< ST25TB number of slots */
#define RFAL_ST25TB_SLOTNUM_MASK 0x0FU /*!< ST25TB Slot Number bit mask on SlotMarker */
#define RFAL_ST25TB_SLOTNUM_SHIFT 4U /*!< ST25TB Slot Number shift on SlotMarker */
#define RFAL_ST25TB_INITIATE_CMD1 0x06U /*!< ST25TB Initiate command byte1 */
#define RFAL_ST25TB_INITIATE_CMD2 0x00U /*!< ST25TB Initiate command byte2 */
#define RFAL_ST25TB_PCALL_CMD1 0x06U /*!< ST25TB Pcall16 command byte1 */
#define RFAL_ST25TB_PCALL_CMD2 0x04U /*!< ST25TB Pcall16 command byte2 */
#define RFAL_ST25TB_SELECT_CMD 0x0EU /*!< ST25TB Select command */
#define RFAL_ST25TB_GET_UID_CMD 0x0BU /*!< ST25TB Get UID command */
#define RFAL_ST25TB_COMPLETION_CMD 0x0FU /*!< ST25TB Completion command */
#define RFAL_ST25TB_RESET_INV_CMD 0x0CU /*!< ST25TB Reset to Inventory command */
#define RFAL_ST25TB_READ_BLOCK_CMD 0x08U /*!< ST25TB Read Block command */
#define RFAL_ST25TB_WRITE_BLOCK_CMD 0x09U /*!< ST25TB Write Block command */
#define RFAL_ST25TB_T0 2157U /*!< ST25TB t0 159 us ST25TB RF characteristics */
#define RFAL_ST25TB_T1 2048U /*!< ST25TB t1 151 us ST25TB RF characteristics */
#define RFAL_ST25TB_FWT \
(RFAL_ST25TB_T0 + RFAL_ST25TB_T1) /*!< ST25TB FWT = T0 + T1 */
#define RFAL_ST25TB_TW rfalConvMsTo1fc(7U) /*!< ST25TB TW : Programming time for write max 7ms */
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
/*! Initiate Request */
typedef struct {
uint8_t cmd1; /*!< Initiate Request cmd1: 0x06 */
uint8_t cmd2; /*!< Initiate Request cmd2: 0x00 */
} rfalSt25tbInitiateReq;
/*! Pcall16 Request */
typedef struct {
uint8_t cmd1; /*!< Pcal16 Request cmd1: 0x06 */
uint8_t cmd2; /*!< Pcal16 Request cmd2: 0x04 */
} rfalSt25tbPcallReq;
/*! Select Request */
typedef struct {
uint8_t cmd; /*!< Select Request cmd: 0x0E */
uint8_t chipId; /*!< Chip ID */
} rfalSt25tbSelectReq;
/*! Read Block Request */
typedef struct {
uint8_t cmd; /*!< Select Request cmd: 0x08 */
uint8_t address; /*!< Block address */
} rfalSt25tbReadBlockReq;
/*! Write Block Request */
typedef struct {
uint8_t cmd; /*!< Select Request cmd: 0x09 */
uint8_t address; /*!< Block address */
rfalSt25tbBlock data; /*!< Block Data */
} rfalSt25tbWriteBlockReq;
/*
******************************************************************************
* LOCAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief ST25TB Poller Do Collision Resolution
*
* This method performs ST25TB Collision resolution loop for each slot
*
* \param[in] devLimit : device limit value, and size st25tbDevList
* \param[out] st25tbDevList : ST35TB listener device info
* \param[out] devCnt : Devices found counter
*
* \return colPending : true if a collision was detected
*****************************************************************************
*/
static bool rfalSt25tbPollerDoCollisionResolution(
uint8_t devLimit,
rfalSt25tbListenDevice* st25tbDevList,
uint8_t* devCnt);
/*
******************************************************************************
* LOCAL FUNCTION PROTOTYPES
******************************************************************************
*/
static bool rfalSt25tbPollerDoCollisionResolution(
uint8_t devLimit,
rfalSt25tbListenDevice* st25tbDevList,
uint8_t* devCnt) {
uint8_t i;
uint8_t chipId;
ReturnCode ret;
bool col;
col = false;
for(i = 0; i < RFAL_ST25TB_SLOTS; i++) {
platformDelay(1); /* Wait t2: Answer to new request delay */
if(i == 0U) {
/* Step 2: Send Pcall16 */
ret = rfalSt25tbPollerPcall(&chipId);
} else {
/* Step 3-17: Send Pcall16 */
ret = rfalSt25tbPollerSlotMarker(i, &chipId);
}
if(ret == ERR_NONE) {
/* Found another device */
st25tbDevList[*devCnt].chipID = chipId;
st25tbDevList[*devCnt].isDeselected = false;
/* Select Device, retrieve its UID */
ret = rfalSt25tbPollerSelect(chipId);
/* By Selecting this device, the previous gets Deselected */
if((*devCnt) > 0U) {
st25tbDevList[(*devCnt) - 1U].isDeselected = true;
}
if(ERR_NONE == ret) {
rfalSt25tbPollerGetUID(&st25tbDevList[*devCnt].UID);
}
if(ERR_NONE == ret) {
(*devCnt)++;
}
} else if((ret == ERR_CRC) || (ret == ERR_FRAMING)) {
col = true;
} else {
/* MISRA 15.7 - Empty else */
}
if(*devCnt >= devLimit) {
break;
}
}
return col;
}
/*
******************************************************************************
* LOCAL VARIABLES
******************************************************************************
*/
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
/*******************************************************************************/
ReturnCode rfalSt25tbPollerInitialize(void) {
return rfalNfcbPollerInitialize();
}
/*******************************************************************************/
ReturnCode rfalSt25tbPollerCheckPresence(uint8_t* chipId) {
ReturnCode ret;
uint8_t chipIdRes;
chipIdRes = 0x00;
/* Send Initiate Request */
ret = rfalSt25tbPollerInitiate(&chipIdRes);
/* Check if a transmission error was detected */
if((ret == ERR_CRC) || (ret == ERR_FRAMING)) {
return ERR_NONE;
}
/* Copy chip ID if requested */
if(chipId != NULL) {
*chipId = chipIdRes;
}
return ret;
}
/*******************************************************************************/
ReturnCode rfalSt25tbPollerInitiate(uint8_t* chipId) {
ReturnCode ret;
uint16_t rxLen;
rfalSt25tbInitiateReq initiateReq;
uint8_t rxBuf
[RFAL_ST25TB_CHIP_ID_LEN +
RFAL_ST25TB_CRC_LEN]; /* In case we receive less data that CRC, RF layer will not remove the CRC from buffer */
/* Compute Initiate Request */
initiateReq.cmd1 = RFAL_ST25TB_INITIATE_CMD1;
initiateReq.cmd2 = RFAL_ST25TB_INITIATE_CMD2;
/* Send Initiate Request */
ret = rfalTransceiveBlockingTxRx(
(uint8_t*)&initiateReq,
sizeof(rfalSt25tbInitiateReq),
(uint8_t*)rxBuf,
sizeof(rxBuf),
&rxLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_ST25TB_FWT);
/* Check for valid Select Response */
if((ret == ERR_NONE) && (rxLen != RFAL_ST25TB_CHIP_ID_LEN)) {
return ERR_PROTO;
}
/* Copy chip ID if requested */
if(chipId != NULL) {
*chipId = *rxBuf;
}
return ret;
}
/*******************************************************************************/
ReturnCode rfalSt25tbPollerPcall(uint8_t* chipId) {
ReturnCode ret;
uint16_t rxLen;
rfalSt25tbPcallReq pcallReq;
/* Compute Pcal16 Request */
pcallReq.cmd1 = RFAL_ST25TB_PCALL_CMD1;
pcallReq.cmd2 = RFAL_ST25TB_PCALL_CMD2;
/* Send Pcal16 Request */
ret = rfalTransceiveBlockingTxRx(
(uint8_t*)&pcallReq,
sizeof(rfalSt25tbPcallReq),
(uint8_t*)chipId,
RFAL_ST25TB_CHIP_ID_LEN,
&rxLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_ST25TB_FWT);
/* Check for valid Select Response */
if((ret == ERR_NONE) && (rxLen != RFAL_ST25TB_CHIP_ID_LEN)) {
return ERR_PROTO;
}
return ret;
}
/*******************************************************************************/
ReturnCode rfalSt25tbPollerSlotMarker(uint8_t slotNum, uint8_t* chipIdRes) {
ReturnCode ret;
uint16_t rxLen;
uint8_t slotMarker;
if((slotNum == 0U) || (slotNum > 15U)) {
return ERR_PARAM;
}
/* Compute SlotMarker */
slotMarker =
(((slotNum & RFAL_ST25TB_SLOTNUM_MASK) << RFAL_ST25TB_SLOTNUM_SHIFT) |
RFAL_ST25TB_PCALL_CMD1);
/* Send SlotMarker */
ret = rfalTransceiveBlockingTxRx(
(uint8_t*)&slotMarker,
RFAL_ST25TB_CMD_LEN,
(uint8_t*)chipIdRes,
RFAL_ST25TB_CHIP_ID_LEN,
&rxLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_ST25TB_FWT);
/* Check for valid ChipID Response */
if((ret == ERR_NONE) && (rxLen != RFAL_ST25TB_CHIP_ID_LEN)) {
return ERR_PROTO;
}
return ret;
}
/*******************************************************************************/
ReturnCode rfalSt25tbPollerSelect(uint8_t chipId) {
ReturnCode ret;
uint16_t rxLen;
rfalSt25tbSelectReq selectReq;
uint8_t chipIdRes;
/* Compute Select Request */
selectReq.cmd = RFAL_ST25TB_SELECT_CMD;
selectReq.chipId = chipId;
/* Send Select Request */
ret = rfalTransceiveBlockingTxRx(
(uint8_t*)&selectReq,
sizeof(rfalSt25tbSelectReq),
(uint8_t*)&chipIdRes,
RFAL_ST25TB_CHIP_ID_LEN,
&rxLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_ST25TB_FWT);
/* Check for valid Select Response */
if((ret == ERR_NONE) && ((rxLen != RFAL_ST25TB_CHIP_ID_LEN) || (chipIdRes != chipId))) {
return ERR_PROTO;
}
return ret;
}
/*******************************************************************************/
ReturnCode rfalSt25tbPollerGetUID(rfalSt25tbUID* UID) {
ReturnCode ret;
uint16_t rxLen;
uint8_t getUidReq;
/* Compute Get UID Request */
getUidReq = RFAL_ST25TB_GET_UID_CMD;
/* Send Select Request */
ret = rfalTransceiveBlockingTxRx(
(uint8_t*)&getUidReq,
RFAL_ST25TB_CMD_LEN,
(uint8_t*)UID,
sizeof(rfalSt25tbUID),
&rxLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_ST25TB_FWT);
/* Check for valid UID Response */
if((ret == ERR_NONE) && (rxLen != RFAL_ST25TB_UID_LEN)) {
return ERR_PROTO;
}
return ret;
}
/*******************************************************************************/
ReturnCode rfalSt25tbPollerCollisionResolution(
uint8_t devLimit,
rfalSt25tbListenDevice* st25tbDevList,
uint8_t* devCnt) {
uint8_t chipId;
ReturnCode ret;
bool detected; /* collision or device was detected */
if((st25tbDevList == NULL) || (devCnt == NULL) || (devLimit == 0U)) {
return ERR_PARAM;
}
*devCnt = 0;
/* Step 1: Send Initiate */
ret = rfalSt25tbPollerInitiate(&chipId);
if(ret == ERR_NONE) {
/* If only 1 answer is detected */
st25tbDevList[*devCnt].chipID = chipId;
st25tbDevList[*devCnt].isDeselected = false;
/* Retrieve its UID and keep it Selected*/
ret = rfalSt25tbPollerSelect(chipId);
if(ERR_NONE == ret) {
ret = rfalSt25tbPollerGetUID(&st25tbDevList[*devCnt].UID);
}
if(ERR_NONE == ret) {
(*devCnt)++;
}
}
/* Always proceed to Pcall16 anticollision as phase differences of tags can lead to no tag recognized, even if there is one */
if(*devCnt < devLimit) {
/* Multiple device responses */
do {
detected = rfalSt25tbPollerDoCollisionResolution(devLimit, st25tbDevList, devCnt);
} while((detected == true) && (*devCnt < devLimit));
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode rfalSt25tbPollerReadBlock(uint8_t blockAddress, rfalSt25tbBlock* blockData) {
ReturnCode ret;
uint16_t rxLen;
rfalSt25tbReadBlockReq readBlockReq;
/* Compute Read Block Request */
readBlockReq.cmd = RFAL_ST25TB_READ_BLOCK_CMD;
readBlockReq.address = blockAddress;
/* Send Read Block Request */
ret = rfalTransceiveBlockingTxRx(
(uint8_t*)&readBlockReq,
sizeof(rfalSt25tbReadBlockReq),
(uint8_t*)blockData,
sizeof(rfalSt25tbBlock),
&rxLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_ST25TB_FWT);
/* Check for valid UID Response */
if((ret == ERR_NONE) && (rxLen != RFAL_ST25TB_BLOCK_LEN)) {
return ERR_PROTO;
}
return ret;
}
/*******************************************************************************/
ReturnCode rfalSt25tbPollerWriteBlock(uint8_t blockAddress, const rfalSt25tbBlock* blockData) {
ReturnCode ret;
uint16_t rxLen;
rfalSt25tbWriteBlockReq writeBlockReq;
rfalSt25tbBlock tmpBlockData;
/* Compute Write Block Request */
writeBlockReq.cmd = RFAL_ST25TB_WRITE_BLOCK_CMD;
writeBlockReq.address = blockAddress;
ST_MEMCPY(&writeBlockReq.data, blockData, RFAL_ST25TB_BLOCK_LEN);
/* Send Write Block Request */
ret = rfalTransceiveBlockingTxRx(
(uint8_t*)&writeBlockReq,
sizeof(rfalSt25tbWriteBlockReq),
tmpBlockData,
RFAL_ST25TB_BLOCK_LEN,
&rxLen,
RFAL_TXRX_FLAGS_DEFAULT,
(RFAL_ST25TB_FWT + RFAL_ST25TB_TW));
/* Check if there was any error besides timeout */
if(ret != ERR_TIMEOUT) {
/* Check if an unexpected answer was received */
if(ret == ERR_NONE) {
return ERR_PROTO;
}
/* Check whether a transmission error occurred */
if((ret != ERR_CRC) && (ret != ERR_FRAMING) && (ret != ERR_NOMEM) &&
(ret != ERR_RF_COLLISION)) {
return ret;
}
/* If a transmission error occurred (maybe noise while committing data) wait maximum programming time and verify data afterwards */
rfalSetGT((RFAL_ST25TB_FWT + RFAL_ST25TB_TW));
rfalFieldOnAndStartGT();
}
ret = rfalSt25tbPollerReadBlock(blockAddress, &tmpBlockData);
if(ret == ERR_NONE) {
if(ST_BYTECMP(&tmpBlockData, blockData, RFAL_ST25TB_BLOCK_LEN) == 0) {
return ERR_NONE;
}
return ERR_PROTO;
}
return ret;
}
/*******************************************************************************/
ReturnCode rfalSt25tbPollerCompletion(void) {
uint8_t completionReq;
/* Compute Completion Request */
completionReq = RFAL_ST25TB_COMPLETION_CMD;
/* Send Completion Request, no response is expected */
return rfalTransceiveBlockingTxRx(
(uint8_t*)&completionReq,
RFAL_ST25TB_CMD_LEN,
NULL,
0,
NULL,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_ST25TB_FWT);
}
/*******************************************************************************/
ReturnCode rfalSt25tbPollerResetToInventory(void) {
uint8_t resetInvReq;
/* Compute Completion Request */
resetInvReq = RFAL_ST25TB_RESET_INV_CMD;
/* Send Completion Request, no response is expected */
return rfalTransceiveBlockingTxRx(
(uint8_t*)&resetInvReq,
RFAL_ST25TB_CMD_LEN,
NULL,
0,
NULL,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_ST25TB_FWT);
}
#endif /* RFAL_FEATURE_ST25TB */
-818
View File
@@ -1,818 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_st25xv.c
*
* \author Gustavo Patricio
*
* \brief NFC-V ST25 NFC-V Tag specific features
*
* This module provides support for ST's specific features available on
* NFC-V (ISO15693) tag families: ST25D, ST25TV, M24LR
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "rfal_st25xv.h"
#include "rfal_nfcv.h"
#include "utils.h"
/*
******************************************************************************
* ENABLE SWITCH
******************************************************************************
*/
#ifndef RFAL_FEATURE_ST25xV
#define RFAL_FEATURE_ST25xV false /* ST25xV module configuration missing. Disabled by default */
#endif
#if RFAL_FEATURE_ST25xV
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_ST25xV_READ_CONFIG_LEN \
2U /*!< READ CONFIGURATION length */
#define RFAL_ST25xV_READ_MSG_LEN_LEN \
2U /*!< READ MESSAGE LENGTH length */
#define RFAL_ST25xV_CONF_POINTER_LEN \
1U /*!< READ/WRITE CONFIGURATION Pointer length */
#define RFAL_ST25xV_CONF_REGISTER_LEN \
1U /*!< READ/WRITE CONFIGURATION Register length */
#define RFAL_ST25xV_PWDNUM_LEN \
1U /*!< Password Number length */
#define RFAL_ST25xV_PWD_LEN \
8U /*!< Password length */
#define RFAL_ST25xV_MBPOINTER_LEN \
1U /*!< Read Message MBPointer length */
#define RFAL_ST25xV_NUMBYTES_LEN \
1U /*!< Read Message Number of Bytes length */
#define RFAL_ST25TV02K_TBOOT_RF \
1U /*!< RF Boot time (Minimum time from carrier generation to first data) */
#define RFAL_ST25TV02K_TRF_OFF \
2U /*!< RF OFF time */
#define RFAL_ST25xV_FDT_POLL_MAX \
rfalConvMsTo1fc(20) /*!< Maximum Wait time FDTV,EOF 20 ms Digital 2.1 B.5 */
#define RFAL_NFCV_FLAG_POS \
0U /*!< Flag byte position */
#define RFAL_NFCV_FLAG_LEN \
1U /*!< Flag byte length */
/*
******************************************************************************
* LOCAL FUNCTION PROTOTYPES
******************************************************************************
*/
static ReturnCode rfalST25xVPollerGenericReadConfiguration(
uint8_t cmd,
uint8_t flags,
const uint8_t* uid,
uint8_t pointer,
uint8_t* regValue);
static ReturnCode rfalST25xVPollerGenericWriteConfiguration(
uint8_t cmd,
uint8_t flags,
const uint8_t* uid,
uint8_t pointer,
uint8_t regValue);
static ReturnCode rfalST25xVPollerGenericReadMessageLength(
uint8_t cmd,
uint8_t flags,
const uint8_t* uid,
uint8_t* msgLen);
static ReturnCode rfalST25xVPollerGenericReadMessage(
uint8_t cmd,
uint8_t flags,
const uint8_t* uid,
uint8_t mbPointer,
uint8_t numBytes,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen);
static ReturnCode rfalST25xVPollerGenericWriteMessage(
uint8_t cmd,
uint8_t flags,
const uint8_t* uid,
uint8_t msgLen,
const uint8_t* msgData,
uint8_t* txBuf,
uint16_t txBufLen);
/*
******************************************************************************
* LOCAL FUNCTIONS
******************************************************************************
*/
/*******************************************************************************/
static ReturnCode rfalST25xVPollerGenericReadConfiguration(
uint8_t cmd,
uint8_t flags,
const uint8_t* uid,
uint8_t pointer,
uint8_t* regValue) {
ReturnCode ret;
uint8_t p;
uint16_t rcvLen;
rfalNfcvGenericRes res;
if(regValue == NULL) {
return ERR_PARAM;
}
p = pointer;
ret = rfalNfcvPollerTransceiveReq(
cmd,
flags,
RFAL_NFCV_ST_IC_MFG_CODE,
uid,
&p,
sizeof(uint8_t),
(uint8_t*)&res,
sizeof(rfalNfcvGenericRes),
&rcvLen);
if(ret == ERR_NONE) {
if(rcvLen < RFAL_ST25xV_READ_CONFIG_LEN) {
ret = ERR_PROTO;
} else {
*regValue = res.data[0];
}
}
return ret;
}
/*******************************************************************************/
static ReturnCode rfalST25xVPollerGenericWriteConfiguration(
uint8_t cmd,
uint8_t flags,
const uint8_t* uid,
uint8_t pointer,
uint8_t regValue) {
uint8_t data[RFAL_ST25xV_CONF_POINTER_LEN + RFAL_ST25xV_CONF_REGISTER_LEN];
uint8_t dataLen;
uint16_t rcvLen;
rfalNfcvGenericRes res;
dataLen = 0U;
data[dataLen++] = pointer;
data[dataLen++] = regValue;
return rfalNfcvPollerTransceiveReq(
cmd,
flags,
RFAL_NFCV_ST_IC_MFG_CODE,
uid,
data,
dataLen,
(uint8_t*)&res,
sizeof(rfalNfcvGenericRes),
&rcvLen);
}
/*******************************************************************************/
static ReturnCode rfalST25xVPollerGenericReadMessageLength(
uint8_t cmd,
uint8_t flags,
const uint8_t* uid,
uint8_t* msgLen) {
ReturnCode ret;
uint16_t rcvLen;
rfalNfcvGenericRes res;
if(msgLen == NULL) {
return ERR_PARAM;
}
ret = rfalNfcvPollerTransceiveReq(
cmd,
flags,
RFAL_NFCV_ST_IC_MFG_CODE,
uid,
NULL,
0,
(uint8_t*)&res,
sizeof(rfalNfcvGenericRes),
&rcvLen);
if(ret == ERR_NONE) {
if(rcvLen < RFAL_ST25xV_READ_MSG_LEN_LEN) {
ret = ERR_PROTO;
} else {
*msgLen = res.data[0];
}
}
return ret;
}
/*******************************************************************************/
static ReturnCode rfalST25xVPollerGenericReadMessage(
uint8_t cmd,
uint8_t flags,
const uint8_t* uid,
uint8_t mbPointer,
uint8_t numBytes,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen) {
uint8_t data[RFAL_ST25xV_MBPOINTER_LEN + RFAL_ST25xV_NUMBYTES_LEN];
uint8_t dataLen;
dataLen = 0;
/* Compute Request Data */
data[dataLen++] = mbPointer;
data[dataLen++] = numBytes;
return rfalNfcvPollerTransceiveReq(
cmd, flags, RFAL_NFCV_ST_IC_MFG_CODE, uid, data, dataLen, rxBuf, rxBufLen, rcvLen);
}
/*******************************************************************************/
static ReturnCode rfalST25xVPollerGenericWriteMessage(
uint8_t cmd,
uint8_t flags,
const uint8_t* uid,
uint8_t msgLen,
const uint8_t* msgData,
uint8_t* txBuf,
uint16_t txBufLen) {
ReturnCode ret;
uint8_t reqFlag;
uint16_t msgIt;
rfalBitRate rxBR;
bool fastMode;
rfalNfcvGenericRes res;
uint16_t rcvLen;
/* Calculate required Tx buf length: Mfg Code UID MSGLen MSGLen+1 */
msgIt =
(uint16_t)(msgLen + sizeof(flags) + sizeof(cmd) + 1U + ((uid != NULL) ? RFAL_NFCV_UID_LEN : 0U) + 1U + 1U);
/* Note: MSGlength parameter of the command is the number of Data bytes minus - 1 (00 for 1 byte of data, FFh for 256 bytes of data) */
/* Check for valid parameters */
if((txBuf == NULL) || (msgData == NULL) || (txBufLen < msgIt)) {
return ERR_PARAM;
}
msgIt = 0;
fastMode = false;
/* Check if the command is an ST's Fast command */
if(cmd == (uint8_t)RFAL_NFCV_CMD_FAST_WRITE_MESSAGE) {
/* Store current Rx bit rate and move to fast mode */
rfalGetBitRate(NULL, &rxBR);
rfalSetBitRate(RFAL_BR_KEEP, RFAL_BR_52p97);
fastMode = true;
}
/* Compute Request Command */
reqFlag =
(uint8_t)(flags & (~((uint32_t)RFAL_NFCV_REQ_FLAG_ADDRESS) & ~((uint32_t)RFAL_NFCV_REQ_FLAG_SELECT)));
reqFlag |=
((uid != NULL) ? (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS : (uint8_t)RFAL_NFCV_REQ_FLAG_SELECT);
txBuf[msgIt++] = reqFlag;
txBuf[msgIt++] = cmd;
txBuf[msgIt++] = RFAL_NFCV_ST_IC_MFG_CODE;
if(uid != NULL) {
ST_MEMCPY(&txBuf[msgIt], uid, RFAL_NFCV_UID_LEN);
msgIt += RFAL_NFCV_UID_LEN;
}
txBuf[msgIt++] = msgLen;
ST_MEMCPY(
&txBuf[msgIt],
msgData,
(uint16_t)(msgLen + (uint16_t)1U)); /* Message Data contains (MSGLength + 1) bytes */
msgIt += (uint16_t)(msgLen + (uint16_t)1U);
/* Transceive Command */
ret = rfalTransceiveBlockingTxRx(
txBuf,
msgIt,
(uint8_t*)&res,
sizeof(rfalNfcvGenericRes),
&rcvLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_ST25xV_FDT_POLL_MAX);
/* Restore Rx BitRate */
if(fastMode) {
rfalSetBitRate(RFAL_BR_KEEP, rxBR);
}
if(ret != ERR_NONE) {
return ret;
}
/* Check if the response minimum length has been received */
if(rcvLen < (uint8_t)RFAL_NFCV_FLAG_LEN) {
return ERR_PROTO;
}
/* Check if an error has been signalled */
if((res.RES_FLAG & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U) {
return ERR_PROTO;
}
return ERR_NONE;
}
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
/*******************************************************************************/
ReturnCode rfalST25xVPollerM24LRReadSingleBlock(
uint8_t flags,
const uint8_t* uid,
uint16_t blockNum,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen) {
uint8_t data[RFAL_NFCV_BLOCKNUM_M24LR_LEN];
uint8_t dataLen;
dataLen = 0;
/* Compute Request Data */
data[dataLen++] = (uint8_t)blockNum; /* Set M24LR Block Number (16 bits) LSB */
data[dataLen++] = (uint8_t)(blockNum >> 8U); /* Set M24LR Block Number (16 bits) MSB */
return rfalNfcvPollerTransceiveReq(
RFAL_NFCV_CMD_READ_SINGLE_BLOCK,
(flags | (uint8_t)RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT),
RFAL_NFCV_PARAM_SKIP,
uid,
data,
dataLen,
rxBuf,
rxBufLen,
rcvLen);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerM24LRWriteSingleBlock(
uint8_t flags,
const uint8_t* uid,
uint16_t blockNum,
const uint8_t* wrData,
uint8_t blockLen) {
uint8_t data[(RFAL_NFCV_BLOCKNUM_M24LR_LEN + RFAL_NFCV_MAX_BLOCK_LEN)];
uint8_t dataLen;
uint16_t rcvLen;
rfalNfcvGenericRes res;
/* Check for valid parameters */
if((blockLen == 0U) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) || (wrData == NULL)) {
return ERR_PARAM;
}
dataLen = 0U;
/* Compute Request Data */
data[dataLen++] = (uint8_t)blockNum; /* Set M24LR Block Number (16 bits) LSB */
data[dataLen++] = (uint8_t)(blockNum >> 8U); /* Set M24LR Block Number (16 bits) MSB */
ST_MEMCPY(&data[dataLen], wrData, blockLen); /* Append Block data to write */
dataLen += blockLen;
return rfalNfcvPollerTransceiveReq(
RFAL_NFCV_CMD_WRITE_SINGLE_BLOCK,
(flags | (uint8_t)RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT),
RFAL_NFCV_PARAM_SKIP,
uid,
data,
dataLen,
(uint8_t*)&res,
sizeof(rfalNfcvGenericRes),
&rcvLen);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerM24LRReadMultipleBlocks(
uint8_t flags,
const uint8_t* uid,
uint16_t firstBlockNum,
uint8_t numOfBlocks,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen) {
uint8_t data[(RFAL_NFCV_BLOCKNUM_M24LR_LEN + RFAL_NFCV_BLOCKNUM_M24LR_LEN)];
uint8_t dataLen;
dataLen = 0U;
/* Compute Request Data */
data[dataLen++] = (uint8_t)firstBlockNum; /* Set M24LR Block Number (16 bits) LSB */
data[dataLen++] = (uint8_t)(firstBlockNum >> 8U); /* Set M24LR Block Number (16 bits) MSB */
data[dataLen++] = numOfBlocks; /* Set number of blocks to read */
return rfalNfcvPollerTransceiveReq(
RFAL_NFCV_CMD_READ_MULTIPLE_BLOCKS,
(flags | (uint8_t)RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT),
RFAL_NFCV_PARAM_SKIP,
uid,
data,
dataLen,
rxBuf,
rxBufLen,
rcvLen);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerFastReadSingleBlock(
uint8_t flags,
const uint8_t* uid,
uint8_t blockNum,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen) {
uint8_t bn;
bn = blockNum;
return rfalNfcvPollerTransceiveReq(
RFAL_NFCV_CMD_FAST_READ_SINGLE_BLOCK,
flags,
RFAL_NFCV_ST_IC_MFG_CODE,
uid,
&bn,
sizeof(uint8_t),
rxBuf,
rxBufLen,
rcvLen);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerM24LRFastReadSingleBlock(
uint8_t flags,
const uint8_t* uid,
uint16_t blockNum,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen) {
uint8_t data[RFAL_NFCV_BLOCKNUM_M24LR_LEN];
uint8_t dataLen;
dataLen = 0;
/* Compute Request Data */
data[dataLen++] = (uint8_t)blockNum; /* Set M24LR Block Number (16 bits) LSB */
data[dataLen++] = (uint8_t)(blockNum >> 8U); /* Set M24LR Block Number (16 bits) MSB */
return rfalNfcvPollerTransceiveReq(
RFAL_NFCV_CMD_FAST_READ_SINGLE_BLOCK,
(flags | (uint8_t)RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT),
RFAL_NFCV_ST_IC_MFG_CODE,
uid,
data,
dataLen,
rxBuf,
rxBufLen,
rcvLen);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerM24LRFastReadMultipleBlocks(
uint8_t flags,
const uint8_t* uid,
uint16_t firstBlockNum,
uint8_t numOfBlocks,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen) {
uint8_t data[(RFAL_NFCV_BLOCKNUM_M24LR_LEN + RFAL_NFCV_BLOCKNUM_M24LR_LEN)];
uint8_t dataLen;
dataLen = 0U;
/* Compute Request Data */
data[dataLen++] = (uint8_t)firstBlockNum; /* Set M24LR Block Number (16 bits) LSB */
data[dataLen++] = (uint8_t)(firstBlockNum >> 8U); /* Set M24LR Block Number (16 bits) MSB */
data[dataLen++] = numOfBlocks; /* Set number of blocks to read */
return rfalNfcvPollerTransceiveReq(
RFAL_NFCV_CMD_FAST_READ_MULTIPLE_BLOCKS,
(flags | (uint8_t)RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT),
RFAL_NFCV_ST_IC_MFG_CODE,
uid,
data,
dataLen,
rxBuf,
rxBufLen,
rcvLen);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerFastReadMultipleBlocks(
uint8_t flags,
const uint8_t* uid,
uint8_t firstBlockNum,
uint8_t numOfBlocks,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen) {
uint8_t data[(RFAL_NFCV_BLOCKNUM_LEN + RFAL_NFCV_BLOCKNUM_LEN)];
uint8_t dataLen;
dataLen = 0U;
/* Compute Request Data */
data[dataLen++] = firstBlockNum; /* Set first Block Number */
data[dataLen++] = numOfBlocks; /* Set number of blocks to read */
return rfalNfcvPollerTransceiveReq(
RFAL_NFCV_CMD_FAST_READ_MULTIPLE_BLOCKS,
flags,
RFAL_NFCV_ST_IC_MFG_CODE,
uid,
data,
dataLen,
rxBuf,
rxBufLen,
rcvLen);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerFastExtendedReadSingleBlock(
uint8_t flags,
const uint8_t* uid,
uint16_t blockNum,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen) {
uint8_t data[RFAL_NFCV_BLOCKNUM_EXTENDED_LEN];
uint8_t dataLen;
dataLen = 0U;
/* Compute Request Data */
data[dataLen++] = (uint8_t)
blockNum; /* TS T5T 1.0 BNo is considered as a multi-byte field. TS T5T 1.0 5.1.1.13 multi-byte field follows [DIGITAL]. [DIGITAL] 9.3.1 A multiple byte field is transmitted LSB first. */
data[dataLen++] = (uint8_t)((blockNum >> 8U) & 0xFFU);
return rfalNfcvPollerTransceiveReq(
RFAL_NFCV_CMD_FAST_EXTENDED_READ_SINGLE_BLOCK,
flags,
RFAL_NFCV_ST_IC_MFG_CODE,
uid,
data,
dataLen,
rxBuf,
rxBufLen,
rcvLen);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerFastExtReadMultipleBlocks(
uint8_t flags,
const uint8_t* uid,
uint16_t firstBlockNum,
uint16_t numOfBlocks,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen) {
uint8_t data[(RFAL_NFCV_BLOCKNUM_EXTENDED_LEN + RFAL_NFCV_BLOCKNUM_EXTENDED_LEN)];
uint8_t dataLen;
dataLen = 0U;
/* Compute Request Data */
data[dataLen++] = (uint8_t)((firstBlockNum >> 0U) & 0xFFU);
data[dataLen++] = (uint8_t)((firstBlockNum >> 8U) & 0xFFU);
data[dataLen++] = (uint8_t)((numOfBlocks >> 0U) & 0xFFU);
data[dataLen++] = (uint8_t)((numOfBlocks >> 8U) & 0xFFU);
return rfalNfcvPollerTransceiveReq(
RFAL_NFCV_CMD_FAST_EXTENDED_READ_MULTIPLE_BLOCKS,
flags,
RFAL_NFCV_ST_IC_MFG_CODE,
uid,
data,
dataLen,
rxBuf,
rxBufLen,
rcvLen);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerReadConfiguration(
uint8_t flags,
const uint8_t* uid,
uint8_t pointer,
uint8_t* regValue) {
return rfalST25xVPollerGenericReadConfiguration(
RFAL_NFCV_CMD_READ_CONFIGURATION, flags, uid, pointer, regValue);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerWriteConfiguration(
uint8_t flags,
const uint8_t* uid,
uint8_t pointer,
uint8_t regValue) {
return rfalST25xVPollerGenericWriteConfiguration(
RFAL_NFCV_CMD_WRITE_CONFIGURATION, flags, uid, pointer, regValue);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerReadDynamicConfiguration(
uint8_t flags,
const uint8_t* uid,
uint8_t pointer,
uint8_t* regValue) {
return rfalST25xVPollerGenericReadConfiguration(
RFAL_NFCV_CMD_READ_DYN_CONFIGURATION, flags, uid, pointer, regValue);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerWriteDynamicConfiguration(
uint8_t flags,
const uint8_t* uid,
uint8_t pointer,
uint8_t regValue) {
return rfalST25xVPollerGenericWriteConfiguration(
RFAL_NFCV_CMD_WRITE_DYN_CONFIGURATION, flags, uid, pointer, regValue);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerFastReadDynamicConfiguration(
uint8_t flags,
const uint8_t* uid,
uint8_t pointer,
uint8_t* regValue) {
return rfalST25xVPollerGenericReadConfiguration(
RFAL_NFCV_CMD_FAST_READ_DYN_CONFIGURATION, flags, uid, pointer, regValue);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerFastWriteDynamicConfiguration(
uint8_t flags,
const uint8_t* uid,
uint8_t pointer,
uint8_t regValue) {
return rfalST25xVPollerGenericWriteConfiguration(
RFAL_NFCV_CMD_FAST_WRITE_DYN_CONFIGURATION, flags, uid, pointer, regValue);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerPresentPassword(
uint8_t flags,
const uint8_t* uid,
uint8_t pwdNum,
const uint8_t* pwd,
uint8_t pwdLen) {
uint8_t data[RFAL_ST25xV_PWDNUM_LEN + RFAL_ST25xV_PWD_LEN];
uint8_t dataLen;
uint16_t rcvLen;
rfalNfcvGenericRes res;
if((pwdLen > RFAL_ST25xV_PWD_LEN) || (pwd == NULL)) {
return ERR_PARAM;
}
dataLen = 0U;
data[dataLen++] = pwdNum;
if(pwdLen > 0U) {
ST_MEMCPY(&data[dataLen], pwd, pwdLen);
}
dataLen += pwdLen;
return rfalNfcvPollerTransceiveReq(
RFAL_NFCV_CMD_PRESENT_PASSWORD,
flags,
RFAL_NFCV_ST_IC_MFG_CODE,
uid,
data,
dataLen,
(uint8_t*)&res,
sizeof(rfalNfcvGenericRes),
&rcvLen);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerGetRandomNumber(
uint8_t flags,
const uint8_t* uid,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen) {
rfalFieldOff();
platformDelay(RFAL_ST25TV02K_TRF_OFF);
rfalNfcvPollerInitialize();
rfalFieldOnAndStartGT();
platformDelay(RFAL_ST25TV02K_TBOOT_RF);
return rfalNfcvPollerTransceiveReq(
RFAL_NFCV_CMD_GET_RANDOM_NUMBER,
flags,
RFAL_NFCV_ST_IC_MFG_CODE,
uid,
NULL,
0U,
rxBuf,
rxBufLen,
rcvLen);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerWriteMessage(
uint8_t flags,
const uint8_t* uid,
uint8_t msgLen,
const uint8_t* msgData,
uint8_t* txBuf,
uint16_t txBufLen) {
return rfalST25xVPollerGenericWriteMessage(
RFAL_NFCV_CMD_WRITE_MESSAGE, flags, uid, msgLen, msgData, txBuf, txBufLen);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerFastWriteMessage(
uint8_t flags,
const uint8_t* uid,
uint8_t msgLen,
const uint8_t* msgData,
uint8_t* txBuf,
uint16_t txBufLen) {
return rfalST25xVPollerGenericWriteMessage(
RFAL_NFCV_CMD_FAST_WRITE_MESSAGE, flags, uid, msgLen, msgData, txBuf, txBufLen);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerReadMessageLength(uint8_t flags, const uint8_t* uid, uint8_t* msgLen) {
return rfalST25xVPollerGenericReadMessageLength(
RFAL_NFCV_CMD_READ_MESSAGE_LENGTH, flags, uid, msgLen);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerFastReadMsgLength(uint8_t flags, const uint8_t* uid, uint8_t* msgLen) {
return rfalST25xVPollerGenericReadMessageLength(
RFAL_NFCV_CMD_FAST_READ_MESSAGE_LENGTH, flags, uid, msgLen);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerReadMessage(
uint8_t flags,
const uint8_t* uid,
uint8_t mbPointer,
uint8_t numBytes,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen) {
return rfalST25xVPollerGenericReadMessage(
RFAL_NFCV_CMD_READ_MESSAGE, flags, uid, mbPointer, numBytes, rxBuf, rxBufLen, rcvLen);
}
/*******************************************************************************/
ReturnCode rfalST25xVPollerFastReadMessage(
uint8_t flags,
const uint8_t* uid,
uint8_t mbPointer,
uint8_t numBytes,
uint8_t* rxBuf,
uint16_t rxBufLen,
uint16_t* rcvLen) {
return rfalST25xVPollerGenericReadMessage(
RFAL_NFCV_CMD_FAST_READ_MESSAGE, flags, uid, mbPointer, numBytes, rxBuf, rxBufLen, rcvLen);
}
#endif /* RFAL_FEATURE_ST25xV */
-233
View File
@@ -1,233 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_t1t.c
*
* \author Gustavo Patricio
*
* \brief Provides NFC-A T1T convenience methods and definitions
*
* This module provides an interface to perform as a NFC-A Reader/Writer
* to handle a Type 1 Tag T1T (Topaz)
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "rfal_t1t.h"
#include "utils.h"
/*
******************************************************************************
* ENABLE SWITCH
******************************************************************************
*/
#ifndef RFAL_FEATURE_T1T
#define RFAL_FEATURE_T1T false /* T1T module configuration missing. Disabled by default */
#endif
#if RFAL_FEATURE_T1T
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_T1T_DRD_READ \
(1236U * 2U) /*!< DRD for Reads with n=9 => 1236/fc ~= 91 us T1T 1.2 4.4.2 */
#define RFAL_T1T_DRD_WRITE \
36052U /*!< DRD for Write with n=281 => 36052/fc ~= 2659 us T1T 1.2 4.4.2 */
#define RFAL_T1T_DRD_WRITE_E \
70996U /*!< DRD for Write/Erase with n=554 => 70996/fc ~= 5236 us T1T 1.2 4.4.2 */
#define RFAL_T1T_RID_RES_HR0_VAL \
0x10U /*!< HR0 indicating NDEF support Digital 2.0 (Candidate) 11.6.2.1 */
#define RFAL_T1T_RID_RES_HR0_MASK \
0xF0U /*!< HR0 most significant nibble mask */
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
/*! NFC-A T1T (Topaz) RID_REQ Digital 1.1 10.6.1 & Table 49 */
typedef struct {
uint8_t cmd; /*!< T1T cmd: RID */
uint8_t add; /*!< ADD: undefined value */
uint8_t data; /*!< DATA: undefined value */
uint8_t uid[RFAL_T1T_UID_LEN]; /*!< UID-echo: undefined value */
} rfalT1TRidReq;
/*! NFC-A T1T (Topaz) RALL_REQ T1T 1.2 Table 4 */
typedef struct {
uint8_t cmd; /*!< T1T cmd: RALL */
uint8_t add1; /*!< ADD: 0x00 */
uint8_t add0; /*!< ADD: 0x00 */
uint8_t uid[RFAL_T1T_UID_LEN]; /*!< UID */
} rfalT1TRallReq;
/*! NFC-A T1T (Topaz) WRITE_REQ T1T 1.2 Table 4 */
typedef struct {
uint8_t cmd; /*!< T1T cmd: RALL */
uint8_t add; /*!< ADD */
uint8_t data; /*!< DAT */
uint8_t uid[RFAL_T1T_UID_LEN]; /*!< UID */
} rfalT1TWriteReq;
/*! NFC-A T1T (Topaz) WRITE_RES T1T 1.2 Table 4 */
typedef struct {
uint8_t add; /*!< ADD */
uint8_t data; /*!< DAT */
} rfalT1TWriteRes;
/*
******************************************************************************
* LOCAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
ReturnCode rfalT1TPollerInitialize(void) {
ReturnCode ret;
EXIT_ON_ERR(ret, rfalSetMode(RFAL_MODE_POLL_NFCA_T1T, RFAL_BR_106, RFAL_BR_106));
rfalSetErrorHandling(RFAL_ERRORHANDLING_NFC);
rfalSetGT(
RFAL_GT_NONE); /* T1T should only be initialized after NFC-A mode, therefore the GT has been fulfilled */
rfalSetFDTListen(
RFAL_FDT_LISTEN_NFCA_POLLER); /* T1T uses NFC-A FDT Listen with n=9 Digital 1.1 10.7.2 */
rfalSetFDTPoll(RFAL_FDT_POLL_NFCA_T1T_POLLER);
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode rfalT1TPollerRid(rfalT1TRidRes* ridRes) {
ReturnCode ret;
rfalT1TRidReq ridReq;
uint16_t rcvdLen;
if(ridRes == NULL) {
return ERR_PARAM;
}
/* Compute RID command and set Undefined Values to 0x00 Digital 1.1 10.6.1 */
ST_MEMSET(&ridReq, 0x00, sizeof(rfalT1TRidReq));
ridReq.cmd = (uint8_t)RFAL_T1T_CMD_RID;
EXIT_ON_ERR(
ret,
rfalTransceiveBlockingTxRx(
(uint8_t*)&ridReq,
sizeof(rfalT1TRidReq),
(uint8_t*)ridRes,
sizeof(rfalT1TRidRes),
&rcvdLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_T1T_DRD_READ));
/* Check expected RID response length and the HR0 Digital 2.0 (Candidate) 11.6.2.1 */
if((rcvdLen != sizeof(rfalT1TRidRes)) ||
((ridRes->hr0 & RFAL_T1T_RID_RES_HR0_MASK) != RFAL_T1T_RID_RES_HR0_VAL)) {
return ERR_PROTO;
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode
rfalT1TPollerRall(const uint8_t* uid, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t* rxRcvdLen) {
rfalT1TRallReq rallReq;
if((rxBuf == NULL) || (uid == NULL) || (rxRcvdLen == NULL)) {
return ERR_PARAM;
}
/* Compute RALL command and set Add to 0x00 */
ST_MEMSET(&rallReq, 0x00, sizeof(rfalT1TRallReq));
rallReq.cmd = (uint8_t)RFAL_T1T_CMD_RALL;
ST_MEMCPY(rallReq.uid, uid, RFAL_T1T_UID_LEN);
return rfalTransceiveBlockingTxRx(
(uint8_t*)&rallReq,
sizeof(rfalT1TRallReq),
(uint8_t*)rxBuf,
rxBufLen,
rxRcvdLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_T1T_DRD_READ);
}
/*******************************************************************************/
ReturnCode rfalT1TPollerWrite(const uint8_t* uid, uint8_t address, uint8_t data) {
rfalT1TWriteReq writeReq;
rfalT1TWriteRes writeRes;
uint16_t rxRcvdLen;
ReturnCode err;
if(uid == NULL) {
return ERR_PARAM;
}
writeReq.cmd = (uint8_t)RFAL_T1T_CMD_WRITE_E;
writeReq.add = address;
writeReq.data = data;
ST_MEMCPY(writeReq.uid, uid, RFAL_T1T_UID_LEN);
err = rfalTransceiveBlockingTxRx(
(uint8_t*)&writeReq,
sizeof(rfalT1TWriteReq),
(uint8_t*)&writeRes,
sizeof(rfalT1TWriteRes),
&rxRcvdLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_T1T_DRD_WRITE_E);
if(err == ERR_NONE) {
if((writeReq.add != writeRes.add) || (writeReq.data != writeRes.data) ||
(rxRcvdLen != sizeof(rfalT1TWriteRes))) {
return ERR_PROTO;
}
}
return err;
}
#endif /* RFAL_FEATURE_T1T */
-253
View File
@@ -1,253 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_t2t.c
*
* \author
*
* \brief Provides NFC-A T2T convenience methods and definitions
*
* This module provides an interface to perform as a NFC-A Reader/Writer
* to handle a Type 2 Tag T2T
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "rfal_t2t.h"
#include "utils.h"
/*
******************************************************************************
* ENABLE SWITCH
******************************************************************************
*/
#ifndef RFAL_FEATURE_T2T
#define RFAL_FEATURE_T2T false /* T2T module configuration missing. Disabled by default */
#endif
#if RFAL_FEATURE_T2T
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_FDT_POLL_READ_MAX \
rfalConvMsTo1fc( \
5U) /*!< Maximum Wait time for Read command as defined in TS T2T 1.0 table 18 */
#define RFAL_FDT_POLL_WRITE_MAX \
rfalConvMsTo1fc( \
10U) /*!< Maximum Wait time for Write command as defined in TS T2T 1.0 table 18 */
#define RFAL_FDT_POLL_SL_MAX \
rfalConvMsTo1fc( \
1U) /*!< Maximum Wait time for Sector Select as defined in TS T2T 1.0 table 18 */
#define RFAL_T2T_ACK_NACK_LEN \
1U /*!< Len of NACK in bytes (4 bits) */
#define RFAL_T2T_ACK \
0x0AU /*!< ACK value */
#define RFAL_T2T_ACK_MASK \
0x0FU /*!< ACK value */
#define RFAL_T2T_SECTOR_SELECT_P1_BYTE2 \
0xFFU /*!< Sector Select Packet 1 byte 2 */
#define RFAL_T2T_SECTOR_SELECT_P2_RFU_LEN \
3U /*!< Sector Select RFU length */
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
/*! NFC-A T2T command set T2T 1.0 5.1 */
typedef enum {
RFAL_T2T_CMD_READ = 0x30, /*!< T2T Read */
RFAL_T2T_CMD_WRITE = 0xA2, /*!< T2T Write */
RFAL_T2T_CMD_SECTOR_SELECT = 0xC2 /*!< T2T Sector Select */
} rfalT2Tcmds;
/*! NFC-A T2T READ T2T 1.0 5.2 and table 11 */
typedef struct {
uint8_t code; /*!< Command code */
uint8_t blNo; /*!< Block number */
} rfalT2TReadReq;
/*! NFC-A T2T WRITE T2T 1.0 5.3 and table 12 */
typedef struct {
uint8_t code; /*!< Command code */
uint8_t blNo; /*!< Block number */
uint8_t data[RFAL_T2T_WRITE_DATA_LEN]; /*!< Data */
} rfalT2TWriteReq;
/*! NFC-A T2T SECTOR SELECT Packet 1 T2T 1.0 5.4 and table 13 */
typedef struct {
uint8_t code; /*!< Command code */
uint8_t byte2; /*!< Sector Select Packet 1 byte 2 */
} rfalT2TSectorSelectP1Req;
/*! NFC-A T2T SECTOR SELECT Packet 2 T2T 1.0 5.4 and table 13 */
typedef struct {
uint8_t secNo; /*!< Block number */
uint8_t rfu[RFAL_T2T_SECTOR_SELECT_P2_RFU_LEN]; /*!< Sector Select Packet RFU */
} rfalT2TSectorSelectP2Req;
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
ReturnCode
rfalT2TPollerRead(uint8_t blockNum, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t* rcvLen) {
ReturnCode ret;
rfalT2TReadReq req;
if((rxBuf == NULL) || (rcvLen == NULL)) {
return ERR_PARAM;
}
req.code = (uint8_t)RFAL_T2T_CMD_READ;
req.blNo = blockNum;
/* Transceive Command */
ret = rfalTransceiveBlockingTxRx(
(uint8_t*)&req,
sizeof(rfalT2TReadReq),
rxBuf,
rxBufLen,
rcvLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_FDT_POLL_READ_MAX);
/* T2T 1.0 5.2.1.7 The Reader/Writer SHALL treat a NACK in response to a READ Command as a Protocol Error */
if((ret == ERR_INCOMPLETE_BYTE) && (*rcvLen == RFAL_T2T_ACK_NACK_LEN) &&
((*rxBuf & RFAL_T2T_ACK_MASK) != RFAL_T2T_ACK)) {
return ERR_PROTO;
}
return ret;
}
/*******************************************************************************/
ReturnCode rfalT2TPollerWrite(uint8_t blockNum, const uint8_t* wrData) {
ReturnCode ret;
rfalT2TWriteReq req;
uint8_t res;
uint16_t rxLen;
req.code = (uint8_t)RFAL_T2T_CMD_WRITE;
req.blNo = blockNum;
ST_MEMCPY(req.data, wrData, RFAL_T2T_WRITE_DATA_LEN);
/* Transceive WRITE Command */
ret = rfalTransceiveBlockingTxRx(
(uint8_t*)&req,
sizeof(rfalT2TWriteReq),
&res,
sizeof(uint8_t),
&rxLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_FDT_POLL_READ_MAX);
/* Check for a valid ACK */
if((ret == ERR_INCOMPLETE_BYTE) || (ret == ERR_NONE)) {
ret = ERR_PROTO;
if((rxLen == RFAL_T2T_ACK_NACK_LEN) && ((res & RFAL_T2T_ACK_MASK) == RFAL_T2T_ACK)) {
ret = ERR_NONE;
}
}
return ret;
}
/*******************************************************************************/
ReturnCode rfalT2TPollerSectorSelect(uint8_t sectorNum) {
rfalT2TSectorSelectP1Req p1Req;
rfalT2TSectorSelectP2Req p2Req;
ReturnCode ret;
uint8_t res;
uint16_t rxLen;
/* Compute SECTOR SELECT Packet 1 */
p1Req.code = (uint8_t)RFAL_T2T_CMD_SECTOR_SELECT;
p1Req.byte2 = RFAL_T2T_SECTOR_SELECT_P1_BYTE2;
/* Transceive SECTOR SELECT Packet 1 */
ret = rfalTransceiveBlockingTxRx(
(uint8_t*)&p1Req,
sizeof(rfalT2TSectorSelectP1Req),
&res,
sizeof(uint8_t),
&rxLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_FDT_POLL_SL_MAX);
/* Check and report any transmission error */
if((ret != ERR_INCOMPLETE_BYTE) && (ret != ERR_NONE)) {
return ret;
}
/* Ensure that an ACK was received */
if((ret != ERR_INCOMPLETE_BYTE) || (rxLen != RFAL_T2T_ACK_NACK_LEN) ||
((res & RFAL_T2T_ACK_MASK) != RFAL_T2T_ACK)) {
return ERR_PROTO;
}
/* Compute SECTOR SELECT Packet 2 */
p2Req.secNo = sectorNum;
ST_MEMSET(&p2Req.rfu, 0x00, RFAL_T2T_SECTOR_SELECT_P2_RFU_LEN);
/* Transceive SECTOR SELECT Packet 2 */
ret = rfalTransceiveBlockingTxRx(
(uint8_t*)&p2Req,
sizeof(rfalT2TSectorSelectP2Req),
&res,
sizeof(uint8_t),
&rxLen,
RFAL_TXRX_FLAGS_DEFAULT,
RFAL_FDT_POLL_SL_MAX);
/* T2T 1.0 5.4.1.14 The Reader/Writer SHALL treat any response received before the end of PATT2T,SL,MAX as a Protocol Error */
if((ret == ERR_NONE) || (ret == ERR_INCOMPLETE_BYTE)) {
return ERR_PROTO;
}
/* T2T 1.0 5.4.1.13 The Reader/Writer SHALL treat the transmission of the SECTOR SELECT Command Packet 2 as being successful when it receives no response until PATT2T,SL,MAX. */
if(ret == ERR_TIMEOUT) {
return ERR_NONE;
}
return ret;
}
#endif /* RFAL_FEATURE_T2T */
-397
View File
@@ -1,397 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file rfal_t4t.h
*
* \author Gustavo Patricio
*
* \brief Provides convenience methods and definitions for T4T (ISO7816-4)
*
* This module provides an interface to exchange T4T APDUs according to
* NFC Forum T4T and ISO7816-4
*
* This implementation was based on the following specs:
* - ISO/IEC 7816-4 3rd Edition 2013-04-15
* - NFC Forum T4T Technical Specification 1.0 2017-08-28
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "rfal_t4t.h"
#include "utils.h"
/*
******************************************************************************
* ENABLE SWITCH
******************************************************************************
*/
#ifndef RFAL_FEATURE_T4T
#define RFAL_FEATURE_T4T false /* T4T module configuration missing. Disabled by default */
#endif
#if RFAL_FEATURE_T4T
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_T4T_OFFSET_DO 0x54U /*!< Tag value for offset BER-TLV data object */
#define RFAL_T4T_LENGTH_DO 0x03U /*!< Len value for offset BER-TLV data object */
#define RFAL_T4T_DATA_DO 0x53U /*!< Tag value for data BER-TLV data object */
#define RFAL_T4T_MAX_LC 255U /*!< Maximum Lc value for short Lc coding */
/*
******************************************************************************
* GLOBAL TYPES
******************************************************************************
*/
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
/*
******************************************************************************
* LOCAL VARIABLES
******************************************************************************
*/
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
/*******************************************************************************/
ReturnCode rfalT4TPollerComposeCAPDU(const rfalT4tCApduParam* apduParam) {
uint8_t hdrLen;
uint16_t msgIt;
if((apduParam == NULL) || (apduParam->cApduBuf == NULL) || (apduParam->cApduLen == NULL)) {
return ERR_PARAM;
}
msgIt = 0;
*(apduParam->cApduLen) = 0;
/*******************************************************************************/
/* Compute Command-APDU according to the format T4T 1.0 5.1.2 & ISO7816-4 2013 Table 1 */
/* Check if Data is present */
if(apduParam->LcFlag) {
if(apduParam->Lc == 0U) {
/* Extended field coding not supported */
return ERR_PARAM;
}
/* Check whether requested Lc fits */
#pragma GCC diagnostic ignored "-Wtype-limits"
if((uint16_t)apduParam->Lc >
(uint16_t)(RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN - RFAL_T4T_LE_LEN)) {
return ERR_PARAM; /* PRQA S 2880 # MISRA 2.1 - Unreachable code due to configuration option being set/unset */
}
/* Calculate the header length a place the data/body where it should be */
hdrLen = RFAL_T4T_MAX_CAPDU_PROLOGUE_LEN + RFAL_T4T_LC_LEN;
/* make sure not to exceed buffer size */
if(((uint16_t)hdrLen + (uint16_t)apduParam->Lc +
(apduParam->LeFlag ? RFAL_T4T_LC_LEN : 0U)) > RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN) {
return ERR_NOMEM; /* PRQA S 2880 # MISRA 2.1 - Unreachable code due to configuration option being set/unset */
}
ST_MEMMOVE(&apduParam->cApduBuf->apdu[hdrLen], apduParam->cApduBuf->apdu, apduParam->Lc);
}
/* Prepend the ADPDU's header */
apduParam->cApduBuf->apdu[msgIt++] = apduParam->CLA;
apduParam->cApduBuf->apdu[msgIt++] = apduParam->INS;
apduParam->cApduBuf->apdu[msgIt++] = apduParam->P1;
apduParam->cApduBuf->apdu[msgIt++] = apduParam->P2;
/* Check if Data field length is to be added */
if(apduParam->LcFlag) {
apduParam->cApduBuf->apdu[msgIt++] = apduParam->Lc;
msgIt += apduParam->Lc;
}
/* Check if Expected Response Length is to be added */
if(apduParam->LeFlag) {
apduParam->cApduBuf->apdu[msgIt++] = apduParam->Le;
}
*(apduParam->cApduLen) = msgIt;
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode rfalT4TPollerParseRAPDU(rfalT4tRApduParam* apduParam) {
if((apduParam == NULL) || (apduParam->rApduBuf == NULL)) {
return ERR_PARAM;
}
if(apduParam->rcvdLen < RFAL_T4T_MAX_RAPDU_SW1SW2_LEN) {
return ERR_PROTO;
}
apduParam->rApduBodyLen = (apduParam->rcvdLen - (uint16_t)RFAL_T4T_MAX_RAPDU_SW1SW2_LEN);
apduParam->statusWord = GETU16((&apduParam->rApduBuf->apdu[apduParam->rApduBodyLen]));
/* Check SW1 SW2 T4T 1.0 5.1.3 NOTE */
if(apduParam->statusWord == RFAL_T4T_ISO7816_STATUS_COMPLETE) {
return ERR_NONE;
}
return ERR_REQUEST;
}
/*******************************************************************************/
ReturnCode rfalT4TPollerComposeSelectAppl(
rfalIsoDepApduBufFormat* cApduBuf,
const uint8_t* aid,
uint8_t aidLen,
uint16_t* cApduLen) {
rfalT4tCApduParam cAPDU;
/* CLA INS P1 P2 Lc Data Le */
/* 00h A4h 00h 00h 07h AID 00h */
cAPDU.CLA = RFAL_T4T_CLA;
cAPDU.INS = (uint8_t)RFAL_T4T_INS_SELECT;
cAPDU.P1 = RFAL_T4T_ISO7816_P1_SELECT_BY_DF_NAME;
cAPDU.P2 = RFAL_T4T_ISO7816_P2_SELECT_FIRST_OR_ONLY_OCCURENCE |
RFAL_T4T_ISO7816_P2_SELECT_RETURN_FCI_TEMPLATE;
cAPDU.Lc = aidLen;
cAPDU.Le = 0x00;
cAPDU.LcFlag = true;
cAPDU.LeFlag = true;
cAPDU.cApduBuf = cApduBuf;
cAPDU.cApduLen = cApduLen;
if(aidLen > 0U) {
ST_MEMCPY(cAPDU.cApduBuf->apdu, aid, aidLen);
}
return rfalT4TPollerComposeCAPDU(&cAPDU);
}
/*******************************************************************************/
ReturnCode rfalT4TPollerComposeSelectFile(
rfalIsoDepApduBufFormat* cApduBuf,
const uint8_t* fid,
uint8_t fidLen,
uint16_t* cApduLen) {
rfalT4tCApduParam cAPDU;
/* CLA INS P1 P2 Lc Data Le */
/* 00h A4h 00h 0Ch 02h FID - */
cAPDU.CLA = RFAL_T4T_CLA;
cAPDU.INS = (uint8_t)RFAL_T4T_INS_SELECT;
cAPDU.P1 = RFAL_T4T_ISO7816_P1_SELECT_BY_FILEID;
cAPDU.P2 = RFAL_T4T_ISO7816_P2_SELECT_FIRST_OR_ONLY_OCCURENCE |
RFAL_T4T_ISO7816_P2_SELECT_NO_RESPONSE_DATA;
cAPDU.Lc = fidLen;
cAPDU.Le = 0x00;
cAPDU.LcFlag = true;
cAPDU.LeFlag = false;
cAPDU.cApduBuf = cApduBuf;
cAPDU.cApduLen = cApduLen;
if(fidLen > 0U) {
ST_MEMCPY(cAPDU.cApduBuf->apdu, fid, fidLen);
}
return rfalT4TPollerComposeCAPDU(&cAPDU);
}
/*******************************************************************************/
ReturnCode rfalT4TPollerComposeSelectFileV1Mapping(
rfalIsoDepApduBufFormat* cApduBuf,
const uint8_t* fid,
uint8_t fidLen,
uint16_t* cApduLen) {
rfalT4tCApduParam cAPDU;
/* CLA INS P1 P2 Lc Data Le */
/* 00h A4h 00h 00h 02h FID - */
cAPDU.CLA = RFAL_T4T_CLA;
cAPDU.INS = (uint8_t)RFAL_T4T_INS_SELECT;
cAPDU.P1 = RFAL_T4T_ISO7816_P1_SELECT_BY_FILEID;
cAPDU.P2 = RFAL_T4T_ISO7816_P2_SELECT_FIRST_OR_ONLY_OCCURENCE |
RFAL_T4T_ISO7816_P2_SELECT_RETURN_FCI_TEMPLATE;
cAPDU.Lc = fidLen;
cAPDU.Le = 0x00;
cAPDU.LcFlag = true;
cAPDU.LeFlag = false;
cAPDU.cApduBuf = cApduBuf;
cAPDU.cApduLen = cApduLen;
if(fidLen > 0U) {
ST_MEMCPY(cAPDU.cApduBuf->apdu, fid, fidLen);
}
return rfalT4TPollerComposeCAPDU(&cAPDU);
}
/*******************************************************************************/
ReturnCode rfalT4TPollerComposeReadData(
rfalIsoDepApduBufFormat* cApduBuf,
uint16_t offset,
uint8_t expLen,
uint16_t* cApduLen) {
rfalT4tCApduParam cAPDU;
/* CLA INS P1 P2 Lc Data Le */
/* 00h B0h [Offset] - - len */
cAPDU.CLA = RFAL_T4T_CLA;
cAPDU.INS = (uint8_t)RFAL_T4T_INS_READBINARY;
cAPDU.P1 = (uint8_t)((offset >> 8U) & 0xFFU);
cAPDU.P2 = (uint8_t)((offset >> 0U) & 0xFFU);
cAPDU.Le = expLen;
cAPDU.LcFlag = false;
cAPDU.LeFlag = true;
cAPDU.cApduBuf = cApduBuf;
cAPDU.cApduLen = cApduLen;
return rfalT4TPollerComposeCAPDU(&cAPDU);
}
/*******************************************************************************/
ReturnCode rfalT4TPollerComposeReadDataODO(
rfalIsoDepApduBufFormat* cApduBuf,
uint32_t offset,
uint8_t expLen,
uint16_t* cApduLen) {
rfalT4tCApduParam cAPDU;
uint8_t dataIt;
/* CLA INS P1 P2 Lc Data Le */
/* 00h B1h 00h 00h Lc 54 03 xxyyzz len */
/* [Offset] */
cAPDU.CLA = RFAL_T4T_CLA;
cAPDU.INS = (uint8_t)RFAL_T4T_INS_READBINARY_ODO;
cAPDU.P1 = 0x00U;
cAPDU.P2 = 0x00U;
cAPDU.Le = expLen;
cAPDU.LcFlag = true;
cAPDU.LeFlag = true;
cAPDU.cApduBuf = cApduBuf;
cAPDU.cApduLen = cApduLen;
dataIt = 0U;
cApduBuf->apdu[dataIt++] = RFAL_T4T_OFFSET_DO;
cApduBuf->apdu[dataIt++] = RFAL_T4T_LENGTH_DO;
cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 16U);
cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 8U);
cApduBuf->apdu[dataIt++] = (uint8_t)(offset);
cAPDU.Lc = dataIt;
return rfalT4TPollerComposeCAPDU(&cAPDU);
}
/*******************************************************************************/
ReturnCode rfalT4TPollerComposeWriteData(
rfalIsoDepApduBufFormat* cApduBuf,
uint16_t offset,
const uint8_t* data,
uint8_t dataLen,
uint16_t* cApduLen) {
rfalT4tCApduParam cAPDU;
/* CLA INS P1 P2 Lc Data Le */
/* 00h D6h [Offset] len Data - */
cAPDU.CLA = RFAL_T4T_CLA;
cAPDU.INS = (uint8_t)RFAL_T4T_INS_UPDATEBINARY;
cAPDU.P1 = (uint8_t)((offset >> 8U) & 0xFFU);
cAPDU.P2 = (uint8_t)((offset >> 0U) & 0xFFU);
cAPDU.Lc = dataLen;
cAPDU.LcFlag = true;
cAPDU.LeFlag = false;
cAPDU.cApduBuf = cApduBuf;
cAPDU.cApduLen = cApduLen;
if(dataLen > 0U) {
ST_MEMCPY(cAPDU.cApduBuf->apdu, data, dataLen);
}
return rfalT4TPollerComposeCAPDU(&cAPDU);
}
/*******************************************************************************/
ReturnCode rfalT4TPollerComposeWriteDataODO(
rfalIsoDepApduBufFormat* cApduBuf,
uint32_t offset,
const uint8_t* data,
uint8_t dataLen,
uint16_t* cApduLen) {
rfalT4tCApduParam cAPDU;
uint8_t dataIt;
/* CLA INS P1 P2 Lc Data Le */
/* 00h D7h 00h 00h len 54 03 xxyyzz 53 Ld data - */
/* [offset] [data] */
cAPDU.CLA = RFAL_T4T_CLA;
cAPDU.INS = (uint8_t)RFAL_T4T_INS_UPDATEBINARY_ODO;
cAPDU.P1 = 0x00U;
cAPDU.P2 = 0x00U;
cAPDU.LcFlag = true;
cAPDU.LeFlag = false;
cAPDU.cApduBuf = cApduBuf;
cAPDU.cApduLen = cApduLen;
dataIt = 0U;
cApduBuf->apdu[dataIt++] = RFAL_T4T_OFFSET_DO;
cApduBuf->apdu[dataIt++] = RFAL_T4T_LENGTH_DO;
cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 16U);
cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 8U);
cApduBuf->apdu[dataIt++] = (uint8_t)(offset);
cApduBuf->apdu[dataIt++] = RFAL_T4T_DATA_DO;
cApduBuf->apdu[dataIt++] = dataLen;
if((((uint32_t)dataLen + (uint32_t)dataIt) >= RFAL_T4T_MAX_LC) ||
(((uint32_t)dataLen + (uint32_t)dataIt) >= RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN)) {
return (ERR_NOMEM);
}
if(dataLen > 0U) {
ST_MEMCPY(&cAPDU.cApduBuf->apdu[dataIt], data, dataLen);
}
dataIt += dataLen;
cAPDU.Lc = dataIt;
return rfalT4TPollerComposeCAPDU(&cAPDU);
}
#endif /* RFAL_FEATURE_T4T */
File diff suppressed because it is too large Load Diff
@@ -1,68 +0,0 @@
/******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* $Revision: $
* LANGUAGE: ISO C99
*/
/*! \file
*
* \author Martin Zechleitner
*
* \brief RF Dynamic Power Table default values
*/
#ifndef ST25R3916_DPO_H
#define ST25R3916_DPO_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "rfal_dpo.h"
/*
******************************************************************************
* GLOBAL DATA TYPES
******************************************************************************
*/
/*! Default DPO table */
const uint8_t rfalDpoDefaultSettings[] = {
0x00,
255,
200,
0x01,
210,
150,
0x02,
160,
100,
0x03,
110,
50,
};
#endif /* ST25R3916_DPO_H */
@@ -1,109 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file
*
* \author Gustavo Patricio
*
* \brief RFAL Features/Capabilities Definition for ST25R3916
*/
#ifndef RFAL_FEATURES_H
#define RFAL_FEATURES_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define RFAL_SUPPORT_MODE_POLL_NFCA true /*!< RFAL Poll NFCA mode support switch */
#define RFAL_SUPPORT_MODE_POLL_NFCB true /*!< RFAL Poll NFCB mode support switch */
#define RFAL_SUPPORT_MODE_POLL_NFCF true /*!< RFAL Poll NFCF mode support switch */
#define RFAL_SUPPORT_MODE_POLL_NFCV true /*!< RFAL Poll NFCV mode support switch */
#define RFAL_SUPPORT_MODE_POLL_ACTIVE_P2P true /*!< RFAL Poll AP2P mode support switch */
#define RFAL_SUPPORT_MODE_LISTEN_NFCA true /*!< RFAL Listen NFCA mode support switch */
#define RFAL_SUPPORT_MODE_LISTEN_NFCB false /*!< RFAL Listen NFCB mode support switch */
#define RFAL_SUPPORT_MODE_LISTEN_NFCF true /*!< RFAL Listen NFCF mode support switch */
#define RFAL_SUPPORT_MODE_LISTEN_ACTIVE_P2P true /*!< RFAL Listen AP2P mode support switch */
/*******************************************************************************/
/*! RFAL supported Card Emulation (CE) */
#define RFAL_SUPPORT_CE \
(RFAL_SUPPORT_MODE_LISTEN_NFCA || RFAL_SUPPORT_MODE_LISTEN_NFCB || \
RFAL_SUPPORT_MODE_LISTEN_NFCF)
/*! RFAL supported Reader/Writer (RW) */
#define RFAL_SUPPORT_RW \
(RFAL_SUPPORT_MODE_POLL_NFCA || RFAL_SUPPORT_MODE_POLL_NFCB || RFAL_SUPPORT_MODE_POLL_NFCF || \
RFAL_SUPPORT_MODE_POLL_NFCV)
/*! RFAL support for Active P2P (AP2P) */
#define RFAL_SUPPORT_AP2P \
(RFAL_SUPPORT_MODE_POLL_ACTIVE_P2P || RFAL_SUPPORT_MODE_LISTEN_ACTIVE_P2P)
/*******************************************************************************/
#define RFAL_SUPPORT_BR_RW_106 true /*!< RFAL RW 106 Bit Rate support switch */
#define RFAL_SUPPORT_BR_RW_212 true /*!< RFAL RW 212 Bit Rate support switch */
#define RFAL_SUPPORT_BR_RW_424 true /*!< RFAL RW 424 Bit Rate support switch */
#define RFAL_SUPPORT_BR_RW_848 true /*!< RFAL RW 848 Bit Rate support switch */
#define RFAL_SUPPORT_BR_RW_1695 false /*!< RFAL RW 1695 Bit Rate support switch */
#define RFAL_SUPPORT_BR_RW_3390 false /*!< RFAL RW 3390 Bit Rate support switch */
#define RFAL_SUPPORT_BR_RW_6780 false /*!< RFAL RW 6780 Bit Rate support switch */
#define RFAL_SUPPORT_BR_RW_13560 false /*!< RFAL RW 6780 Bit Rate support switch */
/*******************************************************************************/
#define RFAL_SUPPORT_BR_AP2P_106 true /*!< RFAL AP2P 106 Bit Rate support switch */
#define RFAL_SUPPORT_BR_AP2P_212 true /*!< RFAL AP2P 212 Bit Rate support switch */
#define RFAL_SUPPORT_BR_AP2P_424 true /*!< RFAL AP2P 424 Bit Rate support switch */
#define RFAL_SUPPORT_BR_AP2P_848 false /*!< RFAL AP2P 848 Bit Rate support switch */
/*******************************************************************************/
#define RFAL_SUPPORT_BR_CE_A_106 true /*!< RFAL CE A 106 Bit Rate support switch */
#define RFAL_SUPPORT_BR_CE_A_212 false /*!< RFAL CE A 212 Bit Rate support switch */
#define RFAL_SUPPORT_BR_CE_A_424 false /*!< RFAL CE A 424 Bit Rate support switch */
#define RFAL_SUPPORT_BR_CE_A_848 false /*!< RFAL CE A 848 Bit Rate support switch */
/*******************************************************************************/
#define RFAL_SUPPORT_BR_CE_B_106 false /*!< RFAL CE B 106 Bit Rate support switch */
#define RFAL_SUPPORT_BR_CE_B_212 false /*!< RFAL CE B 212 Bit Rate support switch */
#define RFAL_SUPPORT_BR_CE_B_424 false /*!< RFAL CE B 424 Bit Rate support switch */
#define RFAL_SUPPORT_BR_CE_B_848 false /*!< RFAL CE B 848 Bit Rate support switch */
/*******************************************************************************/
#define RFAL_SUPPORT_BR_CE_F_212 true /*!< RFAL CE F 212 Bit Rate support switch */
#define RFAL_SUPPORT_BR_CE_F_424 true /*!< RFAL CE F 424 Bit Rate support switch */
#endif /* RFAL_FEATURES_H */
File diff suppressed because it is too large Load Diff
@@ -1,792 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R3916 firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file
*
* \author Gustavo Patricio
*
* \brief ST25R3916 high level interface
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "st25r3916.h"
#include "st25r3916_com.h"
#include "st25r3916_led.h"
#include "st25r3916_irq.h"
#include "utils.h"
/*
******************************************************************************
* LOCAL DEFINES
******************************************************************************
*/
#define ST25R3916_SUPPLY_THRESHOLD \
3600U /*!< Power supply measure threshold between 3.3V or 5V */
#define ST25R3916_NRT_MAX \
0xFFFFU /*!< Max Register value of NRT */
#define ST25R3916_TOUT_MEASURE_VDD \
100U /*!< Max duration time of Measure Power Supply command Datasheet: 25us */
#define ST25R3916_TOUT_MEASURE_AMPLITUDE \
10U /*!< Max duration time of Measure Amplitude command Datasheet: 25us */
#define ST25R3916_TOUT_MEASURE_PHASE \
10U /*!< Max duration time of Measure Phase command Datasheet: 25us */
#define ST25R3916_TOUT_MEASURE_CAPACITANCE \
10U /*!< Max duration time of Measure Capacitance command Datasheet: 25us */
#define ST25R3916_TOUT_CALIBRATE_CAP_SENSOR \
4U /*!< Max duration Calibrate Capacitive Sensor command Datasheet: 3ms */
#define ST25R3916_TOUT_ADJUST_REGULATORS \
6U /*!< Max duration time of Adjust Regulators command Datasheet: 5ms */
#define ST25R3916_TOUT_CA \
10U /*!< Max duration time of Collision Avoidance command */
#define ST25R3916_TEST_REG_PATTERN \
0x33U /*!< Register Read Write test pattern used during selftest */
#define ST25R3916_TEST_WU_TOUT \
12U /*!< Timeout used on WU timer during self test */
#define ST25R3916_TEST_TMR_TOUT \
20U /*!< Timeout used during self test */
#define ST25R3916_TEST_TMR_TOUT_DELTA \
2U /*!< Timeout used during self test */
#define ST25R3916_TEST_TMR_TOUT_8FC \
(ST25R3916_TEST_TMR_TOUT * 16950U) /*!< Timeout in 8/fc */
/*
******************************************************************************
* LOCAL CONSTANTS
******************************************************************************
*/
/*
******************************************************************************
* LOCAL VARIABLES
******************************************************************************
*/
static uint32_t gST25R3916NRT_64fcs;
/*
******************************************************************************
* LOCAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*
******************************************************************************
* LOCAL FUNCTION
******************************************************************************
*/
ReturnCode st25r3916ExecuteCommandAndGetResult(
uint8_t cmd,
uint8_t resReg,
uint8_t tout,
uint8_t* result) {
/* Clear and enable Direct Command interrupt */
st25r3916GetInterrupt(ST25R3916_IRQ_MASK_DCT);
st25r3916EnableInterrupts(ST25R3916_IRQ_MASK_DCT);
st25r3916ExecuteCommand(cmd);
st25r3916WaitForInterruptsTimed(ST25R3916_IRQ_MASK_DCT, tout);
st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_DCT);
/* After execution read out the result if the pointer is not NULL */
if(result != NULL) {
st25r3916ReadRegister(resReg, result);
}
return ERR_NONE;
}
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
ReturnCode st25r3916Initialize(void) {
uint16_t vdd_mV;
ReturnCode ret;
/* Set default state on the ST25R3916 */
st25r3916ExecuteCommand(ST25R3916_CMD_SET_DEFAULT);
#ifndef RFAL_USE_I2C
/* Increase MISO driving level as SPI can go up to 10MHz */
st25r3916WriteRegister(ST25R3916_REG_IO_CONF2, ST25R3916_REG_IO_CONF2_io_drv_lvl);
#endif /* RFAL_USE_I2C */
if(!st25r3916CheckChipID(NULL)) {
platformErrorHandle();
return ERR_HW_MISMATCH;
}
st25r3916InitInterrupts();
st25r3916ledInit();
gST25R3916NRT_64fcs = 0;
#ifndef RFAL_USE_I2C
/* Enable pull downs on MISO line */
st25r3916SetRegisterBits(
ST25R3916_REG_IO_CONF2,
(ST25R3916_REG_IO_CONF2_miso_pd1 | ST25R3916_REG_IO_CONF2_miso_pd2));
#endif /* RFAL_USE_I2C */
/* Disable internal overheat protection */
st25r3916ChangeTestRegisterBits(0x04, 0x10, 0x10);
#ifdef ST25R_SELFTEST
/******************************************************************************
* Check communication interface:
* - write a pattern in a register
* - reads back the register value
* - return ERR_IO in case the read value is different
*/
st25r3916WriteRegister(ST25R3916_REG_BIT_RATE, ST25R3916_TEST_REG_PATTERN);
if(!st25r3916CheckReg(
ST25R3916_REG_BIT_RATE,
(ST25R3916_REG_BIT_RATE_rxrate_mask | ST25R3916_REG_BIT_RATE_txrate_mask),
ST25R3916_TEST_REG_PATTERN)) {
platformErrorHandle();
return ERR_IO;
}
/* Restore default value */
st25r3916WriteRegister(ST25R3916_REG_BIT_RATE, 0x00);
/*
* Check IRQ Handling:
* - use the Wake-up timer to trigger an IRQ
* - wait the Wake-up timer interrupt
* - return ERR_TIMEOUT when the Wake-up timer interrupt is not received
*/
st25r3916WriteRegister(
ST25R3916_REG_WUP_TIMER_CONTROL,
ST25R3916_REG_WUP_TIMER_CONTROL_wur | ST25R3916_REG_WUP_TIMER_CONTROL_wto);
st25r3916EnableInterrupts(ST25R3916_IRQ_MASK_WT);
st25r3916ExecuteCommand(ST25R3916_CMD_START_WUP_TIMER);
if(st25r3916WaitForInterruptsTimed(ST25R3916_IRQ_MASK_WT, ST25R3916_TEST_WU_TOUT) == 0U) {
platformErrorHandle();
return ERR_TIMEOUT;
}
st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_WT);
st25r3916WriteRegister(ST25R3916_REG_WUP_TIMER_CONTROL, 0U);
/*******************************************************************************/
#endif /* ST25R_SELFTEST */
/* Enable Oscillator and wait until it gets stable */
ret = st25r3916OscOn();
if(ret != ERR_NONE) {
platformErrorHandle();
return ret;
}
/* Measure VDD and set sup3V bit according to Power supplied */
vdd_mV = st25r3916MeasureVoltage(ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd);
st25r3916ChangeRegisterBits(
ST25R3916_REG_IO_CONF2,
ST25R3916_REG_IO_CONF2_sup3V,
((vdd_mV < ST25R3916_SUPPLY_THRESHOLD) ? ST25R3916_REG_IO_CONF2_sup3V_3V :
ST25R3916_REG_IO_CONF2_sup3V_5V));
/* Make sure Transmitter and Receiver are disabled */
st25r3916TxRxOff();
#ifdef ST25R_SELFTEST_TIMER
/******************************************************************************
* Check SW timer operation :
* - use the General Purpose timer to measure an amount of time
* - test whether an interrupt is seen when less time was given
* - test whether an interrupt is seen when sufficient time was given
*/
st25r3916EnableInterrupts(ST25R3916_IRQ_MASK_GPE);
st25r3916SetStartGPTimer(
(uint16_t)ST25R3916_TEST_TMR_TOUT_8FC, ST25R3916_REG_TIMER_EMV_CONTROL_gptc_no_trigger);
if(st25r3916WaitForInterruptsTimed(
ST25R3916_IRQ_MASK_GPE, (ST25R3916_TEST_TMR_TOUT - ST25R3916_TEST_TMR_TOUT_DELTA)) !=
0U) {
platformErrorHandle();
return ERR_SYSTEM;
}
/* Stop all activities to stop the GP timer */
st25r3916ExecuteCommand(ST25R3916_CMD_STOP);
st25r3916ClearAndEnableInterrupts(ST25R3916_IRQ_MASK_GPE);
st25r3916SetStartGPTimer(
(uint16_t)ST25R3916_TEST_TMR_TOUT_8FC, ST25R3916_REG_TIMER_EMV_CONTROL_gptc_no_trigger);
if(st25r3916WaitForInterruptsTimed(
ST25R3916_IRQ_MASK_GPE, (ST25R3916_TEST_TMR_TOUT + ST25R3916_TEST_TMR_TOUT_DELTA)) ==
0U) {
platformErrorHandle();
return ERR_SYSTEM;
}
/* Stop all activities to stop the GP timer */
st25r3916ExecuteCommand(ST25R3916_CMD_STOP);
/*******************************************************************************/
#endif /* ST25R_SELFTEST_TIMER */
/* After reset all interrupts are enabled, so disable them at first */
st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_ALL);
/* And clear them, just to be sure */
st25r3916ClearInterrupts();
return ERR_NONE;
}
/*******************************************************************************/
void st25r3916Deinitialize(void) {
st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_ALL);
/* Disable Tx and Rx, Keep OSC On */
st25r3916TxRxOff();
return;
}
/*******************************************************************************/
ReturnCode st25r3916OscOn(void) {
/* Check if oscillator is already turned on and stable */
/* Use ST25R3916_REG_OP_CONTROL_en instead of ST25R3916_REG_AUX_DISPLAY_osc_ok to be on the safe side */
if(!st25r3916CheckReg(
ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_en, ST25R3916_REG_OP_CONTROL_en)) {
/* Clear any eventual previous oscillator IRQ */
st25r3916GetInterrupt(ST25R3916_IRQ_MASK_OSC);
/* Enable oscillator frequency stable interrupt */
st25r3916EnableInterrupts(ST25R3916_IRQ_MASK_OSC);
/* Enable oscillator and regulator output */
st25r3916SetRegisterBits(ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_en);
/* Wait for the oscillator interrupt */
st25r3916WaitForInterruptsTimed(ST25R3916_IRQ_MASK_OSC, ST25R3916_TOUT_OSC_STABLE);
st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_OSC);
}
if(!st25r3916CheckReg(
ST25R3916_REG_AUX_DISPLAY,
ST25R3916_REG_AUX_DISPLAY_osc_ok,
ST25R3916_REG_AUX_DISPLAY_osc_ok)) {
return ERR_SYSTEM;
}
return ERR_NONE;
}
/*******************************************************************************/
uint8_t st25r3916MeasurePowerSupply(uint8_t mpsv) {
uint8_t result;
/* Set the source of direct command: Measure Power Supply Voltage */
st25r3916ChangeRegisterBits(
ST25R3916_REG_REGULATOR_CONTROL, ST25R3916_REG_REGULATOR_CONTROL_mpsv_mask, mpsv);
/* Execute command: Measure Power Supply Voltage */
st25r3916ExecuteCommandAndGetResult(
ST25R3916_CMD_MEASURE_VDD, ST25R3916_REG_AD_RESULT, ST25R3916_TOUT_MEASURE_VDD, &result);
return result;
}
/*******************************************************************************/
uint16_t st25r3916MeasureVoltage(uint8_t mpsv) {
uint8_t result;
uint16_t mV;
result = st25r3916MeasurePowerSupply(mpsv);
/* Convert cmd output into mV (each step represents 23.4 mV )*/
mV = ((uint16_t)result) * 23U;
mV += (((((uint16_t)result) * 4U) + 5U) / 10U);
return mV;
}
/*******************************************************************************/
ReturnCode st25r3916AdjustRegulators(uint16_t* result_mV) {
uint8_t result;
/* Reset logic and set regulated voltages to be defined by result of Adjust Regulators command */
st25r3916SetRegisterBits(
ST25R3916_REG_REGULATOR_CONTROL, ST25R3916_REG_REGULATOR_CONTROL_reg_s);
st25r3916ClrRegisterBits(
ST25R3916_REG_REGULATOR_CONTROL, ST25R3916_REG_REGULATOR_CONTROL_reg_s);
/* Execute Adjust regulators cmd and retrieve result */
st25r3916ExecuteCommandAndGetResult(
ST25R3916_CMD_ADJUST_REGULATORS,
ST25R3916_REG_REGULATOR_RESULT,
ST25R3916_TOUT_ADJUST_REGULATORS,
&result);
/* Calculate result in mV */
result >>= ST25R3916_REG_REGULATOR_RESULT_reg_shift;
if(result_mV != NULL) {
if(st25r3916CheckReg(
ST25R3916_REG_IO_CONF2,
ST25R3916_REG_IO_CONF2_sup3V,
ST25R3916_REG_IO_CONF2_sup3V)) {
result = MIN(
result,
(uint8_t)(result - 5U)); /* In 3.3V mode [0,4] are not used */
*result_mV = 2400U; /* Minimum regulated voltage 2.4V in case of 3.3V supply */
} else {
*result_mV = 3600U; /* Minimum regulated voltage 3.6V in case of 5V supply */
}
*result_mV +=
(uint16_t)result * 100U; /* 100mV steps in both 3.3V and 5V supply */
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode st25r3916MeasureAmplitude(uint8_t* result) {
return st25r3916ExecuteCommandAndGetResult(
ST25R3916_CMD_MEASURE_AMPLITUDE,
ST25R3916_REG_AD_RESULT,
ST25R3916_TOUT_MEASURE_AMPLITUDE,
result);
}
/*******************************************************************************/
ReturnCode st25r3916MeasurePhase(uint8_t* result) {
return st25r3916ExecuteCommandAndGetResult(
ST25R3916_CMD_MEASURE_PHASE, ST25R3916_REG_AD_RESULT, ST25R3916_TOUT_MEASURE_PHASE, result);
}
/*******************************************************************************/
ReturnCode st25r3916MeasureCapacitance(uint8_t* result) {
return st25r3916ExecuteCommandAndGetResult(
ST25R3916_CMD_MEASURE_CAPACITANCE,
ST25R3916_REG_AD_RESULT,
ST25R3916_TOUT_MEASURE_CAPACITANCE,
result);
}
/*******************************************************************************/
ReturnCode st25r3916CalibrateCapacitiveSensor(uint8_t* result) {
ReturnCode ret;
uint8_t res;
/* Clear Manual calibration values to enable automatic calibration mode */
st25r3916ClrRegisterBits(
ST25R3916_REG_CAP_SENSOR_CONTROL, ST25R3916_REG_CAP_SENSOR_CONTROL_cs_mcal_mask);
/* Execute automatic calibration */
ret = st25r3916ExecuteCommandAndGetResult(
ST25R3916_CMD_CALIBRATE_C_SENSOR,
ST25R3916_REG_CAP_SENSOR_RESULT,
ST25R3916_TOUT_CALIBRATE_CAP_SENSOR,
&res);
/* Check whether the calibration was successull */
if(((res & ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_end) !=
ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_end) ||
((res & ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_err) ==
ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_err) ||
(ret != ERR_NONE)) {
return ERR_IO;
}
if(result != NULL) {
(*result) = (uint8_t)(res >> ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_shift);
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode st25r3916SetBitrate(uint8_t txrate, uint8_t rxrate) {
uint8_t reg;
st25r3916ReadRegister(ST25R3916_REG_BIT_RATE, &reg);
if(rxrate != ST25R3916_BR_DO_NOT_SET) {
if(rxrate > ST25R3916_BR_848) {
return ERR_PARAM;
}
reg = (uint8_t)(reg & ~ST25R3916_REG_BIT_RATE_rxrate_mask); /* MISRA 10.3 */
reg |= rxrate << ST25R3916_REG_BIT_RATE_rxrate_shift;
}
if(txrate != ST25R3916_BR_DO_NOT_SET) {
if(txrate > ST25R3916_BR_6780) {
return ERR_PARAM;
}
reg = (uint8_t)(reg & ~ST25R3916_REG_BIT_RATE_txrate_mask); /* MISRA 10.3 */
reg |= txrate << ST25R3916_REG_BIT_RATE_txrate_shift;
}
return st25r3916WriteRegister(ST25R3916_REG_BIT_RATE, reg);
}
/*******************************************************************************/
ReturnCode st25r3916PerformCollisionAvoidance(
uint8_t FieldONCmd,
uint8_t pdThreshold,
uint8_t caThreshold,
uint8_t nTRFW) {
uint8_t treMask;
uint32_t irqs;
ReturnCode err;
if((FieldONCmd != ST25R3916_CMD_INITIAL_RF_COLLISION) &&
(FieldONCmd != ST25R3916_CMD_RESPONSE_RF_COLLISION_N)) {
return ERR_PARAM;
}
err = ERR_INTERNAL;
/* Check if new thresholds are to be applied */
if((pdThreshold != ST25R3916_THRESHOLD_DO_NOT_SET) ||
(caThreshold != ST25R3916_THRESHOLD_DO_NOT_SET)) {
treMask = 0;
if(pdThreshold != ST25R3916_THRESHOLD_DO_NOT_SET) {
treMask |= ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_mask;
}
if(caThreshold != ST25R3916_THRESHOLD_DO_NOT_SET) {
treMask |= ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_mask;
}
/* Set Detection Threshold and|or Collision Avoidance Threshold */
st25r3916ChangeRegisterBits(
ST25R3916_REG_FIELD_THRESHOLD_ACTV,
treMask,
(pdThreshold & ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_mask) |
(caThreshold & ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_mask));
}
/* Set n x TRFW */
st25r3916ChangeRegisterBits(ST25R3916_REG_AUX, ST25R3916_REG_AUX_nfc_n_mask, nTRFW);
/*******************************************************************************/
/* Enable and clear CA specific interrupts and execute command */
st25r3916GetInterrupt(
(ST25R3916_IRQ_MASK_CAC | ST25R3916_IRQ_MASK_CAT | ST25R3916_IRQ_MASK_APON));
st25r3916EnableInterrupts(
(ST25R3916_IRQ_MASK_CAC | ST25R3916_IRQ_MASK_CAT | ST25R3916_IRQ_MASK_APON));
st25r3916ExecuteCommand(FieldONCmd);
/*******************************************************************************/
/* Wait for initial APON interrupt, indicating anticollision avoidance done and ST25R3916's
* field is now on, or a CAC indicating a collision */
irqs = st25r3916WaitForInterruptsTimed(
(ST25R3916_IRQ_MASK_CAC | ST25R3916_IRQ_MASK_APON), ST25R3916_TOUT_CA);
if((ST25R3916_IRQ_MASK_CAC & irqs) != 0U) /* Collision occurred */
{
err = ERR_RF_COLLISION;
} else if((ST25R3916_IRQ_MASK_APON & irqs) != 0U) {
/* After APON wait for CAT interrupt, indication field was switched on minimum guard time has been fulfilled */
irqs = st25r3916WaitForInterruptsTimed((ST25R3916_IRQ_MASK_CAT), ST25R3916_TOUT_CA);
if((ST25R3916_IRQ_MASK_CAT & irqs) != 0U) /* No Collision detected, Field On */
{
err = ERR_NONE;
}
} else {
/* MISRA 15.7 - Empty else */
}
/* Clear any previous External Field events and disable CA specific interrupts */
st25r3916GetInterrupt((ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_EON));
st25r3916DisableInterrupts(
(ST25R3916_IRQ_MASK_CAC | ST25R3916_IRQ_MASK_CAT | ST25R3916_IRQ_MASK_APON));
return err;
}
/*******************************************************************************/
void st25r3916SetNumTxBits(uint16_t nBits) {
st25r3916WriteRegister(ST25R3916_REG_NUM_TX_BYTES2, (uint8_t)((nBits >> 0) & 0xFFU));
st25r3916WriteRegister(ST25R3916_REG_NUM_TX_BYTES1, (uint8_t)((nBits >> 8) & 0xFFU));
}
/*******************************************************************************/
uint16_t st25r3916GetNumFIFOBytes(void) {
uint8_t reg;
uint16_t result;
st25r3916ReadRegister(ST25R3916_REG_FIFO_STATUS2, &reg);
reg =
((reg & ST25R3916_REG_FIFO_STATUS2_fifo_b_mask) >>
ST25R3916_REG_FIFO_STATUS2_fifo_b_shift);
result = ((uint16_t)reg << 8);
st25r3916ReadRegister(ST25R3916_REG_FIFO_STATUS1, &reg);
result |= (((uint16_t)reg) & 0x00FFU);
return result;
}
/*******************************************************************************/
uint8_t st25r3916GetNumFIFOLastBits(void) {
uint8_t reg;
st25r3916ReadRegister(ST25R3916_REG_FIFO_STATUS2, &reg);
return (
(reg & ST25R3916_REG_FIFO_STATUS2_fifo_lb_mask) >>
ST25R3916_REG_FIFO_STATUS2_fifo_lb_shift);
}
/*******************************************************************************/
uint32_t st25r3916GetNoResponseTime(void) {
return gST25R3916NRT_64fcs;
}
/*******************************************************************************/
ReturnCode st25r3916SetNoResponseTime(uint32_t nrt_64fcs) {
ReturnCode err;
uint8_t nrt_step;
uint32_t tmpNRT;
tmpNRT = nrt_64fcs; /* MISRA 17.8 */
err = ERR_NONE;
gST25R3916NRT_64fcs = tmpNRT; /* Store given NRT value in 64/fc into local var */
nrt_step =
ST25R3916_REG_TIMER_EMV_CONTROL_nrt_step_64fc; /* Set default NRT in steps of 64/fc */
if(tmpNRT > ST25R3916_NRT_MAX) /* Check if the given NRT value fits using 64/fc steps */
{
nrt_step =
ST25R3916_REG_TIMER_EMV_CONTROL_nrt_step_4096_fc; /* If not, change NRT set to 4096/fc */
tmpNRT = ((tmpNRT + 63U) / 64U); /* Calculate number of steps in 4096/fc */
if(tmpNRT > ST25R3916_NRT_MAX) /* Check if the NRT value fits using 64/fc steps */
{
tmpNRT = ST25R3916_NRT_MAX; /* Assign the maximum possible */
err = ERR_PARAM; /* Signal parameter error */
}
gST25R3916NRT_64fcs = (64U * tmpNRT);
}
/* Set the ST25R3916 NRT step units and the value */
st25r3916ChangeRegisterBits(
ST25R3916_REG_TIMER_EMV_CONTROL, ST25R3916_REG_TIMER_EMV_CONTROL_nrt_step, nrt_step);
st25r3916WriteRegister(ST25R3916_REG_NO_RESPONSE_TIMER1, (uint8_t)(tmpNRT >> 8U));
st25r3916WriteRegister(ST25R3916_REG_NO_RESPONSE_TIMER2, (uint8_t)(tmpNRT & 0xFFU));
return err;
}
/*******************************************************************************/
ReturnCode st25r3916SetStartNoResponseTimer(uint32_t nrt_64fcs) {
ReturnCode err;
err = st25r3916SetNoResponseTime(nrt_64fcs);
if(err == ERR_NONE) {
st25r3916ExecuteCommand(ST25R3916_CMD_START_NO_RESPONSE_TIMER);
}
return err;
}
/*******************************************************************************/
void st25r3916SetGPTime(uint16_t gpt_8fcs) {
st25r3916WriteRegister(ST25R3916_REG_GPT1, (uint8_t)(gpt_8fcs >> 8));
st25r3916WriteRegister(ST25R3916_REG_GPT2, (uint8_t)(gpt_8fcs & 0xFFU));
}
/*******************************************************************************/
ReturnCode st25r3916SetStartGPTimer(uint16_t gpt_8fcs, uint8_t trigger_source) {
st25r3916SetGPTime(gpt_8fcs);
st25r3916ChangeRegisterBits(
ST25R3916_REG_TIMER_EMV_CONTROL,
ST25R3916_REG_TIMER_EMV_CONTROL_gptc_mask,
trigger_source);
/* If there's no trigger source, start GPT immediately */
if(trigger_source == ST25R3916_REG_TIMER_EMV_CONTROL_gptc_no_trigger) {
st25r3916ExecuteCommand(ST25R3916_CMD_START_GP_TIMER);
}
return ERR_NONE;
}
/*******************************************************************************/
bool st25r3916CheckChipID(uint8_t* rev) {
uint8_t ID;
ID = 0;
st25r3916ReadRegister(ST25R3916_REG_IC_IDENTITY, &ID);
/* Check if IC Identity Register contains ST25R3916's IC type code */
if((ID & ST25R3916_REG_IC_IDENTITY_ic_type_mask) !=
ST25R3916_REG_IC_IDENTITY_ic_type_st25r3916) {
return false;
}
if(rev != NULL) {
*rev = (ID & ST25R3916_REG_IC_IDENTITY_ic_rev_mask);
}
return true;
}
/*******************************************************************************/
ReturnCode st25r3916GetRegsDump(t_st25r3916Regs* regDump) {
uint8_t regIt;
if(regDump == NULL) {
return ERR_PARAM;
}
/* Dump Registers on space A */
for(regIt = ST25R3916_REG_IO_CONF1; regIt <= ST25R3916_REG_IC_IDENTITY; regIt++) {
st25r3916ReadRegister(regIt, &regDump->RsA[regIt]);
}
regIt = 0;
/* Read non-consecutive Registers on space B */
st25r3916ReadRegister(ST25R3916_REG_EMD_SUP_CONF, &regDump->RsB[regIt++]);
st25r3916ReadRegister(ST25R3916_REG_SUBC_START_TIME, &regDump->RsB[regIt++]);
st25r3916ReadRegister(ST25R3916_REG_P2P_RX_CONF, &regDump->RsB[regIt++]);
st25r3916ReadRegister(ST25R3916_REG_CORR_CONF1, &regDump->RsB[regIt++]);
st25r3916ReadRegister(ST25R3916_REG_CORR_CONF2, &regDump->RsB[regIt++]);
st25r3916ReadRegister(ST25R3916_REG_SQUELCH_TIMER, &regDump->RsB[regIt++]);
st25r3916ReadRegister(ST25R3916_REG_FIELD_ON_GT, &regDump->RsB[regIt++]);
st25r3916ReadRegister(ST25R3916_REG_AUX_MOD, &regDump->RsB[regIt++]);
st25r3916ReadRegister(ST25R3916_REG_TX_DRIVER_TIMING, &regDump->RsB[regIt++]);
st25r3916ReadRegister(ST25R3916_REG_RES_AM_MOD, &regDump->RsB[regIt++]);
st25r3916ReadRegister(ST25R3916_REG_TX_DRIVER_STATUS, &regDump->RsB[regIt++]);
st25r3916ReadRegister(ST25R3916_REG_REGULATOR_RESULT, &regDump->RsB[regIt++]);
st25r3916ReadRegister(ST25R3916_REG_OVERSHOOT_CONF1, &regDump->RsB[regIt++]);
st25r3916ReadRegister(ST25R3916_REG_OVERSHOOT_CONF2, &regDump->RsB[regIt++]);
st25r3916ReadRegister(ST25R3916_REG_UNDERSHOOT_CONF1, &regDump->RsB[regIt++]);
st25r3916ReadRegister(ST25R3916_REG_UNDERSHOOT_CONF2, &regDump->RsB[regIt++]);
return ERR_NONE;
}
/*******************************************************************************/
bool st25r3916IsCmdValid(uint8_t cmd) {
if(!((cmd >= ST25R3916_CMD_SET_DEFAULT) && (cmd <= ST25R3916_CMD_RESPONSE_RF_COLLISION_N)) &&
!((cmd >= ST25R3916_CMD_GOTO_SENSE) && (cmd <= ST25R3916_CMD_GOTO_SLEEP)) &&
!((cmd >= ST25R3916_CMD_MASK_RECEIVE_DATA) && (cmd <= ST25R3916_CMD_MEASURE_AMPLITUDE)) &&
!((cmd >= ST25R3916_CMD_RESET_RXGAIN) && (cmd <= ST25R3916_CMD_ADJUST_REGULATORS)) &&
!((cmd >= ST25R3916_CMD_CALIBRATE_DRIVER_TIMING) &&
(cmd <= ST25R3916_CMD_START_PPON2_TIMER)) &&
(cmd != ST25R3916_CMD_SPACE_B_ACCESS) && (cmd != ST25R3916_CMD_STOP_NRT)) {
return false;
}
return true;
}
/*******************************************************************************/
ReturnCode st25r3916StreamConfigure(const struct st25r3916StreamConfig* config) {
uint8_t smd;
uint8_t mode;
smd = 0;
if(config->useBPSK != 0U) {
mode = ST25R3916_REG_MODE_om_bpsk_stream;
if((config->din < 2U) || (config->din > 4U)) /* not in fc/4 .. fc/16 */
{
return ERR_PARAM;
}
smd |= ((4U - config->din) << ST25R3916_REG_STREAM_MODE_scf_shift);
} else {
mode = ST25R3916_REG_MODE_om_subcarrier_stream;
if((config->din < 3U) || (config->din > 6U)) /* not in fc/8 .. fc/64 */
{
return ERR_PARAM;
}
smd |= ((6U - config->din) << ST25R3916_REG_STREAM_MODE_scf_shift);
if(config->report_period_length == 0U) {
return ERR_PARAM;
}
}
if((config->dout < 1U) || (config->dout > 7U)) /* not in fc/2 .. fc/128 */
{
return ERR_PARAM;
}
smd |= (7U - config->dout) << ST25R3916_REG_STREAM_MODE_stx_shift;
if(config->report_period_length > 3U) {
return ERR_PARAM;
}
smd |= (config->report_period_length << ST25R3916_REG_STREAM_MODE_scp_shift);
st25r3916WriteRegister(ST25R3916_REG_STREAM_MODE, smd);
st25r3916ChangeRegisterBits(ST25R3916_REG_MODE, ST25R3916_REG_MODE_om_mask, mode);
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode st25r3916GetRSSI(uint16_t* amRssi, uint16_t* pmRssi) {
/*******************************************************************************/
/* MISRA 8.9 An object should be defined at block scope if its identifier only appears in a single function */
/*< ST25R3916 RSSI Display Reg values: 0 1 2 3 4 5 6 7 8 9 a b c d e f */
static const uint16_t st25r3916Rssi2mV[] = {
0, 20, 27, 37, 52, 72, 99, 136, 190, 262, 357, 500, 686, 950, 1150, 1150};
/* ST25R3916 2/3 stage gain reduction [dB] 0 0 0 0 0 3 6 9 12 15 18 na na na na na */
static const uint16_t st25r3916Gain2Percent[] = {
100, 100, 100, 100, 100, 141, 200, 281, 398, 562, 794, 1, 1, 1, 1, 1};
/*******************************************************************************/
uint8_t rssi;
uint8_t gainRed;
st25r3916ReadRegister(ST25R3916_REG_RSSI_RESULT, &rssi);
st25r3916ReadRegister(ST25R3916_REG_GAIN_RED_STATE, &gainRed);
if(amRssi != NULL) {
*amRssi =
(uint16_t)(((uint32_t)st25r3916Rssi2mV[(rssi >> ST25R3916_REG_RSSI_RESULT_rssi_am_shift)] * (uint32_t)st25r3916Gain2Percent[(gainRed >> ST25R3916_REG_GAIN_RED_STATE_gs_am_shift)]) / 100U);
}
if(pmRssi != NULL) {
*pmRssi =
(uint16_t)(((uint32_t)st25r3916Rssi2mV[(rssi & ST25R3916_REG_RSSI_RESULT_rssi_pm_mask)] * (uint32_t)st25r3916Gain2Percent[(gainRed & ST25R3916_REG_GAIN_RED_STATE_gs_pm_mask)]) / 100U);
}
return ERR_NONE;
}
@@ -1,669 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R3916 firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file
*
* \author Gustavo Patricio
*
* \brief ST25R3916 high level interface
*
*
* \addtogroup RFAL
* @{
*
* \addtogroup RFAL-HAL
* \brief RFAL Hardware Abstraction Layer
* @{
*
* \addtogroup ST25R3916
* \brief RFAL ST25R3916 Driver
* @{
*
* \addtogroup ST25R3916_Driver
* \brief RFAL ST25R3916 Driver
* @{
*
*/
#ifndef ST25R3916_H
#define ST25R3916_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
#include "st_errno.h"
#include "st25r3916_com.h"
/*
******************************************************************************
* GLOBAL DATATYPES
******************************************************************************
*/
/*! Struct to represent all regs on ST25R3916 */
typedef struct {
uint8_t RsA[(
ST25R3916_REG_IC_IDENTITY + 1U)]; /*!< Registers contained on ST25R3916 space A (Rs-A) */
uint8_t
RsB[ST25R3916_SPACE_B_REG_LEN]; /*!< Registers contained on ST25R3916 space B (Rs-B) */
} t_st25r3916Regs;
/*! Parameters how the stream mode should work */
struct st25r3916StreamConfig {
uint8_t useBPSK; /*!< 0: subcarrier, 1:BPSK */
uint8_t din; /*!< Divider for the in subcarrier frequency: fc/2^din */
uint8_t dout; /*!< Divider for the in subcarrier frequency fc/2^dout */
uint8_t report_period_length; /*!< Length of the reporting period 2^report_period_length*/
};
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
/* ST25R3916 direct commands */
#define ST25R3916_CMD_SET_DEFAULT \
0xC1U /*!< Puts the chip in default state (same as after power-up) */
#define ST25R3916_CMD_STOP 0xC2U /*!< Stops all activities and clears FIFO */
#define ST25R3916_CMD_TRANSMIT_WITH_CRC \
0xC4U /*!< Transmit with CRC */
#define ST25R3916_CMD_TRANSMIT_WITHOUT_CRC \
0xC5U /*!< Transmit without CRC */
#define ST25R3916_CMD_TRANSMIT_REQA \
0xC6U /*!< Transmit REQA */
#define ST25R3916_CMD_TRANSMIT_WUPA \
0xC7U /*!< Transmit WUPA */
#define ST25R3916_CMD_INITIAL_RF_COLLISION \
0xC8U /*!< NFC transmit with Initial RF Collision Avoidance */
#define ST25R3916_CMD_RESPONSE_RF_COLLISION_N \
0xC9U /*!< NFC transmit with Response RF Collision Avoidance */
#define ST25R3916_CMD_GOTO_SENSE \
0xCDU /*!< Passive target logic to Sense/Idle state */
#define ST25R3916_CMD_GOTO_SLEEP \
0xCEU /*!< Passive target logic to Sleep/Halt state */
#define ST25R3916_CMD_MASK_RECEIVE_DATA \
0xD0U /*!< Mask receive data */
#define ST25R3916_CMD_UNMASK_RECEIVE_DATA \
0xD1U /*!< Unmask receive data */
#define ST25R3916_CMD_AM_MOD_STATE_CHANGE \
0xD2U /*!< AM Modulation state change */
#define ST25R3916_CMD_MEASURE_AMPLITUDE \
0xD3U /*!< Measure signal amplitude on RFI inputs */
#define ST25R3916_CMD_RESET_RXGAIN \
0xD5U /*!< Reset RX Gain */
#define ST25R3916_CMD_ADJUST_REGULATORS \
0xD6U /*!< Adjust regulators */
#define ST25R3916_CMD_CALIBRATE_DRIVER_TIMING \
0xD8U /*!< Starts the sequence to adjust the driver timing */
#define ST25R3916_CMD_MEASURE_PHASE \
0xD9U /*!< Measure phase between RFO and RFI signal */
#define ST25R3916_CMD_CLEAR_RSSI \
0xDAU /*!< Clear RSSI bits and restart the measurement */
#define ST25R3916_CMD_CLEAR_FIFO \
0xDBU /*!< Clears FIFO, Collision and IRQ status */
#define ST25R3916_CMD_TRANSPARENT_MODE \
0xDCU /*!< Transparent mode */
#define ST25R3916_CMD_CALIBRATE_C_SENSOR \
0xDDU /*!< Calibrate the capacitive sensor */
#define ST25R3916_CMD_MEASURE_CAPACITANCE \
0xDEU /*!< Measure capacitance */
#define ST25R3916_CMD_MEASURE_VDD \
0xDFU /*!< Measure power supply voltage */
#define ST25R3916_CMD_START_GP_TIMER \
0xE0U /*!< Start the general purpose timer */
#define ST25R3916_CMD_START_WUP_TIMER \
0xE1U /*!< Start the wake-up timer */
#define ST25R3916_CMD_START_MASK_RECEIVE_TIMER \
0xE2U /*!< Start the mask-receive timer */
#define ST25R3916_CMD_START_NO_RESPONSE_TIMER \
0xE3U /*!< Start the no-response timer */
#define ST25R3916_CMD_START_PPON2_TIMER \
0xE4U /*!< Start PPon2 timer */
#define ST25R3916_CMD_STOP_NRT \
0xE8U /*!< Stop No Response Timer */
#define ST25R3916_CMD_SPACE_B_ACCESS \
0xFBU /*!< Enable R/W access to the test registers */
#define ST25R3916_CMD_TEST_ACCESS \
0xFCU /*!< Enable R/W access to the test registers */
#define ST25R3916_THRESHOLD_DO_NOT_SET \
0xFFU /*!< Indicates not to change this Threshold */
#define ST25R3916_BR_DO_NOT_SET \
0xFFU /*!< Indicates not to change this Bit Rate */
#define ST25R3916_BR_106 0x00U /*!< ST25R3916 Bit Rate 106 kbit/s (fc/128) */
#define ST25R3916_BR_212 0x01U /*!< ST25R3916 Bit Rate 212 kbit/s (fc/64) */
#define ST25R3916_BR_424 0x02U /*!< ST25R3916 Bit Rate 424 kbit/s (fc/32) */
#define ST25R3916_BR_848 0x03U /*!< ST25R3916 Bit Rate 848 kbit/s (fc/16) */
#define ST25R3916_BR_1695 0x04U /*!< ST25R3916 Bit Rate 1696 kbit/s (fc/8) */
#define ST25R3916_BR_3390 0x05U /*!< ST25R3916 Bit Rate 3390 kbit/s (fc/4) */
#define ST25R3916_BR_6780 0x07U /*!< ST25R3916 Bit Rate 6780 kbit/s (fc/2) */
#define ST25R3916_FIFO_DEPTH 512U /*!< Depth of FIFO */
#define ST25R3916_TOUT_OSC_STABLE \
10U /*!< Max timeout for Oscillator to get stable DS: 700us */
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
/*! Enables the Transmitter (Field On) and Receiver */
#define st25r3916TxRxOn() \
st25r3916SetRegisterBits( \
ST25R3916_REG_OP_CONTROL, \
(ST25R3916_REG_OP_CONTROL_rx_en | ST25R3916_REG_OP_CONTROL_tx_en))
/*! Disables the Transmitter (Field Off) and Receiver */
#define st25r3916TxRxOff() \
st25r3916ClrRegisterBits( \
ST25R3916_REG_OP_CONTROL, \
(ST25R3916_REG_OP_CONTROL_rx_en | ST25R3916_REG_OP_CONTROL_tx_en))
/*! Disables the Transmitter (Field Off) */
#define st25r3916TxOff() \
st25r3916ClrRegisterBits(ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_tx_en)
/*! Checks if General Purpose Timer is still running by reading gpt_on flag */
#define st25r3916IsGPTRunning() \
st25r3916CheckReg( \
ST25R3916_REG_NFCIP1_BIT_RATE, \
ST25R3916_REG_NFCIP1_BIT_RATE_gpt_on, \
ST25R3916_REG_NFCIP1_BIT_RATE_gpt_on)
/*! Checks if External Filed is detected by reading ST25R3916 External Field Detector output */
#define st25r3916IsExtFieldOn() \
st25r3916CheckReg( \
ST25R3916_REG_AUX_DISPLAY, \
ST25R3916_REG_AUX_DISPLAY_efd_o, \
ST25R3916_REG_AUX_DISPLAY_efd_o)
/*! Checks if Transmitter is enabled (Field On) */
#define st25r3916IsTxEnabled() \
st25r3916CheckReg( \
ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_tx_en, ST25R3916_REG_OP_CONTROL_tx_en)
/*! Checks if NRT is in EMV mode */
#define st25r3916IsNRTinEMV() \
st25r3916CheckReg( \
ST25R3916_REG_TIMER_EMV_CONTROL, \
ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv, \
ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv_on)
/*! Checks if last FIFO byte is complete */
#define st25r3916IsLastFIFOComplete() \
st25r3916CheckReg(ST25R3916_REG_FIFO_STATUS2, ST25R3916_REG_FIFO_STATUS2_fifo_lb_mask, 0)
/*! Checks if the Oscillator is enabled */
#define st25r3916IsOscOn() \
st25r3916CheckReg( \
ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_en, ST25R3916_REG_OP_CONTROL_en)
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief Initialise ST25R3916 driver
*
* This function initialises the ST25R3916 driver.
*
* \return ERR_NONE : Operation successful
* \return ERR_HW_MISMATCH : Expected HW do not match or communication error
* \return ERR_IO : Error during communication selftest. Check communication interface
* \return ERR_TIMEOUT : Timeout during IRQ selftest. Check IRQ handling
* \return ERR_SYSTEM : Failure during oscillator activation or timer error
*
*****************************************************************************
*/
ReturnCode st25r3916Initialize(void);
/*!
*****************************************************************************
* \brief Deinitialize ST25R3916 driver
*
* Calling this function deinitializes the ST25R3916 driver.
*
*****************************************************************************
*/
void st25r3916Deinitialize(void);
/*!
*****************************************************************************
* \brief Turn on Oscillator and Regulator
*
* This function turn on oscillator and regulator and waits for the
* oscillator to become stable
*
* \return ERR_SYSTEM : Failure dusring Oscillator activation
* \return ERR_NONE : No error, Oscillator is active and stable, Regulator is on
*
*****************************************************************************
*/
ReturnCode st25r3916OscOn(void);
/*!
*****************************************************************************
* \brief Sets the bitrate
*
* This function sets the bitrates for rx and tx
*
* \param txrate : speed is 2^txrate * 106 kb/s
* 0xff : don't set txrate (ST25R3916_BR_DO_NOT_SET)
* \param rxrate : speed is 2^rxrate * 106 kb/s
* 0xff : don't set rxrate (ST25R3916_BR_DO_NOT_SET)
*
* \return ERR_PARAM: At least one bit rate was invalid
* \return ERR_NONE : No error, both bit rates were set
*
*****************************************************************************
*/
ReturnCode st25r3916SetBitrate(uint8_t txrate, uint8_t rxrate);
/*!
*****************************************************************************
* \brief Adjusts supply regulators according to the current supply voltage
*
* This function the power level is measured in maximum load conditions and
* the regulated voltage reference is set to 250mV below this level.
* Execution of this function lasts around 5ms.
*
* The regulated voltages will be set to the result of Adjust Regulators
*
* \param [out] result_mV : Result of calibration in milliVolts
*
* \return ERR_IO : Error during communication with ST25R3916
* \return ERR_NONE : No error
*
*****************************************************************************
*/
ReturnCode st25r3916AdjustRegulators(uint16_t* result_mV);
/*!
*****************************************************************************
* \brief Measure Amplitude
*
* This function measured the amplitude on the RFI inputs and stores the
* result in parameter \a result.
*
* \param[out] result: result of RF measurement.
*
* \return ERR_PARAM : Invalid parameter
* \return ERR_NONE : No error
*
*****************************************************************************
*/
ReturnCode st25r3916MeasureAmplitude(uint8_t* result);
/*!
*****************************************************************************
* \brief Measure Power Supply
*
* This function executes Measure Power Supply and returns the raw value
*
* \param[in] mpsv : one of ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd
* ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_rf
* ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_a
* ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_d
* ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_am
*
* \return the measured voltage in raw format.
*
*****************************************************************************
*/
uint8_t st25r3916MeasurePowerSupply(uint8_t mpsv);
/*!
*****************************************************************************
* \brief Measure Voltage
*
* This function measures the voltage on one of VDD and VDD_* and returns
* the result in mV
*
* \param[in] mpsv : one of ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd
* ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_rf
* ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_a
* ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_d
* or ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_am
*
* \return the measured voltage in mV
*
*****************************************************************************
*/
uint16_t st25r3916MeasureVoltage(uint8_t mpsv);
/*!
*****************************************************************************
* \brief Measure Phase
*
* This function performs a Phase measurement.
* The result is stored in the \a result parameter.
*
* \param[out] result: 8 bit long result of the measurement.
*
* \return ERR_PARAM : Invalid parameter
* \return ERR_NONE : No error
*
*****************************************************************************
*/
ReturnCode st25r3916MeasurePhase(uint8_t* result);
/*!
*****************************************************************************
* \brief Measure Capacitance
*
* This function performs the capacitance measurement and stores the
* result in parameter \a result.
*
* \param[out] result: 8 bit long result of RF measurement.
*
* \return ERR_PARAM : Invalid parameter
* \return ERR_NONE : No error
*
*****************************************************************************
*/
ReturnCode st25r3916MeasureCapacitance(uint8_t* result);
/*!
*****************************************************************************
* \brief Calibrates Capacitive Sensor
*
* This function performs automatic calibration of the capacitive sensor
* and stores the result in parameter \a result.
*
* \warning To avoid interference with Xtal oscillator and reader magnetic
* field, it is strongly recommended to perform calibration
* in Power-down mode only.
* This method does not modify the Oscillator nor transmitter state,
* these should be configured before by user.
*
* \param[out] result: 5 bit long result of the calibration.
* Binary weighted, step 0.1 pF, max 3.1 pF
*
* \return ERR_PARAM : Invalid parameter
* \return ERR_IO : The calibration was not successful
* \return ERR_NONE : No error
*
*****************************************************************************
*/
ReturnCode st25r3916CalibrateCapacitiveSensor(uint8_t* result);
/*!
*****************************************************************************
* \brief Get NRT time
*
* This returns the last value set on the NRT
*
* \warning it does not read chip register, just the sw var that contains the
* last value set before
*
* \return the value of the NRT in 64/fc
*/
uint32_t st25r3916GetNoResponseTime(void);
/*!
*****************************************************************************
* \brief Set NRT time
*
* This function sets the No Response Time with the given value
*
* \param [in] nrt_64fcs : no response time in steps of 64/fc (4.72us)
*
* \return ERR_PARAM : Invalid parameter (time is too large)
* \return ERR_NONE : No error
*
*****************************************************************************
*/
ReturnCode st25r3916SetNoResponseTime(uint32_t nrt_64fcs);
/*!
*****************************************************************************
* \brief Set and Start NRT
*
* This function sets the No Response Time with the given value and
* immediately starts it
* Used when needs to add more time before timeout without performing Tx
*
* \param [in] nrt_64fcs : no response time in steps of 64/fc (4.72us)
*
* \return ERR_PARAM : Invalid parameter
* \return ERR_NONE : No error
*
*****************************************************************************
*/
ReturnCode st25r3916SetStartNoResponseTimer(uint32_t nrt_64fcs);
/*!
*****************************************************************************
* \brief Set GPT time
*
* This function sets the General Purpose Timer time registers
*
* \param [in] gpt_8fcs : general purpose timer timeout in steps of 8/fc (590ns)
*
*****************************************************************************
*/
void st25r3916SetGPTime(uint16_t gpt_8fcs);
/*!
*****************************************************************************
* \brief Set and Start GPT
*
* This function sets the General Purpose Timer with the given timeout and
* immediately starts it ONLY if the trigger source is not set to none.
*
* \param [in] gpt_8fcs : general purpose timer timeout in steps of8/fc (590ns)
* \param [in] trigger_source : no trigger, start of Rx, end of Rx, end of Tx in NFC mode
*
* \return ERR_PARAM : Invalid parameter
* \return ERR_NONE : No error
*
*****************************************************************************
*/
ReturnCode st25r3916SetStartGPTimer(uint16_t gpt_8fcs, uint8_t trigger_source);
/*!
*****************************************************************************
* \brief Sets the number Tx Bits
*
* Sets ST25R3916 internal registers with correct number of complete bytes and
* bits to be sent
*
* \param [in] nBits : number of bits to be set/transmitted
*
*****************************************************************************
*/
void st25r3916SetNumTxBits(uint16_t nBits);
/*!
*****************************************************************************
* \brief Get amount of bytes in FIFO
*
* Gets the number of bytes currently in the FIFO
*
* \return the number of bytes currently in the FIFO
*
*****************************************************************************
*/
uint16_t st25r3916GetNumFIFOBytes(void);
/*!
*****************************************************************************
* \brief Get amount of bits of the last FIFO byte if incomplete
*
* Gets the number of bits of the last FIFO byte if incomplete
*
* \return the number of bits of the last FIFO byte if incomplete, 0 if
* the last byte is complete
*
*****************************************************************************
*/
uint8_t st25r3916GetNumFIFOLastBits(void);
/*!
*****************************************************************************
* \brief Perform Collision Avoidance
*
* Performs Collision Avoidance with the given threshold and with the
* n number of TRFW
*
* \param[in] FieldONCmd : Field ON command to be executed ST25R3916_CMD_INITIAL_RF_COLLISION
* or ST25R3916_CMD_RESPONSE_RF_COLLISION_N
* \param[in] pdThreshold : Peer Detection Threshold (ST25R3916_REG_FIELD_THRESHOLD_trg_xx)
* 0xff : don't set Threshold (ST25R3916_THRESHOLD_DO_NOT_SET)
* \param[in] caThreshold : Collision Avoidance Threshold (ST25R3916_REG_FIELD_THRESHOLD_rfe_xx)
* 0xff : don't set Threshold (ST25R3916_THRESHOLD_DO_NOT_SET)
* \param[in] nTRFW : Number of TRFW
*
* \return ERR_PARAM : Invalid parameter
* \return ERR_RF_COLLISION : Collision detected
* \return ERR_NONE : No collision detected
*
*****************************************************************************
*/
ReturnCode st25r3916PerformCollisionAvoidance(
uint8_t FieldONCmd,
uint8_t pdThreshold,
uint8_t caThreshold,
uint8_t nTRFW);
/*!
*****************************************************************************
* \brief Check Identity
*
* Checks if the chip ID is as expected.
*
* 5 bit IC type code for ST25R3916: 00101
* The 3 lsb contain the IC revision code
*
* \param[out] rev : the IC revision code
*
* \return true when IC type is as expected
* \return false otherwise
*/
bool st25r3916CheckChipID(uint8_t* rev);
/*!
*****************************************************************************
* \brief Retrieves all internal registers from ST25R3916
*
* \param[out] regDump : pointer to the struct/buffer where the reg dump
* will be written
*
* \return ERR_PARAM : Invalid parameter
* \return ERR_NONE : No error
*****************************************************************************
*/
ReturnCode st25r3916GetRegsDump(t_st25r3916Regs* regDump);
/*!
*****************************************************************************
* \brief Check if command is valid
*
* Checks if the given command is a valid ST25R3916 command
*
* \param[in] cmd: Command to check
*
* \return true if is a valid command
* \return false otherwise
*
*****************************************************************************
*/
bool st25r3916IsCmdValid(uint8_t cmd);
/*!
*****************************************************************************
* \brief Configure the stream mode of ST25R3916
*
* This function initializes the stream with the given parameters
*
* \param[in] config : all settings for bitrates, type, etc.
*
* \return ERR_PARAM : Invalid parameter
* \return ERR_NONE : No error, stream mode driver initialized
*
*****************************************************************************
*/
ReturnCode st25r3916StreamConfigure(const struct st25r3916StreamConfig* config);
/*!
*****************************************************************************
* \brief Executes a direct command and returns the result
*
* This function executes the direct command given by \a cmd waits for
* \a sleeptime for I_dct and returns the result read from register \a resreg.
* The value of cmd is not checked.
*
* \param[in] cmd : direct command to execute
* \param[in] resReg: address of the register containing the result
* \param[in] tout : time in milliseconds to wait before reading the result
* \param[out] result: result
*
* \return ERR_NONE : No error
*
*****************************************************************************
*/
ReturnCode
st25r3916ExecuteCommandAndGetResult(uint8_t cmd, uint8_t resReg, uint8_t tout, uint8_t* result);
/*!
*****************************************************************************
* \brief Gets the RSSI values
*
* This function gets the RSSI value of the previous reception taking into
* account the gain reductions that were used.
* RSSI value for both AM and PM channel can be retrieved.
*
* \param[out] amRssi: the RSSI on the AM channel expressed in mV
* \param[out] pmRssi: the RSSI on the PM channel expressed in mV
*
* \return ERR_PARAM : Invalid parameter
* \return ERR_NONE : No error
*
*****************************************************************************
*/
ReturnCode st25r3916GetRSSI(uint16_t* amRssi, uint16_t* pmRssi);
#endif /* ST25R3916_H */
/**
* @}
*
* @}
*
* @}
*
* @}
*/
@@ -1,366 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R3916 firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file st25r3916_aat.c
*
* \author
*
* \brief ST25R3916 Antenna Tuning
*
* The antenna tuning algorithm tries to find the optimal settings for
* the AAT_A and AAT_B registers, which are connected to variable capacitors
* to tune the antenna matching.
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "st25r3916_aat.h"
#include "utils.h"
#include "st_errno.h"
#include "st25r3916.h"
#include "st25r3916_com.h"
#include "platform.h"
#include "rfal_chip.h"
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define ST25R3916_AAT_CAP_DELAY_MAX 10 /*!< Max Variable Capacitor settle delay */
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
#define st25r3916AatLog(...) /* platformLog(__VA_ARGS__) */ /*!< Logging macro */
/*
******************************************************************************
* LOCAL FUNCTION PROTOTYPES
******************************************************************************
*/
static ReturnCode aatHillClimb(
const struct st25r3916AatTuneParams* tuningParams,
struct st25r3916AatTuneResult* tuningStatus);
static int32_t aatGreedyDescent(
uint32_t* f_min,
const struct st25r3916AatTuneParams* tuningParams,
struct st25r3916AatTuneResult* tuningStatus,
int32_t previousDir);
static int32_t aatSteepestDescent(
uint32_t* f_min,
const struct st25r3916AatTuneParams* tuningParams,
struct st25r3916AatTuneResult* tuningStatus,
int32_t previousDir,
int32_t previousDir2);
static ReturnCode aatMeasure(
uint8_t serCap,
uint8_t parCap,
uint8_t* amplitude,
uint8_t* phase,
uint16_t* measureCnt);
static uint32_t
aatCalcF(const struct st25r3916AatTuneParams* tuningParams, uint8_t amplitude, uint8_t phase);
static ReturnCode aatStepDacVals(
const struct st25r3916AatTuneParams* tuningParams,
uint8_t* a,
uint8_t* b,
int32_t dir);
/*******************************************************************************/
ReturnCode st25r3916AatTune(
const struct st25r3916AatTuneParams* tuningParams,
struct st25r3916AatTuneResult* tuningStatus) {
ReturnCode err;
const struct st25r3916AatTuneParams* tp = tuningParams;
struct st25r3916AatTuneResult* ts = tuningStatus;
struct st25r3916AatTuneParams defaultTuningParams = {
.aat_a_min = 0,
.aat_a_max = 255,
.aat_a_start = 127,
.aat_a_stepWidth = 32,
.aat_b_min = 0,
.aat_b_max = 255,
.aat_b_start = 127,
.aat_b_stepWidth = 32,
.phaTarget = 128,
.phaWeight = 2,
.ampTarget = 196,
.ampWeight = 1,
.doDynamicSteps = true,
.measureLimit = 50,
};
struct st25r3916AatTuneResult defaultTuneResult;
if((NULL != tp) && ((tp->aat_a_min > tp->aat_a_max) || (tp->aat_a_start < tp->aat_a_min) ||
(tp->aat_a_start > tp->aat_a_max) || (tp->aat_b_min > tp->aat_b_max) ||
(tp->aat_b_start < tp->aat_b_min) || (tp->aat_b_start > tp->aat_b_max))) {
return ERR_PARAM;
}
if(NULL == tp) { /* Start from current caps with default params */
st25r3916ReadRegister(ST25R3916_REG_ANT_TUNE_A, &defaultTuningParams.aat_a_start);
st25r3916ReadRegister(ST25R3916_REG_ANT_TUNE_B, &defaultTuningParams.aat_b_start);
tp = &defaultTuningParams;
}
if(NULL == ts) {
ts = &defaultTuneResult;
}
ts->measureCnt = 0; /* Clear current measure count */
err = aatHillClimb(tp, ts);
return err;
}
/*******************************************************************************/
static ReturnCode aatHillClimb(
const struct st25r3916AatTuneParams* tuningParams,
struct st25r3916AatTuneResult* tuningStatus) {
ReturnCode err = ERR_NONE;
uint32_t f_min;
int32_t direction, gdirection;
uint8_t amp, phs;
struct st25r3916AatTuneParams tp = *tuningParams; // local copy to obey const
tuningStatus->aat_a = tuningParams->aat_a_start;
tuningStatus->aat_b = tuningParams->aat_b_start;
/* Get a proper start value */
aatMeasure(tuningStatus->aat_a, tuningStatus->aat_b, &amp, &phs, &tuningStatus->measureCnt);
f_min = aatCalcF(&tp, amp, phs);
direction = 0;
st25r3916AatLog("%d %d: %d***\n", tuningStatus->aat_a, tuningStatus->aat_b, f_min);
do {
direction =
0; /* Initially and after reducing step sizes we don't have a previous direction */
do {
/* With the greedy step below always executed aftwards the -direction does never need to be investigated */
direction = aatSteepestDescent(&f_min, &tp, tuningStatus, direction, -direction);
if(tuningStatus->measureCnt > tp.measureLimit) {
err = ERR_OVERRUN;
break;
}
do {
gdirection = aatGreedyDescent(&f_min, &tp, tuningStatus, direction);
if(tuningStatus->measureCnt > tp.measureLimit) {
err = ERR_OVERRUN;
break;
}
} while(0 != gdirection);
} while(0 != direction);
tp.aat_a_stepWidth /= 2U; /* Reduce step sizes */
tp.aat_b_stepWidth /= 2U;
} while(tp.doDynamicSteps && ((tp.aat_a_stepWidth > 0U) || (tp.aat_b_stepWidth > 0U)));
return err;
}
/*******************************************************************************/
static int32_t aatSteepestDescent(
uint32_t* f_min,
const struct st25r3916AatTuneParams* tuningParams,
struct st25r3916AatTuneResult* tuningStatus,
int32_t previousDir,
int32_t previousDir2) {
int32_t i;
uint8_t amp, phs;
uint32_t f;
int32_t bestdir =
0; /* Negative direction: decrease, Positive: increase. (-)1: aat_a, (-)2: aat_b */
for(i = -2; i <= 2; i++) {
uint8_t a = tuningStatus->aat_a, b = tuningStatus->aat_b;
if((0 == i) || (i == -previousDir) ||
(i == -previousDir2)) { /* Skip no direction and avoid going backwards */
continue;
}
if(0U != aatStepDacVals(
tuningParams,
&a,
&b,
i)) { /* If stepping did not change the value, omit this direction */
continue;
}
aatMeasure(a, b, &amp, &phs, &tuningStatus->measureCnt);
f = aatCalcF(tuningParams, amp, phs);
st25r3916AatLog("%d : %d %d: %d", i, a, b, f);
if(f < *f_min) { /* Value is better than all previous ones */
st25r3916AatLog("*");
*f_min = f;
bestdir = i;
}
st25r3916AatLog("\n");
}
if(0 != bestdir) { /* Walk into the best direction */
aatStepDacVals(tuningParams, &tuningStatus->aat_a, &tuningStatus->aat_b, bestdir);
}
return bestdir;
}
/*******************************************************************************/
static int32_t aatGreedyDescent(
uint32_t* f_min,
const struct st25r3916AatTuneParams* tuningParams,
struct st25r3916AatTuneResult* tuningStatus,
int32_t previousDir) {
uint8_t amp, phs;
uint32_t f;
uint8_t a = tuningStatus->aat_a, b = tuningStatus->aat_b;
if(0U != aatStepDacVals(
tuningParams,
&a,
&b,
previousDir)) { /* If stepping did not change the value, omit this direction */
return 0;
}
aatMeasure(a, b, &amp, &phs, &tuningStatus->measureCnt);
f = aatCalcF(tuningParams, amp, phs);
st25r3916AatLog("g : %d %d: %d", a, b, f);
if(f < *f_min) { /* Value is better than previous one */
st25r3916AatLog("*\n");
tuningStatus->aat_a = a;
tuningStatus->aat_b = b;
*f_min = f;
return previousDir;
}
st25r3916AatLog("\n");
return 0;
}
/*******************************************************************************/
static uint32_t
aatCalcF(const struct st25r3916AatTuneParams* tuningParams, uint8_t amplitude, uint8_t phase) {
/* f(amp, pha) = (ampWeight * |amp - ampTarget|) + (phaWeight * |pha - phaTarget|) */
uint8_t ampTarget = tuningParams->ampTarget;
uint8_t phaTarget = tuningParams->phaTarget;
uint32_t ampWeight = tuningParams->ampWeight;
uint32_t phaWeight = tuningParams->phaWeight;
/* Temp variables to avoid MISRA R10.8 (cast on composite expression) */
uint8_t ad = ((amplitude > ampTarget) ? (amplitude - ampTarget) : (ampTarget - amplitude));
uint8_t pd = ((phase > phaTarget) ? (phase - phaTarget) : (phaTarget - phase));
uint32_t ampDelta = (uint32_t)ad;
uint32_t phaDelta = (uint32_t)pd;
return ((ampWeight * ampDelta) + (phaWeight * phaDelta));
}
/*******************************************************************************/
static ReturnCode aatStepDacVals(
const struct st25r3916AatTuneParams* tuningParams,
uint8_t* a,
uint8_t* b,
int32_t dir) {
int16_t aat_a = (int16_t)*a, aat_b = (int16_t)*b;
switch(abs(dir)) { /* Advance by steps size in requested direction */
case 1:
aat_a = (dir < 0) ? (aat_a - (int16_t)tuningParams->aat_a_stepWidth) :
(aat_a + (int16_t)tuningParams->aat_a_stepWidth);
if(aat_a < (int16_t)tuningParams->aat_a_min) {
aat_a = (int16_t)tuningParams->aat_a_min;
}
if(aat_a > (int16_t)tuningParams->aat_a_max) {
aat_a = (int16_t)tuningParams->aat_a_max;
}
if((int16_t)*a == aat_a) {
return ERR_PARAM;
}
break;
case 2:
aat_b = (dir < 0) ? (aat_b - (int16_t)tuningParams->aat_b_stepWidth) :
(aat_b + (int16_t)tuningParams->aat_b_stepWidth);
if(aat_b < (int16_t)tuningParams->aat_b_min) {
aat_b = (int16_t)tuningParams->aat_b_min;
}
if(aat_b > (int16_t)tuningParams->aat_b_max) {
aat_b = (int16_t)tuningParams->aat_b_max;
}
if((int16_t)*b == aat_b) {
return ERR_PARAM;
}
break;
default:
return ERR_REQUEST;
}
/* We only get here if actual values have changed. In all other cases an error is returned */
*a = (uint8_t)aat_a;
*b = (uint8_t)aat_b;
return ERR_NONE;
}
/*******************************************************************************/
static ReturnCode aatMeasure(
uint8_t serCap,
uint8_t parCap,
uint8_t* amplitude,
uint8_t* phase,
uint16_t* measureCnt) {
ReturnCode err;
*amplitude = 0;
*phase = 0;
st25r3916WriteRegister(ST25R3916_REG_ANT_TUNE_A, serCap);
st25r3916WriteRegister(ST25R3916_REG_ANT_TUNE_B, parCap);
/* Wait till caps have settled.. */
platformDelay(ST25R3916_AAT_CAP_DELAY_MAX);
/* Get amplitude and phase .. */
err = rfalChipMeasureAmplitude(amplitude);
if(ERR_NONE == err) {
err = rfalChipMeasurePhase(phase);
}
if(measureCnt != NULL) {
(*measureCnt)++;
}
return err;
}
@@ -1,109 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R3916 firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file st25r3916_aat.h
*
* \author
*
* \brief ST25R3916 Antenna Tuning
*
* The antenna tuning algorithm tries to find the optimal settings for
* the AAT_A and AAT_B registers, which are connected to variable capacitors
* to tune the antenna matching.
*
*/
#ifndef ST25R3916_AAT_H
#define ST25R3916_AAT_H
#include "platform.h"
#include "st_errno.h"
/*
******************************************************************************
* GLOBAL DATATYPES
******************************************************************************
*/
/*!
* struct representing input parameters for the antenna tuning
*/
struct st25r3916AatTuneParams {
uint8_t aat_a_min; /*!< min value of A cap */
uint8_t aat_a_max; /*!< max value of A cap */
uint8_t aat_a_start; /*!< start value of A cap */
uint8_t aat_a_stepWidth; /*!< increment stepWidth for A cap */
uint8_t aat_b_min; /*!< min value of B cap */
uint8_t aat_b_max; /*!< max value of B cap */
uint8_t aat_b_start; /*!< start value of B cap */
uint8_t aat_b_stepWidth; /*!< increment stepWidth for B cap */
uint8_t phaTarget; /*!< target phase */
uint8_t phaWeight; /*!< weight of target phase */
uint8_t ampTarget; /*!< target amplitude */
uint8_t ampWeight; /*!< weight of target amplitude */
bool doDynamicSteps; /*!< dynamically reduce step size in algo */
uint8_t measureLimit; /*!< max number of allowed steps/measurements */
};
/*!
* struct representing out parameters for the antenna tuning
*/
struct st25r3916AatTuneResult {
uint8_t aat_a; /*!< serial cap after tuning */
uint8_t aat_b; /*!< parallel cap after tuning */
uint8_t pha; /*!< phase after tuning */
uint8_t amp; /*!< amplitude after tuning */
uint16_t measureCnt; /*!< number of measures performed */
};
/*!
*****************************************************************************
* \brief Perform antenna tuning
*
* This function starts an antenna tuning procedure by modifying the serial
* and parallel capacitors of the antenna matching circuit via the AAT_A
* and AAT_B registers.
*
* \param[in] tuningParams : Input parameters for the tuning algorithm. If NULL
* default values will be used.
* \param[out] tuningStatus : Result information of performed tuning. If NULL
* no further information is returned, only registers
* ST25R3916 (AAT_A,B) will be adapted.
*
* \return ERR_IO : Error during communication.
* \return ERR_PARAM : Invalid input parameters
* \return ERR_NONE : No error.
*
*****************************************************************************
*/
extern ReturnCode st25r3916AatTune(
const struct st25r3916AatTuneParams* tuningParams,
struct st25r3916AatTuneResult* tuningStatus);
#endif /* ST25R3916_AAT_H */
@@ -1,618 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R3916 firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file
*
* \author Gustavo Patricio
*
* \brief Implementation of ST25R3916 communication
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "st25r3916.h"
#include "st25r3916_com.h"
#include "st25r3916_led.h"
#include "st_errno.h"
#include "platform.h"
#include "utils.h"
/*
******************************************************************************
* LOCAL DEFINES
******************************************************************************
*/
#define ST25R3916_OPTIMIZE \
true /*!< Optimization switch: false always write value to register */
#define ST25R3916_I2C_ADDR \
(0xA0U >> 1) /*!< ST25R3916's default I2C address */
#define ST25R3916_REG_LEN 1U /*!< Byte length of a ST25R3916 register */
#define ST25R3916_WRITE_MODE \
(0U << 6) /*!< ST25R3916 Operation Mode: Write */
#define ST25R3916_READ_MODE \
(1U << 6) /*!< ST25R3916 Operation Mode: Read */
#define ST25R3916_CMD_MODE \
(3U << 6) /*!< ST25R3916 Operation Mode: Direct Command */
#define ST25R3916_FIFO_LOAD \
(0x80U) /*!< ST25R3916 Operation Mode: FIFO Load */
#define ST25R3916_FIFO_READ \
(0x9FU) /*!< ST25R3916 Operation Mode: FIFO Read */
#define ST25R3916_PT_A_CONFIG_LOAD \
(0xA0U) /*!< ST25R3916 Operation Mode: Passive Target Memory A-Config Load */
#define ST25R3916_PT_F_CONFIG_LOAD \
(0xA8U) /*!< ST25R3916 Operation Mode: Passive Target Memory F-Config Load */
#define ST25R3916_PT_TSN_DATA_LOAD \
(0xACU) /*!< ST25R3916 Operation Mode: Passive Target Memory TSN Load */
#define ST25R3916_PT_MEM_READ \
(0xBFU) /*!< ST25R3916 Operation Mode: Passive Target Memory Read */
#define ST25R3916_CMD_LEN \
(1U) /*!< ST25R3916 CMD length */
#define ST25R3916_BUF_LEN \
(ST25R3916_CMD_LEN + \
ST25R3916_FIFO_DEPTH) /*!< ST25R3916 communication buffer: CMD + FIFO length */
/*
******************************************************************************
* MACROS
******************************************************************************
*/
#ifdef RFAL_USE_I2C
#define st25r3916I2CStart() \
platformI2CStart() /*!< ST25R3916 HAL I2C driver macro to start a I2C transfer */
#define st25r3916I2CStop() \
platformI2CStop() /*!< ST25R3916 HAL I2C driver macro to stop a I2C transfer */
#define st25r3916I2CRepeatStart() \
platformI2CRepeatStart() /*!< ST25R3916 HAL I2C driver macro to repeat Start */
#define st25r3916I2CSlaveAddrWR(sA) \
platformI2CSlaveAddrWR( \
sA) /*!< ST25R3916 HAL I2C driver macro to repeat Start */
#define st25r3916I2CSlaveAddrRD(sA) \
platformI2CSlaveAddrRD( \
sA) /*!< ST25R3916 HAL I2C driver macro to repeat Start */
#endif /* RFAL_USE_I2C */
#if defined(ST25R_COM_SINGLETXRX) && !defined(RFAL_USE_I2C)
static uint8_t
comBuf[ST25R3916_BUF_LEN]; /*!< ST25R3916 communication buffer */
static uint16_t comBufIt; /*!< ST25R3916 communication buffer iterator */
#endif /* ST25R_COM_SINGLETXRX */
/*
******************************************************************************
* LOCAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
******************************************************************************
* \brief ST25R3916 communication Start
*
* This method performs the required actions to start communications with
* ST25R3916, either by SPI or I2C
******************************************************************************
*/
static void st25r3916comStart(void);
/*!
******************************************************************************
* \brief ST25R3916 communication Stop
*
* This method performs the required actions to terminate communications with
* ST25R3916, either by SPI or I2C
******************************************************************************
*/
static void st25r3916comStop(void);
/*!
******************************************************************************
* \brief ST25R3916 communication Repeat Start
*
* This method performs the required actions to repeat start a transmission
* with ST25R3916, either by SPI or I2C
******************************************************************************
*/
#ifdef RFAL_USE_I2C
static void st25r3916comRepeatStart(void);
#else
#define st25r3916comRepeatStart()
#endif /* RFAL_USE_I2C */
/*!
******************************************************************************
* \brief ST25R3916 communication Tx
*
* This method performs the required actions to transmit the given buffer
* to ST25R3916, either by SPI or I2C
*
* \param[in] txBuf : the buffer to transmit
* \param[in] txLen : the length of the buffer to transmit
* \param[in] last : true if last data to be transmitted
* \param[in] txOnly : true no reception is to be performed
*
******************************************************************************
*/
static void st25r3916comTx(const uint8_t* txBuf, uint16_t txLen, bool last, bool txOnly);
/*!
******************************************************************************
* \brief ST25R3916 communication Rx
*
* This method performs the required actions to receive from ST25R3916 the given
* amount of bytes, either by SPI or I2C
*
* \param[out] rxBuf : the buffer place the received bytes
* \param[in] rxLen : the length to receive
*
******************************************************************************
*/
static void st25r3916comRx(uint8_t* rxBuf, uint16_t rxLen);
/*!
******************************************************************************
* \brief ST25R3916 communication Tx Byte
*
* This helper method transmits a byte passed by value and not by reference
*
* \param[in] txByte : the value of the byte to be transmitted
* \param[in] last : true if last byte to be transmitted
* \param[in] txOnly : true no reception is to be performed
*
******************************************************************************
*/
static void st25r3916comTxByte(uint8_t txByte, bool last, bool txOnly);
/*
******************************************************************************
* LOCAL FUNCTION
******************************************************************************
*/
static void st25r3916comStart(void) {
/* Make this operation atomic, disabling ST25R3916 interrupt during communications*/
platformProtectST25RComm();
#ifdef RFAL_USE_I2C
/* I2C Start and send Slave Address */
st25r3916I2CStart();
st25r3916I2CSlaveAddrWR(ST25R3916_I2C_ADDR);
#else
/* Perform the chip select */
platformSpiSelect();
#if defined(ST25R_COM_SINGLETXRX)
comBufIt = 0; /* reset local buffer position */
#endif /* ST25R_COM_SINGLETXRX */
#endif /* RFAL_USE_I2C */
}
/*******************************************************************************/
static void st25r3916comStop(void) {
#ifdef RFAL_USE_I2C
/* Generate Stop signal */
st25r3916I2CStop();
#else
/* Release the chip select */
platformSpiDeselect();
#endif /* RFAL_USE_I2C */
/* reEnable the ST25R3916 interrupt */
platformUnprotectST25RComm();
}
/*******************************************************************************/
#ifdef RFAL_USE_I2C
static void st25r3916comRepeatStart(void) {
st25r3916I2CRepeatStart();
st25r3916I2CSlaveAddrRD(ST25R3916_I2C_ADDR);
}
#endif /* RFAL_USE_I2C */
/*******************************************************************************/
static void st25r3916comTx(const uint8_t* txBuf, uint16_t txLen, bool last, bool txOnly) {
NO_WARNING(last);
NO_WARNING(txOnly);
if(txLen > 0U) {
#ifdef RFAL_USE_I2C
platformI2CTx(txBuf, txLen, last, txOnly);
#else /* RFAL_USE_I2C */
#ifdef ST25R_COM_SINGLETXRX
ST_MEMCPY(
&comBuf[comBufIt],
txBuf,
MIN(txLen,
(ST25R3916_BUF_LEN -
comBufIt))); /* copy tx data to local buffer */
comBufIt +=
MIN(txLen,
(ST25R3916_BUF_LEN -
comBufIt)); /* store position on local buffer */
if(last && txOnly) /* only perform SPI transaction if no Rx will follow */
{
platformSpiTxRx(comBuf, NULL, comBufIt);
}
#else
platformSpiTxRx(txBuf, NULL, txLen);
#endif /* ST25R_COM_SINGLETXRX */
#endif /* RFAL_USE_I2C */
}
}
/*******************************************************************************/
static void st25r3916comRx(uint8_t* rxBuf, uint16_t rxLen) {
if(rxLen > 0U) {
#ifdef RFAL_USE_I2C
platformI2CRx(rxBuf, rxLen);
#else /* RFAL_USE_I2C */
#ifdef ST25R_COM_SINGLETXRX
ST_MEMSET(
&comBuf[comBufIt],
0x00,
MIN(rxLen,
(ST25R3916_BUF_LEN -
comBufIt))); /* clear outgoing buffer */
platformSpiTxRx(
comBuf,
comBuf,
MIN((comBufIt + rxLen),
ST25R3916_BUF_LEN)); /* transceive as a single SPI call */
ST_MEMCPY(
rxBuf,
&comBuf[comBufIt],
MIN(rxLen,
(ST25R3916_BUF_LEN -
comBufIt))); /* copy from local buf to output buffer and skip cmd byte */
#else
if(rxBuf != NULL) {
ST_MEMSET(
rxBuf, 0x00, rxLen); /* clear outgoing buffer */
}
platformSpiTxRx(NULL, rxBuf, rxLen);
#endif /* ST25R_COM_SINGLETXRX */
#endif /* RFAL_USE_I2C */
}
}
/*******************************************************************************/
static void st25r3916comTxByte(uint8_t txByte, bool last, bool txOnly) {
uint8_t val = txByte; /* MISRA 17.8: use intermediate variable */
st25r3916comTx(&val, ST25R3916_REG_LEN, last, txOnly);
}
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
/*******************************************************************************/
ReturnCode st25r3916ReadRegister(uint8_t reg, uint8_t* val) {
return st25r3916ReadMultipleRegisters(reg, val, ST25R3916_REG_LEN);
}
/*******************************************************************************/
ReturnCode st25r3916ReadMultipleRegisters(uint8_t reg, uint8_t* values, uint8_t length) {
if(length > 0U) {
st25r3916comStart();
/* If is a space-B register send a direct command first */
if((reg & ST25R3916_SPACE_B) != 0U) {
st25r3916comTxByte(ST25R3916_CMD_SPACE_B_ACCESS, false, false);
}
st25r3916comTxByte(((reg & ~ST25R3916_SPACE_B) | ST25R3916_READ_MODE), true, false);
st25r3916comRepeatStart();
st25r3916comRx(values, length);
st25r3916comStop();
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode st25r3916WriteRegister(uint8_t reg, uint8_t val) {
uint8_t value = val; /* MISRA 17.8: use intermediate variable */
return st25r3916WriteMultipleRegisters(reg, &value, ST25R3916_REG_LEN);
}
/*******************************************************************************/
ReturnCode st25r3916WriteMultipleRegisters(uint8_t reg, const uint8_t* values, uint8_t length) {
if(length > 0U) {
st25r3916comStart();
if((reg & ST25R3916_SPACE_B) != 0U) {
st25r3916comTxByte(ST25R3916_CMD_SPACE_B_ACCESS, false, true);
}
st25r3916comTxByte(((reg & ~ST25R3916_SPACE_B) | ST25R3916_WRITE_MODE), false, true);
st25r3916comTx(values, length, true, true);
st25r3916comStop();
/* Send a WriteMultiReg event to LED handling */
st25r3916ledEvtWrMultiReg(reg, values, length);
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode st25r3916WriteFifo(const uint8_t* values, uint16_t length) {
if(length > ST25R3916_FIFO_DEPTH) {
return ERR_PARAM;
}
if(length > 0U) {
st25r3916comStart();
st25r3916comTxByte(ST25R3916_FIFO_LOAD, false, true);
st25r3916comTx(values, length, true, true);
st25r3916comStop();
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode st25r3916ReadFifo(uint8_t* buf, uint16_t length) {
if(length > 0U) {
st25r3916comStart();
st25r3916comTxByte(ST25R3916_FIFO_READ, true, false);
st25r3916comRepeatStart();
st25r3916comRx(buf, length);
st25r3916comStop();
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode st25r3916WritePTMem(const uint8_t* values, uint16_t length) {
if(length > ST25R3916_PTM_LEN) {
return ERR_PARAM;
}
if(length > 0U) {
st25r3916comStart();
st25r3916comTxByte(ST25R3916_PT_A_CONFIG_LOAD, false, true);
st25r3916comTx(values, length, true, true);
st25r3916comStop();
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode st25r3916ReadPTMem(uint8_t* values, uint16_t length) {
uint8_t
tmp[ST25R3916_REG_LEN +
ST25R3916_PTM_LEN]; /* local buffer to handle prepended byte on I2C and SPI */
if(length > 0U) {
if(length > ST25R3916_PTM_LEN) {
return ERR_PARAM;
}
st25r3916comStart();
st25r3916comTxByte(ST25R3916_PT_MEM_READ, true, false);
st25r3916comRepeatStart();
st25r3916comRx(tmp, (ST25R3916_REG_LEN + length)); /* skip prepended byte */
st25r3916comStop();
/* Copy PTMem content without prepended byte */
ST_MEMCPY(values, (tmp + ST25R3916_REG_LEN), length);
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode st25r3916WritePTMemF(const uint8_t* values, uint16_t length) {
if(length > (ST25R3916_PTM_F_LEN + ST25R3916_PTM_TSN_LEN)) {
return ERR_PARAM;
}
if(length > 0U) {
st25r3916comStart();
st25r3916comTxByte(ST25R3916_PT_F_CONFIG_LOAD, false, true);
st25r3916comTx(values, length, true, true);
st25r3916comStop();
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode st25r3916WritePTMemTSN(const uint8_t* values, uint16_t length) {
if(length > ST25R3916_PTM_TSN_LEN) {
return ERR_PARAM;
}
if(length > 0U) {
st25r3916comStart();
st25r3916comTxByte(ST25R3916_PT_TSN_DATA_LOAD, false, true);
st25r3916comTx(values, length, true, true);
st25r3916comStop();
}
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode st25r3916ExecuteCommand(uint8_t cmd) {
st25r3916comStart();
st25r3916comTxByte((cmd | ST25R3916_CMD_MODE), true, true);
st25r3916comStop();
/* Send a cmd event to LED handling */
st25r3916ledEvtCmd(cmd);
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode st25r3916ReadTestRegister(uint8_t reg, uint8_t* val) {
st25r3916comStart();
st25r3916comTxByte(ST25R3916_CMD_TEST_ACCESS, false, false);
st25r3916comTxByte((reg | ST25R3916_READ_MODE), true, false);
st25r3916comRepeatStart();
st25r3916comRx(val, ST25R3916_REG_LEN);
st25r3916comStop();
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode st25r3916WriteTestRegister(uint8_t reg, uint8_t val) {
uint8_t value = val; /* MISRA 17.8: use intermediate variable */
st25r3916comStart();
st25r3916comTxByte(ST25R3916_CMD_TEST_ACCESS, false, true);
st25r3916comTxByte((reg | ST25R3916_WRITE_MODE), false, true);
st25r3916comTx(&value, ST25R3916_REG_LEN, true, true);
st25r3916comStop();
return ERR_NONE;
}
/*******************************************************************************/
ReturnCode st25r3916ClrRegisterBits(uint8_t reg, uint8_t clr_mask) {
ReturnCode ret;
uint8_t rdVal;
/* Read current reg value */
EXIT_ON_ERR(ret, st25r3916ReadRegister(reg, &rdVal));
/* Only perform a Write if value to be written is different */
if(ST25R3916_OPTIMIZE && (rdVal == (uint8_t)(rdVal & ~clr_mask))) {
return ERR_NONE;
}
/* Write new reg value */
return st25r3916WriteRegister(reg, (uint8_t)(rdVal & ~clr_mask));
}
/*******************************************************************************/
ReturnCode st25r3916SetRegisterBits(uint8_t reg, uint8_t set_mask) {
ReturnCode ret;
uint8_t rdVal;
/* Read current reg value */
EXIT_ON_ERR(ret, st25r3916ReadRegister(reg, &rdVal));
/* Only perform a Write if the value to be written is different */
if(ST25R3916_OPTIMIZE && (rdVal == (rdVal | set_mask))) {
return ERR_NONE;
}
/* Write new reg value */
return st25r3916WriteRegister(reg, (rdVal | set_mask));
}
/*******************************************************************************/
ReturnCode st25r3916ChangeRegisterBits(uint8_t reg, uint8_t valueMask, uint8_t value) {
return st25r3916ModifyRegister(reg, valueMask, (valueMask & value));
}
/*******************************************************************************/
ReturnCode st25r3916ModifyRegister(uint8_t reg, uint8_t clr_mask, uint8_t set_mask) {
ReturnCode ret;
uint8_t rdVal;
uint8_t wrVal;
/* Read current reg value */
EXIT_ON_ERR(ret, st25r3916ReadRegister(reg, &rdVal));
/* Compute new value */
wrVal = (uint8_t)(rdVal & ~clr_mask);
wrVal |= set_mask;
/* Only perform a Write if the value to be written is different */
if(ST25R3916_OPTIMIZE && (rdVal == wrVal)) {
return ERR_NONE;
}
/* Write new reg value */
return st25r3916WriteRegister(reg, wrVal);
}
/*******************************************************************************/
ReturnCode st25r3916ChangeTestRegisterBits(uint8_t reg, uint8_t valueMask, uint8_t value) {
ReturnCode ret;
uint8_t rdVal;
uint8_t wrVal;
/* Read current reg value */
EXIT_ON_ERR(ret, st25r3916ReadTestRegister(reg, &rdVal));
/* Compute new value */
wrVal = (uint8_t)(rdVal & ~valueMask);
wrVal |= (uint8_t)(value & valueMask);
/* Only perform a Write if the value to be written is different */
if(ST25R3916_OPTIMIZE && (rdVal == wrVal)) {
return ERR_NONE;
}
/* Write new reg value */
return st25r3916WriteTestRegister(reg, wrVal);
}
/*******************************************************************************/
bool st25r3916CheckReg(uint8_t reg, uint8_t mask, uint8_t val) {
uint8_t regVal;
regVal = 0;
st25r3916ReadRegister(reg, &regVal);
return ((regVal & mask) == val);
}
/*******************************************************************************/
bool st25r3916IsRegValid(uint8_t reg) {
#pragma GCC diagnostic ignored "-Wtype-limits"
if(!(((int16_t)reg >= (int32_t)ST25R3916_REG_IO_CONF1) &&
(reg <= (ST25R3916_SPACE_B | ST25R3916_REG_IC_IDENTITY)))) {
return false;
}
return true;
}
@@ -1,231 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R3916 firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file
*
* \author Gustavo Patricio
*
* \brief ST25R3916 Interrupt handling
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "st25r3916_irq.h"
#include "st25r3916_com.h"
#include "st25r3916_led.h"
#include "st25r3916.h"
#include "utils.h"
/*
******************************************************************************
* LOCAL DATA TYPES
******************************************************************************
*/
/*! Holds current and previous interrupt callback pointer as well as current Interrupt status and mask */
typedef struct {
void (*prevCallback)(void); /*!< call back function for ST25R3916 interrupt */
void (*callback)(void); /*!< call back function for ST25R3916 interrupt */
uint32_t status; /*!< latest interrupt status */
uint32_t mask; /*!< Interrupt mask. Negative mask = ST25R3916 mask regs */
} st25r3916Interrupt;
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
/*! Length of the interrupt registers */
#define ST25R3916_INT_REGS_LEN ((ST25R3916_REG_IRQ_TARGET - ST25R3916_REG_IRQ_MAIN) + 1U)
/*
******************************************************************************
* GLOBAL VARIABLES
******************************************************************************
*/
static volatile st25r3916Interrupt st25r3916interrupt; /*!< Instance of ST25R3916 interrupt */
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
void st25r3916InitInterrupts(void) {
platformIrqST25RPinInitialize();
platformIrqST25RSetCallback(st25r3916Isr);
st25r3916interrupt.callback = NULL;
st25r3916interrupt.prevCallback = NULL;
st25r3916interrupt.status = ST25R3916_IRQ_MASK_NONE;
st25r3916interrupt.mask = ST25R3916_IRQ_MASK_NONE;
}
/*******************************************************************************/
void st25r3916Isr(void) {
st25r3916CheckForReceivedInterrupts();
// Check if callback is set and run it
if(NULL != st25r3916interrupt.callback) {
st25r3916interrupt.callback();
}
}
/*******************************************************************************/
void st25r3916CheckForReceivedInterrupts(void) {
uint8_t iregs[ST25R3916_INT_REGS_LEN];
uint32_t irqStatus;
/* Initialize iregs */
irqStatus = ST25R3916_IRQ_MASK_NONE;
ST_MEMSET(iregs, (int32_t)(ST25R3916_IRQ_MASK_ALL & 0xFFU), ST25R3916_INT_REGS_LEN);
/* In case the IRQ is Edge (not Level) triggered read IRQs until done */
while(platformGpioIsHigh(ST25R_INT_PORT, ST25R_INT_PIN)) {
st25r3916ReadMultipleRegisters(ST25R3916_REG_IRQ_MAIN, iregs, ST25R3916_INT_REGS_LEN);
irqStatus |= (uint32_t)iregs[0];
irqStatus |= (uint32_t)iregs[1] << 8;
irqStatus |= (uint32_t)iregs[2] << 16;
irqStatus |= (uint32_t)iregs[3] << 24;
}
/* Forward all interrupts, even masked ones to application */
platformProtectST25RIrqStatus();
st25r3916interrupt.status |= irqStatus;
platformUnprotectST25RIrqStatus();
/* Send an IRQ event to LED handling */
st25r3916ledEvtIrq(st25r3916interrupt.status);
}
/*******************************************************************************/
void st25r3916ModifyInterrupts(uint32_t clr_mask, uint32_t set_mask) {
uint8_t i;
uint32_t old_mask;
uint32_t new_mask;
old_mask = st25r3916interrupt.mask;
new_mask = ((~old_mask & set_mask) | (old_mask & clr_mask));
st25r3916interrupt.mask &= ~clr_mask;
st25r3916interrupt.mask |= set_mask;
for(i = 0; i < ST25R3916_INT_REGS_LEN; i++) {
if(((new_mask >> (8U * i)) & 0xFFU) == 0U) {
continue;
}
st25r3916WriteRegister(
ST25R3916_REG_IRQ_MASK_MAIN + i,
(uint8_t)((st25r3916interrupt.mask >> (8U * i)) & 0xFFU));
}
return;
}
/*******************************************************************************/
uint32_t st25r3916WaitForInterruptsTimed(uint32_t mask, uint16_t tmo) {
uint32_t tmrDelay;
uint32_t status;
tmrDelay = platformTimerCreate(tmo);
/* Run until specific interrupt has happen or the timer has expired */
do {
status = (st25r3916interrupt.status & mask);
} while((!platformTimerIsExpired(tmrDelay) || (tmo == 0U)) && (status == 0U));
platformTimerDestroy(tmrDelay);
status = st25r3916interrupt.status & mask;
platformProtectST25RIrqStatus();
st25r3916interrupt.status &= ~status;
platformUnprotectST25RIrqStatus();
return status;
}
/*******************************************************************************/
uint32_t st25r3916GetInterrupt(uint32_t mask) {
uint32_t irqs;
irqs = (st25r3916interrupt.status & mask);
if(irqs != ST25R3916_IRQ_MASK_NONE) {
platformProtectST25RIrqStatus();
st25r3916interrupt.status &= ~irqs;
platformUnprotectST25RIrqStatus();
}
return irqs;
}
/*******************************************************************************/
void st25r3916ClearAndEnableInterrupts(uint32_t mask) {
st25r3916GetInterrupt(mask);
st25r3916EnableInterrupts(mask);
}
/*******************************************************************************/
void st25r3916EnableInterrupts(uint32_t mask) {
st25r3916ModifyInterrupts(mask, 0);
}
/*******************************************************************************/
void st25r3916DisableInterrupts(uint32_t mask) {
st25r3916ModifyInterrupts(0, mask);
}
/*******************************************************************************/
void st25r3916ClearInterrupts(void) {
uint8_t iregs[ST25R3916_INT_REGS_LEN];
st25r3916ReadMultipleRegisters(ST25R3916_REG_IRQ_MAIN, iregs, ST25R3916_INT_REGS_LEN);
platformProtectST25RIrqStatus();
st25r3916interrupt.status = ST25R3916_IRQ_MASK_NONE;
platformUnprotectST25RIrqStatus();
return;
}
/*******************************************************************************/
void st25r3916IRQCallbackSet(void (*cb)(void)) {
st25r3916interrupt.prevCallback = st25r3916interrupt.callback;
st25r3916interrupt.callback = cb;
}
/*******************************************************************************/
void st25r3916IRQCallbackRestore(void) {
st25r3916interrupt.callback = st25r3916interrupt.prevCallback;
st25r3916interrupt.prevCallback = NULL;
}
@@ -1,296 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R3916 firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file
*
* \author Gustavo Patricio
*
* \brief ST25R3916 Interrupt handling
*
* \addtogroup RFAL
* @{
*
* \addtogroup RFAL-HAL
* \brief RFAL Hardware Abstraction Layer
* @{
*
* \addtogroup ST25R3916
* \brief RFAL ST25R3916 Driver
* @{
*
* \addtogroup ST25R3916_IRQ
* \brief RFAL ST25R3916 IRQ
* @{
*
*/
#ifndef ST25R3916_IRQ_H
#define ST25R3916_IRQ_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define ST25R3916_IRQ_MASK_ALL \
(uint32_t)(0xFFFFFFFFUL) /*!< All ST25R3916 interrupt sources */
#define ST25R3916_IRQ_MASK_NONE \
(uint32_t)(0x00000000UL) /*!< No ST25R3916 interrupt source */
/* Main interrupt register */
#define ST25R3916_IRQ_MASK_OSC \
(uint32_t)(0x00000080U) /*!< ST25R3916 oscillator stable interrupt */
#define ST25R3916_IRQ_MASK_FWL \
(uint32_t)(0x00000040U) /*!< ST25R3916 FIFO water level interrupt */
#define ST25R3916_IRQ_MASK_RXS \
(uint32_t)(0x00000020U) /*!< ST25R3916 start of receive interrupt */
#define ST25R3916_IRQ_MASK_RXE \
(uint32_t)(0x00000010U) /*!< ST25R3916 end of receive interrupt */
#define ST25R3916_IRQ_MASK_TXE \
(uint32_t)(0x00000008U) /*!< ST25R3916 end of transmission interrupt */
#define ST25R3916_IRQ_MASK_COL \
(uint32_t)(0x00000004U) /*!< ST25R3916 bit collision interrupt */
#define ST25R3916_IRQ_MASK_RX_REST \
(uint32_t)(0x00000002U) /*!< ST25R3916 automatic reception restart interrupt */
#define ST25R3916_IRQ_MASK_RFU \
(uint32_t)(0x00000001U) /*!< ST25R3916 RFU interrupt */
/* Timer and NFC interrupt register */
#define ST25R3916_IRQ_MASK_DCT \
(uint32_t)(0x00008000U) /*!< ST25R3916 termination of direct command interrupt. */
#define ST25R3916_IRQ_MASK_NRE \
(uint32_t)(0x00004000U) /*!< ST25R3916 no-response timer expired interrupt */
#define ST25R3916_IRQ_MASK_GPE \
(uint32_t)(0x00002000U) /*!< ST25R3916 general purpose timer expired interrupt */
#define ST25R3916_IRQ_MASK_EON \
(uint32_t)(0x00001000U) /*!< ST25R3916 external field on interrupt */
#define ST25R3916_IRQ_MASK_EOF \
(uint32_t)(0x00000800U) /*!< ST25R3916 external field off interrupt */
#define ST25R3916_IRQ_MASK_CAC \
(uint32_t)(0x00000400U) /*!< ST25R3916 collision during RF collision avoidance interrupt */
#define ST25R3916_IRQ_MASK_CAT \
(uint32_t)(0x00000200U) /*!< ST25R3916 minimum guard time expired interrupt */
#define ST25R3916_IRQ_MASK_NFCT \
(uint32_t)(0x00000100U) /*!< ST25R3916 initiator bit rate recognised interrupt */
/* Error and wake-up interrupt register */
#define ST25R3916_IRQ_MASK_CRC \
(uint32_t)(0x00800000U) /*!< ST25R3916 CRC error interrupt */
#define ST25R3916_IRQ_MASK_PAR \
(uint32_t)(0x00400000U) /*!< ST25R3916 parity error interrupt */
#define ST25R3916_IRQ_MASK_ERR2 \
(uint32_t)(0x00200000U) /*!< ST25R3916 soft framing error interrupt */
#define ST25R3916_IRQ_MASK_ERR1 \
(uint32_t)(0x00100000U) /*!< ST25R3916 hard framing error interrupt */
#define ST25R3916_IRQ_MASK_WT \
(uint32_t)(0x00080000U) /*!< ST25R3916 wake-up interrupt */
#define ST25R3916_IRQ_MASK_WAM \
(uint32_t)(0x00040000U) /*!< ST25R3916 wake-up due to amplitude interrupt */
#define ST25R3916_IRQ_MASK_WPH \
(uint32_t)(0x00020000U) /*!< ST25R3916 wake-up due to phase interrupt */
#define ST25R3916_IRQ_MASK_WCAP \
(uint32_t)(0x00010000U) /*!< ST25R3916 wake-up due to capacitance measurement */
/* Passive Target Interrupt Register */
#define ST25R3916_IRQ_MASK_PPON2 \
(uint32_t)(0x80000000U) /*!< ST25R3916 PPON2 Field on waiting Timer interrupt */
#define ST25R3916_IRQ_MASK_SL_WL \
(uint32_t)(0x40000000U) /*!< ST25R3916 Passive target slot number water level interrupt */
#define ST25R3916_IRQ_MASK_APON \
(uint32_t)(0x20000000U) /*!< ST25R3916 Anticollision done and Field On interrupt */
#define ST25R3916_IRQ_MASK_RXE_PTA \
(uint32_t)(0x10000000U) /*!< ST25R3916 RXE with an automatic response interrupt */
#define ST25R3916_IRQ_MASK_WU_F \
(uint32_t)(0x08000000U) /*!< ST25R3916 212/424b/s Passive target interrupt: Active */
#define ST25R3916_IRQ_MASK_RFU2 \
(uint32_t)(0x04000000U) /*!< ST25R3916 RFU2 interrupt */
#define ST25R3916_IRQ_MASK_WU_A_X \
(uint32_t)(0x02000000U) /*!< ST25R3916 106kb/s Passive target state interrupt: Active* */
#define ST25R3916_IRQ_MASK_WU_A \
(uint32_t)(0x01000000U) /*!< ST25R3916 106kb/s Passive target state interrupt: Active */
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief Wait until an ST25R3916 interrupt occurs
*
* This function is used to access the ST25R3916 interrupt flags. Use this
* to wait for max. \a tmo milliseconds for the \b first interrupt indicated
* with mask \a mask to occur.
*
* \param[in] mask : mask indicating the interrupts to wait for.
* \param[in] tmo : time in milliseconds until timeout occurs. If set to 0
* the functions waits forever.
*
* \return : 0 if timeout occurred otherwise a mask indicating the cleared
* interrupts.
*
*****************************************************************************
*/
uint32_t st25r3916WaitForInterruptsTimed(uint32_t mask, uint16_t tmo);
/*!
*****************************************************************************
* \brief Get status for the given interrupt
*
* This function is used to check whether the interrupt given by \a mask
* has occurred. If yes the interrupt gets cleared. This function returns
* only status bits which are inside \a mask.
*
* \param[in] mask : mask indicating the interrupt to check for.
*
* \return the mask of the interrupts occurred
*
*****************************************************************************
*/
uint32_t st25r3916GetInterrupt(uint32_t mask);
/*!
*****************************************************************************
* \brief Init the 3916 interrupt
*
* This function is used to check whether the interrupt given by \a mask
* has occurred.
*
*****************************************************************************
*/
void st25r3916InitInterrupts(void);
/*!
*****************************************************************************
* \brief Modifies the Interrupt
*
* This function modifies the interrupt
*
* \param[in] clr_mask : bit mask to be cleared on the interrupt mask
* \param[in] set_mask : bit mask to be set on the interrupt mask
*****************************************************************************
*/
void st25r3916ModifyInterrupts(uint32_t clr_mask, uint32_t set_mask);
/*!
*****************************************************************************
* \brief Checks received interrupts
*
* Checks received interrupts and saves the result into global params
*****************************************************************************
*/
void st25r3916CheckForReceivedInterrupts(void);
/*!
*****************************************************************************
* \brief ISR Service routine
*
* This function modiefies the interrupt
*****************************************************************************
*/
void st25r3916Isr(void);
/*!
*****************************************************************************
* \brief Enable a given ST25R3916 Interrupt source
*
* This function enables all interrupts given by \a mask,
* ST25R3916_IRQ_MASK_ALL enables all interrupts.
*
* \param[in] mask: mask indicating the interrupts to be enabled
*
*****************************************************************************
*/
void st25r3916EnableInterrupts(uint32_t mask);
/*!
*****************************************************************************
* \brief Disable one or more a given ST25R3916 Interrupt sources
*
* This function disables all interrupts given by \a mask. 0xff disables all.
*
* \param[in] mask: mask indicating the interrupts to be disabled.
*
*****************************************************************************
*/
void st25r3916DisableInterrupts(uint32_t mask);
/*!
*****************************************************************************
* \brief Clear all ST25R3916 irq flags
*
*****************************************************************************
*/
void st25r3916ClearInterrupts(void);
/*!
*****************************************************************************
* \brief Clears and then enables the given ST25R3916 Interrupt sources
*
* \param[in] mask: mask indicating the interrupts to be cleared and enabled
*****************************************************************************
*/
void st25r3916ClearAndEnableInterrupts(uint32_t mask);
/*!
*****************************************************************************
* \brief Sets IRQ callback for the ST25R3916 interrupt
*
*****************************************************************************
*/
void st25r3916IRQCallbackSet(void (*cb)(void));
/*!
*****************************************************************************
* \brief Sets IRQ callback for the ST25R3916 interrupt
*
*****************************************************************************
*/
void st25r3916IRQCallbackRestore(void);
#endif /* ST25R3916_IRQ_H */
/**
* @}
*
* @}
*
* @}
*
* @}
*/
@@ -1,148 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R3916 firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file
*
* \author Gustavo Patricio
*
* \brief ST25R3916 LEDs handling
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "st25r3916_led.h"
#include "st25r3916_irq.h"
#include "st25r3916_com.h"
#include "st25r3916.h"
/*
******************************************************************************
* MACROS
******************************************************************************
*/
#ifdef PLATFORM_LED_RX_PIN
#define st25r3916ledRxOn() \
platformLedOn( \
PLATFORM_LED_RX_PORT, \
PLATFORM_LED_RX_PIN); /*!< LED Rx Pin On from system HAL */
#define st25r3916ledRxOff() \
platformLedOff( \
PLATFORM_LED_RX_PORT, \
PLATFORM_LED_RX_PIN); /*!< LED Rx Pin Off from system HAL */
#else /* PLATFORM_LED_RX_PIN */
#define st25r3916ledRxOn()
#define st25r3916ledRxOff()
#endif /* PLATFORM_LED_RX_PIN */
#ifdef PLATFORM_LED_FIELD_PIN
#define st25r3916ledFieldOn() \
platformLedOn( \
PLATFORM_LED_FIELD_PORT, \
PLATFORM_LED_FIELD_PIN); /*!< LED Field Pin On from system HAL */
#define st25r3916ledFieldOff() \
platformLedOff( \
PLATFORM_LED_FIELD_PORT, \
PLATFORM_LED_FIELD_PIN); /*!< LED Field Pin Off from system HAL */
#else /* PLATFORM_LED_FIELD_PIN */
#define st25r3916ledFieldOn()
#define st25r3916ledFieldOff()
#endif /* PLATFORM_LED_FIELD_PIN */
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
void st25r3916ledInit(void) {
/* Initialize LEDs if existing and defined */
platformLedsInitialize();
st25r3916ledRxOff();
st25r3916ledFieldOff();
}
/*******************************************************************************/
void st25r3916ledEvtIrq(uint32_t irqs) {
if((irqs & (ST25R3916_IRQ_MASK_TXE | ST25R3916_IRQ_MASK_CAT)) != 0U) {
st25r3916ledFieldOn();
}
if((irqs & (ST25R3916_IRQ_MASK_RXS | ST25R3916_IRQ_MASK_NFCT)) != 0U) {
st25r3916ledRxOn();
}
if((irqs & (ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_NRE | ST25R3916_IRQ_MASK_RX_REST |
ST25R3916_IRQ_MASK_RXE_PTA | ST25R3916_IRQ_MASK_WU_A | ST25R3916_IRQ_MASK_WU_A_X |
ST25R3916_IRQ_MASK_WU_F | ST25R3916_IRQ_MASK_RFU2)) != 0U) {
st25r3916ledRxOff();
}
}
/*******************************************************************************/
void st25r3916ledEvtWrReg(uint8_t reg, uint8_t val) {
if(reg == ST25R3916_REG_OP_CONTROL) {
if((ST25R3916_REG_OP_CONTROL_tx_en & val) != 0U) {
st25r3916ledFieldOn();
} else {
st25r3916ledFieldOff();
}
}
}
/*******************************************************************************/
void st25r3916ledEvtWrMultiReg(uint8_t reg, const uint8_t* vals, uint8_t len) {
uint8_t i;
for(i = 0; i < (len); i++) {
st25r3916ledEvtWrReg((reg + i), vals[i]);
}
}
/*******************************************************************************/
void st25r3916ledEvtCmd(uint8_t cmd) {
if((cmd >= ST25R3916_CMD_TRANSMIT_WITH_CRC) &&
(cmd <= ST25R3916_CMD_RESPONSE_RF_COLLISION_N)) {
st25r3916ledFieldOff();
}
if(cmd == ST25R3916_CMD_UNMASK_RECEIVE_DATA) {
st25r3916ledRxOff();
}
if(cmd == ST25R3916_CMD_SET_DEFAULT) {
st25r3916ledFieldOff();
st25r3916ledRxOff();
}
}
@@ -1,151 +0,0 @@
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R3916 firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file
*
* \author Gustavo Patricio
*
* \brief ST25R3916 LEDs handling
*
*
* \addtogroup RFAL
* @{
*
* \addtogroup RFAL-HAL
* \brief RFAL Hardware Abstraction Layer
* @{
*
* \addtogroup ST25R3916
* \brief RFAL ST25R3916 Driver
* @{
*
* \addtogroup ST25R3916_LED
* \brief RFAL ST25R3916 LED
* @{
*
*/
#ifndef ST25R3916_LED_H
#define ST25R3916_LED_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief ST25R3916 LED Initialize
*
* This function initializes the LEDs that represent ST25R3916 activity
*
*****************************************************************************
*/
void st25r3916ledInit(void);
/*!
*****************************************************************************
* \brief ST25R3916 LED Event Interrupt
*
* This function should be called upon a ST25R3916 Interrupt, providing
* the interrupt event with ST25R3916 irq flags to update LEDs
*
* \param[in] irqs: ST25R3916 irqs mask
*
*****************************************************************************
*/
void st25r3916ledEvtIrq(uint32_t irqs);
/*!
*****************************************************************************
* \brief ST25R3916 LED Event Write Register
*
* This function should be called on a ST25R3916 Write Register operation
* providing the event with the register and value to update LEDs
*
* \param[in] reg: ST25R3916 register to be written
* \param[in] val: value to be written on the register
*
*****************************************************************************
*/
void st25r3916ledEvtWrReg(uint8_t reg, uint8_t val);
/*!
*****************************************************************************
* \brief ST25R3916 LED Event Write Multiple Register
*
* This function should be called upon a ST25R3916 Write Multiple Registers,
* providing the event with the registers and values to update LEDs
*
* \param[in] reg : ST25R3916 first register written
* \param[in] vals: pointer to the values written
* \param[in] len : number of registers written
*
*****************************************************************************
*/
void st25r3916ledEvtWrMultiReg(uint8_t reg, const uint8_t* vals, uint8_t len);
/*!
*****************************************************************************
* \brief ST25R3916 LED Event Direct Command
*
* This function should be called upon a ST25R3916 direct command, providing
* the event with the command executed
*
* \param[in] cmd: ST25R3916 cmd executed
*
*****************************************************************************
*/
void st25r3916ledEvtCmd(uint8_t cmd);
#endif /* ST25R3916_LED_H */
/**
* @}
*
* @}
*
* @}
*
* @}
*/
-158
View File
@@ -1,158 +0,0 @@
/******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2018 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: STxxxx firmware
* LANGUAGE: ISO C99
*/
/*! \file st_errno.h
*
* \author
*
* \brief Main error codes
*
*/
#ifndef ST_ERRNO_H
#define ST_ERRNO_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include <stdint.h>
/*
******************************************************************************
* GLOBAL DATA TYPES
******************************************************************************
*/
typedef uint16_t ReturnCode; /*!< Standard Return Code type from function. */
/*
******************************************************************************
* DEFINES
******************************************************************************
*/
/*
* Error codes to be used within the application.
* They are represented by an uint8_t
*/
enum {
ERR_NONE = 0, /*!< no error occurred */
ERR_NOMEM = 1, /*!< not enough memory to perform the requested operation */
ERR_BUSY = 2, /*!< device or resource busy */
ERR_IO = 3, /*!< generic IO error */
ERR_TIMEOUT = 4, /*!< error due to timeout */
ERR_REQUEST = 5, /*!< invalid request or requested function can't be executed at the moment */
ERR_NOMSG = 6, /*!< No message of desired type */
ERR_PARAM = 7, /*!< Parameter error */
ERR_SYSTEM = 8, /*!< System error */
ERR_FRAMING = 9, /*!< Framing error */
ERR_OVERRUN = 10, /*!< lost one or more received bytes */
ERR_PROTO = 11, /*!< protocol error */
ERR_INTERNAL = 12, /*!< Internal Error */
ERR_AGAIN = 13, /*!< Call again */
ERR_MEM_CORRUPT = 14, /*!< memory corruption */
ERR_NOT_IMPLEMENTED = 15, /*!< not implemented */
ERR_PC_CORRUPT =
16, /*!< Program Counter has been manipulated or spike/noise trigger illegal operation */
ERR_SEND = 17, /*!< error sending*/
ERR_IGNORE = 18, /*!< indicates error detected but to be ignored */
ERR_SEMANTIC = 19, /*!< indicates error in state machine (unexpected cmd) */
ERR_SYNTAX = 20, /*!< indicates error in state machine (unknown cmd) */
ERR_CRC = 21, /*!< crc error */
ERR_NOTFOUND = 22, /*!< transponder not found */
ERR_NOTUNIQUE = 23, /*!< transponder not unique - more than one transponder in field */
ERR_NOTSUPP = 24, /*!< requested operation not supported */
ERR_WRITE = 25, /*!< write error */
ERR_FIFO = 26, /*!< fifo over or underflow error */
ERR_PAR = 27, /*!< parity error */
ERR_DONE = 28, /*!< transfer has already finished */
ERR_RF_COLLISION =
29, /*!< collision error (Bit Collision or during RF Collision avoidance ) */
ERR_HW_OVERRUN = 30, /*!< lost one or more received bytes */
ERR_RELEASE_REQ = 31, /*!< device requested release */
ERR_SLEEP_REQ = 32, /*!< device requested sleep */
ERR_WRONG_STATE = 33, /*!< incorrent state for requested operation */
ERR_MAX_RERUNS = 34, /*!< blocking procedure reached maximum runs */
ERR_DISABLED = 35, /*!< operation aborted due to disabled configuration */
ERR_HW_MISMATCH = 36, /*!< expected hw do not match */
ERR_LINK_LOSS =
37, /*!< Other device's field didn't behave as expected: turned off by Initiator in Passive mode, or AP2P did not turn on field */
ERR_INVALID_HANDLE = 38, /*!< invalid or not initalized device handle */
ERR_INCOMPLETE_BYTE = 40, /*!< Incomplete byte rcvd */
ERR_INCOMPLETE_BYTE_01 = 41, /*!< Incomplete byte rcvd - 1 bit */
ERR_INCOMPLETE_BYTE_02 = 42, /*!< Incomplete byte rcvd - 2 bit */
ERR_INCOMPLETE_BYTE_03 = 43, /*!< Incomplete byte rcvd - 3 bit */
ERR_INCOMPLETE_BYTE_04 = 44, /*!< Incomplete byte rcvd - 4 bit */
ERR_INCOMPLETE_BYTE_05 = 45, /*!< Incomplete byte rcvd - 5 bit */
ERR_INCOMPLETE_BYTE_06 = 46, /*!< Incomplete byte rcvd - 6 bit */
ERR_INCOMPLETE_BYTE_07 = 47, /*!< Incomplete byte rcvd - 7 bit */
};
/* General Sub-category number */
#define ERR_GENERIC_GRP (0x0000) /*!< Reserved value for generic error no */
#define ERR_WARN_GRP (0x0100) /*!< Errors which are not expected in normal operation */
#define ERR_PROCESS_GRP (0x0200) /*!< Processes management errors */
#define ERR_SIO_GRP (0x0800) /*!< SIO errors due to logging */
#define ERR_RINGBUF_GRP (0x0900) /*!< Ring Buffer errors */
#define ERR_MQ_GRP (0x0A00) /*!< MQ errors */
#define ERR_TIMER_GRP (0x0B00) /*!< Timer errors */
#define ERR_RFAL_GRP (0x0C00) /*!< RFAL errors */
#define ERR_UART_GRP (0x0D00) /*!< UART errors */
#define ERR_SPI_GRP (0x0E00) /*!< SPI errors */
#define ERR_I2C_GRP (0x0F00) /*!< I2c errors */
#define ERR_INSERT_SIO_GRP(x) (ERR_SIO_GRP | x) /*!< Insert the SIO grp */
#define ERR_INSERT_RINGBUF_GRP(x) (ERR_RINGBUF_GRP | x) /*!< Insert the Ring Buffer grp */
#define ERR_INSERT_RFAL_GRP(x) (ERR_RFAL_GRP | x) /*!< Insert the RFAL grp */
#define ERR_INSERT_SPI_GRP(x) (ERR_SPI_GRP | x) /*!< Insert the spi grp */
#define ERR_INSERT_I2C_GRP(x) (ERR_I2C_GRP | x) /*!< Insert the i2c grp */
#define ERR_INSERT_UART_GRP(x) (ERR_UART_GRP | x) /*!< Insert the uart grp */
#define ERR_INSERT_TIMER_GRP(x) (ERR_TIMER_GRP | x) /*!< Insert the timer grp */
#define ERR_INSERT_MQ_GRP(x) (ERR_MQ_GRP | x) /*!< Insert the mq grp */
#define ERR_INSERT_PROCESS_GRP(x) (ERR_PROCESS_GRP | x) /*!< Insert the process grp */
#define ERR_INSERT_WARN_GRP(x) (ERR_WARN_GRP | x) /*!< Insert the i2c grp */
#define ERR_INSERT_GENERIC_GRP(x) (ERR_GENERIC_GRP | x) /*!< Insert the generic grp */
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
#define ERR_NO_MASK(x) (x & 0x00FF) /*!< Mask the error number */
/*! Common code to exit a function with the error if function f return error */
#define EXIT_ON_ERR(r, f) \
if(ERR_NONE != (r = f)) { \
return r; \
}
#endif /* ST_ERRNO_H */
-105
View File
@@ -1,105 +0,0 @@
/******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2016 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* $Revision: $
* LANGUAGE: ANSI C
*/
/*! \file timer.c
*
* \brief SW Timer implementation
*
* \author Gustavo Patricio
*
* This module makes use of a System Tick in millisconds and provides
* an abstraction for SW timers
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "timer.h"
#include <furi.h>
/*
******************************************************************************
* LOCAL DEFINES
******************************************************************************
*/
/*
******************************************************************************
* LOCAL VARIABLES
******************************************************************************
*/
static uint32_t timerStopwatchTick;
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
/*******************************************************************************/
uint32_t timerCalculateTimer(uint16_t time) {
return (furi_get_tick() + time);
}
/*******************************************************************************/
bool timerIsExpired(uint32_t timer) {
uint32_t uDiff;
int32_t sDiff;
uDiff = (timer - furi_get_tick()); /* Calculate the diff between the timers */
sDiff = uDiff; /* Convert the diff to a signed var */
/* Check if the given timer has expired already */
if(sDiff < 0) {
return true;
}
return false;
}
/*******************************************************************************/
void timerDelay(uint16_t tOut) {
uint32_t t;
/* Calculate the timer and wait blocking until is running */
t = timerCalculateTimer(tOut);
while(timerIsRunning(t))
;
}
/*******************************************************************************/
void timerStopwatchStart(void) {
timerStopwatchTick = furi_get_tick();
}
/*******************************************************************************/
uint32_t timerStopwatchMeasure(void) {
return (uint32_t)(furi_get_tick() - timerStopwatchTick);
}
-125
View File
@@ -1,125 +0,0 @@
#pragma once
/******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2016 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R391x firmware
* $Revision: $
* LANGUAGE: ANSI C
*/
/*! \file timer.h
*
* \brief SW Timer implementation header file
*
* This module makes use of a System Tick in millisconds and provides
* an abstraction for SW timers
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include <stdint.h>
#include <stdbool.h>
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
#define timerIsRunning(t) (!timerIsExpired(t))
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief Calculate Timer
*
* This method calculates when the timer will be expired given the amount
* time in milliseconds /a tOut.
* Once the timer has been calculated it will then be used to check when
* it expires.
*
* \see timersIsExpired
*
* \param[in] time : time/duration in Milliseconds for the timer
*
* \return u32 : The new timer calculated based on the given time
*****************************************************************************
*/
uint32_t timerCalculateTimer(uint16_t time);
/*!
*****************************************************************************
* \brief Checks if a Timer is Expired
*
* This method checks if a timer has already expired.
* Based on the given timer previously calculated it checks if this timer
* has already elapsed
*
* \see timersCalculateTimer
*
* \param[in] timer : the timer to check
*
* \return true : timer has already expired
* \return false : timer is still running
*****************************************************************************
*/
bool timerIsExpired(uint32_t timer);
/*!
*****************************************************************************
* \brief Performs a Delay
*
* This method performs a delay for the given amount of time in Milliseconds
*
* \param[in] time : time/duration in Milliseconds of the delay
*
*****************************************************************************
*/
void timerDelay(uint16_t time);
/*!
*****************************************************************************
* \brief Stopwatch start
*
* This method initiates the stopwatch to later measure the time in ms
*
*****************************************************************************
*/
void timerStopwatchStart(void);
/*!
*****************************************************************************
* \brief Stopwatch Measure
*
* This method returns the elapsed time in ms since the stopwatch was initiated
*
* \return The time in ms since the stopwatch was started
*****************************************************************************
*/
uint32_t timerStopwatchMeasure(void);
-100
View File
@@ -1,100 +0,0 @@
/******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2018 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: NFCC firmware
* $Revision: $
* LANGUAGE: ISO C99
*/
/*! \file
*
* \author Ulrich Herrmann
*
* \brief Common and helpful macros
*
*/
#ifndef UTILS_H
#define UTILS_H
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include <string.h>
#include <stdint.h>
/*
******************************************************************************
* GLOBAL MACROS
******************************************************************************
*/
/*!
* this macro evaluates an error variable \a ERR against an error code \a EC.
* in case it is not equal it jumps to the given label \a LABEL.
*/
#define EVAL_ERR_NE_GOTO(EC, ERR, LABEL) \
if(EC != ERR) goto LABEL;
/*!
* this macro evaluates an error variable \a ERR against an error code \a EC.
* in case it is equal it jumps to the given label \a LABEL.
*/
#define EVAL_ERR_EQ_GOTO(EC, ERR, LABEL) \
if(EC == ERR) goto LABEL;
#define BITMASK_1 (0x01) /*!< Bit mask for lsb bit */
#define BITMASK_2 (0x03) /*!< Bit mask for two lsb bits */
#define BITMASK_3 (0x07) /*!< Bit mask for three lsb bits */
#define BITMASK_4 (0x0F) /*!< Bit mask for four lsb bits */
#define U16TOU8(a) ((a)&0x00FF) /*!< Cast 16-bit unsigned to 8-bit unsigned */
#define GETU16(a) \
(uint16_t)( \
(a[0] << 8) | a[1]) /*!< Cast two Big Endian 8-bits byte array to 16-bits unsigned */
#define REVERSE_BYTES(pData, nDataSize) \
unsigned char swap, *lo = pData, *hi = pData + nDataSize - 1; \
while(lo < hi) { \
swap = *lo; \
*lo++ = *hi; \
*hi-- = swap; \
}
#define ST_MEMMOVE memmove /*!< map memmove to string library code */
#define ST_MEMCPY memcpy /*!< map memcpy to string library code */
#define ST_MEMSET memset /*!< map memset to string library code */
#define ST_BYTECMP memcmp /*!< map bytecmp to string library code */
#define NO_WARNING(v) ((void)(v)) /*!< Macro to suppress compiler warning */
#ifndef NULL
#define NULL (void*)0 /*!< represents a NULL pointer */
#endif /* !NULL */
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
#endif /* UTILS_H */
+1
View File
@@ -6,6 +6,7 @@ env.Append(
],
SDK_HEADERS=[
File("digital_signal.h"),
File("digital_sequence.h"),
],
)
+381
View File
@@ -0,0 +1,381 @@
#include "digital_sequence.h"
#include "digital_signal_i.h"
#include <furi.h>
#include <furi_hal_bus.h>
#include <stm32wbxx_ll_dma.h>
#include <stm32wbxx_ll_tim.h>
/**
* To enable debug output on an additional pin, set DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN to the required
* GpioPin variable. It can be passed at compile time via the --extra-define fbt switch.
* NOTE: This pin must be on the same GPIO port as the main pin.
*
* Example:
* ./fbt --extra-define=DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN=gpio_ext_pb3
*/
#define TAG "DigitalSequence"
/* Special value used to indicate the end of DMA ring buffer. */
#define DIGITAL_SEQUENCE_TIMER_MAX 0xFFFFFFFFUL
/* Time to wait in loops before returning */
#define DIGITAL_SEQUENCE_LOCK_WAIT_MS 10UL
#define DIGITAL_SEQUENCE_LOCK_WAIT_TICKS (DIGITAL_SEQUENCE_LOCK_WAIT_MS * 1000 * 64)
#define DIGITAL_SEQUENCE_GPIO_BUFFER_SIZE 2
/* Maximum capacity of the DMA ring buffer. */
#define DIGITAL_SEQUENCE_RING_BUFFER_SIZE 128
#define DIGITAL_SEQUENCE_RING_BUFFER_MIN_FREE_SIZE 2
/* Maximum amount of registered signals. */
#define DIGITAL_SEQUENCE_BANK_SIZE 32
typedef enum {
DigitalSequenceStateIdle,
DigitalSequenceStateActive,
} DigitalSequenceState;
typedef struct {
uint32_t data[DIGITAL_SEQUENCE_RING_BUFFER_SIZE];
uint32_t write_pos;
uint32_t read_pos;
} DigitalSequenceRingBuffer;
typedef uint32_t DigitalSequenceGpioBuffer[DIGITAL_SEQUENCE_GPIO_BUFFER_SIZE];
typedef const DigitalSignal* DigitalSequenceSignalBank[DIGITAL_SEQUENCE_BANK_SIZE];
struct DigitalSequence {
const GpioPin* gpio;
uint32_t size;
uint32_t max_size;
uint8_t* data;
LL_DMA_InitTypeDef dma_config_gpio;
LL_DMA_InitTypeDef dma_config_timer;
DigitalSequenceGpioBuffer gpio_buf;
DigitalSequenceRingBuffer timer_buf;
DigitalSequenceSignalBank signals;
DigitalSequenceState state;
};
DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio) {
furi_assert(size);
furi_assert(gpio);
DigitalSequence* sequence = malloc(sizeof(DigitalSequence));
sequence->gpio = gpio;
sequence->max_size = size;
sequence->data = malloc(sequence->max_size);
sequence->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t)&gpio->port->BSRR;
sequence->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)sequence->gpio_buf;
sequence->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
sequence->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR;
sequence->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
sequence->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
sequence->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
sequence->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
sequence->dma_config_gpio.NbData = DIGITAL_SEQUENCE_GPIO_BUFFER_SIZE;
sequence->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
sequence->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH;
sequence->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t)&TIM2->ARR;
sequence->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)sequence->timer_buf.data;
sequence->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
sequence->dma_config_timer.Mode = LL_DMA_MODE_CIRCULAR;
sequence->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
sequence->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
sequence->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
sequence->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
sequence->dma_config_timer.NbData = DIGITAL_SEQUENCE_RING_BUFFER_SIZE;
sequence->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
sequence->dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH;
return sequence;
}
void digital_sequence_free(DigitalSequence* sequence) {
furi_assert(sequence);
free(sequence->data);
free(sequence);
}
void digital_sequence_register_signal(
DigitalSequence* sequence,
uint8_t signal_index,
const DigitalSignal* signal) {
furi_assert(sequence);
furi_assert(signal);
furi_assert(signal_index < DIGITAL_SEQUENCE_BANK_SIZE);
sequence->signals[signal_index] = signal;
}
void digital_sequence_add_signal(DigitalSequence* sequence, uint8_t signal_index) {
furi_assert(sequence);
furi_assert(signal_index < DIGITAL_SEQUENCE_BANK_SIZE);
furi_assert(sequence->size < sequence->max_size);
sequence->data[sequence->size++] = signal_index;
}
static inline void digital_sequence_start_dma(DigitalSequence* sequence) {
furi_assert(sequence);
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &sequence->dma_config_gpio);
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &sequence->dma_config_timer);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);
}
static inline void digital_sequence_stop_dma() {
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2);
LL_DMA_ClearFlag_TC1(DMA1);
LL_DMA_ClearFlag_TC2(DMA1);
}
static inline void digital_sequence_start_timer() {
furi_hal_bus_enable(FuriHalBusTIM2);
LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP);
LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1);
LL_TIM_SetPrescaler(TIM2, 0);
LL_TIM_SetAutoReload(TIM2, DIGITAL_SEQUENCE_TIMER_MAX);
LL_TIM_SetCounter(TIM2, 0);
LL_TIM_EnableCounter(TIM2);
LL_TIM_EnableUpdateEvent(TIM2);
LL_TIM_EnableDMAReq_UPDATE(TIM2);
LL_TIM_GenerateEvent_UPDATE(TIM2);
}
static void digital_sequence_stop_timer() {
LL_TIM_DisableCounter(TIM2);
LL_TIM_DisableUpdateEvent(TIM2);
LL_TIM_DisableDMAReq_UPDATE(TIM2);
furi_hal_bus_disable(FuriHalBusTIM2);
}
static inline void digital_sequence_init_gpio_buffer(
DigitalSequence* sequence,
const DigitalSignal* first_signal) {
const uint32_t bit_set = sequence->gpio->pin << GPIO_BSRR_BS0_Pos
#ifdef DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN
| DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN.pin << GPIO_BSRR_BS0_Pos
#endif
;
const uint32_t bit_reset = sequence->gpio->pin << GPIO_BSRR_BR0_Pos
#ifdef DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN
| DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN.pin << GPIO_BSRR_BR0_Pos
#endif
;
if(first_signal->start_level) {
sequence->gpio_buf[0] = bit_set;
sequence->gpio_buf[1] = bit_reset;
} else {
sequence->gpio_buf[0] = bit_reset;
sequence->gpio_buf[1] = bit_set;
}
}
static inline void digital_sequence_finish(DigitalSequence* sequence) {
if(sequence->state == DigitalSequenceStateActive) {
const uint32_t prev_timer = DWT->CYCCNT;
do {
/* Special value has been loaded into the timer, signaling the end of transmission. */
if(TIM2->ARR == DIGITAL_SEQUENCE_TIMER_MAX) {
break;
}
if(DWT->CYCCNT - prev_timer > DIGITAL_SEQUENCE_LOCK_WAIT_TICKS) {
DigitalSequenceRingBuffer* dma_buffer = &sequence->timer_buf;
dma_buffer->read_pos = DIGITAL_SEQUENCE_RING_BUFFER_SIZE -
LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2);
FURI_LOG_D(
TAG,
"[SEQ] hung %lu ms in finish (ARR 0x%08lx, read %lu, write %lu)",
DIGITAL_SEQUENCE_LOCK_WAIT_MS,
TIM2->ARR,
dma_buffer->read_pos,
dma_buffer->write_pos);
break;
}
} while(true);
}
digital_sequence_stop_timer();
digital_sequence_stop_dma();
}
static inline void digital_sequence_enqueue_period(DigitalSequence* sequence, uint32_t length) {
DigitalSequenceRingBuffer* dma_buffer = &sequence->timer_buf;
if(sequence->state == DigitalSequenceStateActive) {
const uint32_t prev_timer = DWT->CYCCNT;
do {
dma_buffer->read_pos =
DIGITAL_SEQUENCE_RING_BUFFER_SIZE - LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2);
const uint32_t size_free = (DIGITAL_SEQUENCE_RING_BUFFER_SIZE + dma_buffer->read_pos -
dma_buffer->write_pos) %
DIGITAL_SEQUENCE_RING_BUFFER_SIZE;
if(size_free > DIGITAL_SEQUENCE_RING_BUFFER_MIN_FREE_SIZE) {
break;
}
if(DWT->CYCCNT - prev_timer > DIGITAL_SEQUENCE_LOCK_WAIT_TICKS) {
FURI_LOG_D(
TAG,
"[SEQ] hung %lu ms in queue (ARR 0x%08lx, read %lu, write %lu)",
DIGITAL_SEQUENCE_LOCK_WAIT_MS,
TIM2->ARR,
dma_buffer->read_pos,
dma_buffer->write_pos);
break;
}
if(TIM2->ARR == DIGITAL_SEQUENCE_TIMER_MAX) {
FURI_LOG_D(
TAG,
"[SEQ] buffer underrun in queue (ARR 0x%08lx, read %lu, write %lu)",
TIM2->ARR,
dma_buffer->read_pos,
dma_buffer->write_pos);
break;
}
} while(true);
}
dma_buffer->data[dma_buffer->write_pos] = length;
dma_buffer->write_pos += 1;
dma_buffer->write_pos %= DIGITAL_SEQUENCE_RING_BUFFER_SIZE;
dma_buffer->data[dma_buffer->write_pos] = DIGITAL_SEQUENCE_TIMER_MAX;
}
static inline void digital_sequence_timer_buffer_reset(DigitalSequence* sequence) {
sequence->timer_buf.data[0] = DIGITAL_SEQUENCE_TIMER_MAX;
sequence->timer_buf.read_pos = 0;
sequence->timer_buf.write_pos = 0;
}
void digital_sequence_transmit(DigitalSequence* sequence) {
furi_assert(sequence);
furi_assert(sequence->size);
furi_assert(sequence->state == DigitalSequenceStateIdle);
FURI_CRITICAL_ENTER();
furi_hal_gpio_init(sequence->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
#ifdef DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN
furi_hal_gpio_init(
&DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
#endif
const DigitalSignal* signal_current = sequence->signals[sequence->data[0]];
digital_sequence_init_gpio_buffer(sequence, signal_current);
int32_t remainder_ticks = 0;
uint32_t reload_value_carry = 0;
uint32_t next_signal_index = 1;
for(;;) {
const DigitalSignal* signal_next =
(next_signal_index < sequence->size) ?
sequence->signals[sequence->data[next_signal_index++]] :
NULL;
for(uint32_t i = 0; i < signal_current->size; i++) {
const bool is_last_value = (i == signal_current->size - 1);
const uint32_t reload_value = signal_current->data[i] + reload_value_carry;
reload_value_carry = 0;
if(is_last_value) {
if(signal_next != NULL) {
/* Special case: signal boundary. Depending on whether the adjacent levels are equal or not,
* they will be combined to a single one or handled separately. */
const bool end_level = signal_current->start_level ^
((signal_current->size % 2) == 0);
/* If the adjacent levels are equal, carry the current period duration over to the next signal. */
if(end_level == signal_next->start_level) {
reload_value_carry = reload_value;
}
} else {
/** Special case: during the last period of the last signal, hold the output level indefinitely.
* @see digital_signal.h
*
* Setting reload_value_carry to a non-zero value will prevent the respective period from being
* added to the DMA ring buffer. */
reload_value_carry = 1;
}
}
/* A non-zero reload_value_carry means that the level was the same on the both sides of the signal boundary
* and the two respective periods were combined to one. */
if(reload_value_carry == 0) {
digital_sequence_enqueue_period(sequence, reload_value);
}
if(sequence->state == DigitalSequenceStateIdle) {
const bool is_buffer_filled = sequence->timer_buf.write_pos >=
(DIGITAL_SEQUENCE_RING_BUFFER_SIZE -
DIGITAL_SEQUENCE_RING_BUFFER_MIN_FREE_SIZE);
const bool is_end_of_data = (signal_next == NULL) && is_last_value;
if(is_buffer_filled || is_end_of_data) {
digital_sequence_start_dma(sequence);
digital_sequence_start_timer();
sequence->state = DigitalSequenceStateActive;
}
}
}
/* Exit the loop here when no further signals are available */
if(signal_next == NULL) break;
/* Prevent the rounding error from accumulating by distributing it across multiple periods. */
remainder_ticks += signal_current->remainder;
if(remainder_ticks >= DIGITAL_SIGNAL_T_TIM_DIV2) {
remainder_ticks -= DIGITAL_SIGNAL_T_TIM;
reload_value_carry += 1;
}
signal_current = signal_next;
};
digital_sequence_finish(sequence);
digital_sequence_timer_buffer_reset(sequence);
FURI_CRITICAL_EXIT();
sequence->state = DigitalSequenceStateIdle;
}
void digital_sequence_clear(DigitalSequence* sequence) {
furi_assert(sequence);
sequence->size = 0;
}
+112
View File
@@ -0,0 +1,112 @@
/**
* @file digital_sequence.h
* @brief Fast and precise digital signal generation library.
*
* Each sequence is represented by one or more (up to 32) registered signals, which are addressed
* by their indices, and a list of signal indices to be transmitted.
*
* The registered signals must be set up prior to actually defining the sequence.
*
* Example: A sequence containing 4 registered signals and n indices to transmit.
*
* |Signal | Index |
* |:-----:|:-----:|
* | SOF | 0 |
* | EOF | 1 |
* | Zero | 2 |
* | One | 3 |
*
* ```
* Signal index | 0 | 3 | 2 | 2 | ... | 3 | 1 |
* 0 1 2 3 ... n - 2 n - 1
* ```
*
* The above sequence starts by transmitting the signal with index 0, which is SOF in this case,
* then it proceeds with indices 3, 2, 2, which are One, Zero, Zero and after n - 2 signals,
* it will conclude with indices 3 and 1 which are One and EOF respectively.
*
* This way, only the order in which the signals are sent is stored, while the signals themselves
* are not duplicated.
*/
#pragma once
#include <furi_hal_gpio.h>
#include <digital_signal/digital_signal.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct DigitalSequence DigitalSequence;
/**
* @brief Allocate a DigitalSequence instance of a given size which will operate on a set GPIO pin.
*
* @param[in] size maximum number of signal indices contained in the instance.
* @param[in] gpio the GPIO pin used to generate the signal.
* @returns pointer to the allocated DigitalSequence instance.
*/
DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio);
/**
* @brief Delete a previously allocated DigitalSequence instance.
*
* @param[in,out] sequence pointer to the instance to be deleted.
*/
void digital_sequence_free(DigitalSequence* sequence);
/**
* @brief Register a signal within a DigitalSequence instance by its index.
*
* This function must be called for each signal to be used in the sequence. The DigitalSequence
* instance does not own the signals, therefore, their lifetime must be no less than the instance's.
*
* The user is responsible for creation and deletion of DigitalSignal instances and
* also for keeping track of their respective indices.
*
* @param[in,out] sequence pointer to the instance to be modified.
* @param[in] signal_index index to register the signal under (must be less than 32).
* @param[in] signal pointer to the DigitalSignal instance to be registered.
*/
void digital_sequence_register_signal(
DigitalSequence* sequence,
uint8_t signal_index,
const DigitalSignal* signal);
/**
* @brief Append a signal index to a DigitalSequence instance.
*
* The signal under the index must be registered beforehand by calling digital_sequence_set_signal().
*
* @param[in,out] sequence pointer to the instance to be modified.
* @param[in] signal_index signal index to be appended to the sequence (must be less than 32).
*/
void digital_sequence_add_signal(DigitalSequence* sequence, uint8_t signal_index);
/**
* @brief Transmit the sequence contained in the DigitalSequence instance.
*
* Must contain at least one registered signal and one signal index.
*
* NOTE: The current implementation will properly initialise the GPIO provided during construction,
* but it is the caller's responsibility to reconfigure it back before reusing for other purposes.
* This is due to performance reasons.
*
* @param[in] sequence pointer to the sequence to be transmitted.
*/
void digital_sequence_transmit(DigitalSequence* sequence);
/**
* @brief Clear the signal sequence in a DigitalSequence instance.
*
* Calling this function does not un-register the registered signals, so it is
* safe to call digital_sequence_add_signal() right afterwards.
*
* @param[in,out] sequence pointer to the instance to be cleared.
*/
void digital_sequence_clear(DigitalSequence* sequence);
#ifdef __cplusplus
}
#endif
+56 -625
View File
@@ -1,106 +1,15 @@
#include "digital_signal.h"
#include "digital_signal_i.h"
#include <furi.h>
#include <furi_hal.h>
#include <furi_hal_resources.h>
#include <math.h>
#include <stm32wbxx_ll_dma.h>
#include <stm32wbxx_ll_tim.h>
/* must be on bank B */
// For debugging purposes use `--extra-define=DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN=gpio_ext_pb3` fbt option
struct ReloadBuffer {
uint32_t* buffer; /* DMA ringbuffer */
uint32_t size; /* maximum entry count of the ring buffer */
uint32_t write_pos; /* current buffer write index */
uint32_t read_pos; /* current buffer read index */
bool dma_active;
};
struct DigitalSequence {
uint8_t signals_size;
bool bake;
uint32_t sequence_used;
uint32_t sequence_size;
DigitalSignal** signals;
uint8_t* sequence;
const GpioPin* gpio;
uint32_t send_time;
bool send_time_active;
LL_DMA_InitTypeDef dma_config_gpio;
LL_DMA_InitTypeDef dma_config_timer;
uint32_t* gpio_buff;
struct ReloadBuffer* dma_buffer;
};
struct DigitalSignalInternals {
uint64_t factor;
uint32_t reload_reg_entries;
uint32_t reload_reg_remainder;
uint32_t gpio_buff[2];
const GpioPin* gpio;
LL_DMA_InitTypeDef dma_config_gpio;
LL_DMA_InitTypeDef dma_config_timer;
};
#define TAG "DigitalSignal"
#define F_TIM (64000000.0)
#define T_TIM 1562 /* 15.625 ns *100 */
#define T_TIM_DIV2 781 /* 15.625 ns / 2 *100 */
/* end marker in DMA ringbuffer, will get written into timer register at the end */
#define SEQ_TIMER_MAX 0xFFFFFFFF
/* time to wait in loops before returning */
#define SEQ_LOCK_WAIT_MS 10UL
#define SEQ_LOCK_WAIT_TICKS (SEQ_LOCK_WAIT_MS * 1000 * 64)
/* maximum entry count of the sequence dma ring buffer */
#define RINGBUFFER_SIZE 128
/* maximum number of DigitalSignals in a sequence */
#define SEQUENCE_SIGNALS_SIZE 32
/*
* if sequence size runs out from the initial value passed to digital_sequence_alloc
* the size will be increased by this amount and reallocated
*/
#define SEQUENCE_SIZE_REALLOCATE_INCREMENT 256
DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) {
DigitalSignal* digital_signal_alloc(uint32_t max_size) {
DigitalSignal* signal = malloc(sizeof(DigitalSignal));
signal->start_level = true;
signal->edges_max_cnt = max_edges_cnt;
signal->edge_timings = malloc(signal->edges_max_cnt * sizeof(uint32_t));
signal->edge_cnt = 0;
signal->reload_reg_buff = malloc(signal->edges_max_cnt * sizeof(uint32_t));
signal->internals = malloc(sizeof(DigitalSignalInternals));
DigitalSignalInternals* internals = signal->internals;
internals->factor = 1024 * 1024;
internals->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
internals->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR;
internals->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
internals->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
internals->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
internals->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
internals->dma_config_gpio.NbData = 2;
internals->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
internals->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH;
internals->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR);
internals->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
internals->dma_config_timer.Mode = LL_DMA_MODE_NORMAL;
internals->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
internals->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
internals->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
internals->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
internals->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
internals->dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH;
signal->max_size = max_size;
signal->data = malloc(max_size * sizeof(uint32_t));
return signal;
}
@@ -108,559 +17,81 @@ DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) {
void digital_signal_free(DigitalSignal* signal) {
furi_assert(signal);
free(signal->edge_timings);
free(signal->reload_reg_buff);
free(signal->internals);
free(signal->data);
free(signal);
}
bool digital_signal_append(DigitalSignal* signal_a, DigitalSignal* signal_b) {
furi_assert(signal_a);
furi_assert(signal_b);
if(signal_a->edges_max_cnt < signal_a->edge_cnt + signal_b->edge_cnt) {
return false;
}
/* in case there are no edges in our target signal, the signal to append makes the rules */
if(!signal_a->edge_cnt) {
signal_a->start_level = signal_b->start_level;
}
bool end_level = signal_a->start_level;
if(signal_a->edge_cnt) {
end_level = signal_a->start_level ^ !(signal_a->edge_cnt % 2);
}
uint8_t start_copy = 0;
if(end_level == signal_b->start_level) {
if(signal_a->edge_cnt) {
signal_a->edge_timings[signal_a->edge_cnt - 1] += signal_b->edge_timings[0];
start_copy += 1;
} else {
signal_a->edge_timings[signal_a->edge_cnt] += signal_b->edge_timings[0];
}
}
for(size_t i = 0; i < signal_b->edge_cnt - start_copy; i++) {
signal_a->edge_timings[signal_a->edge_cnt + i] = signal_b->edge_timings[start_copy + i];
}
signal_a->edge_cnt += signal_b->edge_cnt - start_copy;
return true;
}
bool digital_signal_get_start_level(DigitalSignal* signal) {
bool digital_signal_get_start_level(const DigitalSignal* signal) {
furi_assert(signal);
return signal->start_level;
}
uint32_t digital_signal_get_edges_cnt(DigitalSignal* signal) {
void digital_signal_set_start_level(DigitalSignal* signal, bool level) {
furi_assert(signal);
return signal->edge_cnt;
signal->start_level = level;
}
void digital_signal_add(DigitalSignal* signal, uint32_t ticks) {
uint32_t digital_signal_get_size(const DigitalSignal* signal) {
furi_assert(signal);
furi_assert(signal->edge_cnt < signal->edges_max_cnt);
signal->edge_timings[signal->edge_cnt++] = ticks;
return signal->size;
}
void digital_signal_add_pulse(DigitalSignal* signal, uint32_t ticks, bool level) {
void digital_signal_add_period(DigitalSignal* signal, uint32_t ticks) {
furi_assert(signal);
furi_assert(signal->edge_cnt < signal->edges_max_cnt);
furi_assert(signal->size < signal->max_size);
/* virgin signal? add it as the only level */
if(signal->edge_cnt == 0) {
const uint32_t duration = ticks + signal->remainder;
uint32_t reload_value = duration / DIGITAL_SIGNAL_T_TIM;
int32_t remainder = duration - reload_value * DIGITAL_SIGNAL_T_TIM;
if(remainder >= DIGITAL_SIGNAL_T_TIM_DIV2) {
reload_value += 1;
remainder -= DIGITAL_SIGNAL_T_TIM;
}
furi_check(reload_value > 1);
signal->data[signal->size++] = reload_value - 1;
signal->remainder = remainder;
}
static void digital_signal_extend_last_period(DigitalSignal* signal, uint32_t ticks) {
furi_assert(signal->size <= signal->max_size);
const uint32_t reload_value_old = signal->data[signal->size - 1] + 1;
const uint32_t duration = ticks + signal->remainder + reload_value_old * DIGITAL_SIGNAL_T_TIM;
uint32_t reload_value = duration / DIGITAL_SIGNAL_T_TIM;
int32_t remainder = duration - reload_value * DIGITAL_SIGNAL_T_TIM;
if(remainder >= DIGITAL_SIGNAL_T_TIM_DIV2) {
reload_value += 1;
remainder -= DIGITAL_SIGNAL_T_TIM;
}
furi_check(reload_value > 1);
signal->data[signal->size - 1] = reload_value - 1;
signal->remainder = remainder;
}
void digital_signal_add_period_with_level(DigitalSignal* signal, uint32_t ticks, bool level) {
furi_assert(signal);
if(signal->size == 0) {
signal->start_level = level;
signal->edge_timings[signal->edge_cnt++] = ticks;
digital_signal_add_period(signal, ticks);
} else {
bool end_level = signal->start_level ^ !(signal->edge_cnt % 2);
const bool end_level = signal->start_level ^ !(signal->size % 2);
if(level != end_level) {
signal->edge_timings[signal->edge_cnt++] = ticks;
digital_signal_add_period(signal, ticks);
} else {
signal->edge_timings[signal->edge_cnt - 1] += ticks;
}
}
}
uint32_t digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num) {
furi_assert(signal);
furi_assert(edge_num < signal->edge_cnt);
return signal->edge_timings[edge_num];
}
void digital_signal_prepare_arr(DigitalSignal* signal) {
furi_assert(signal);
DigitalSignalInternals* internals = signal->internals;
/* set up signal polarities */
if(internals->gpio) {
uint32_t bit_set = internals->gpio->pin;
uint32_t bit_reset = internals->gpio->pin << 16;
#ifdef DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN
bit_set |= DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN.pin;
bit_reset |= DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN.pin << 16;
#endif
if(signal->start_level) {
internals->gpio_buff[0] = bit_set;
internals->gpio_buff[1] = bit_reset;
} else {
internals->gpio_buff[0] = bit_reset;
internals->gpio_buff[1] = bit_set;
}
}
/* set up edge timings */
internals->reload_reg_entries = 0;
for(size_t pos = 0; pos < signal->edge_cnt; pos++) {
uint32_t pulse_duration = signal->edge_timings[pos] + internals->reload_reg_remainder;
if(pulse_duration < 10 || pulse_duration > 10000000) {
FURI_LOG_D(
TAG,
"[prepare] pulse_duration out of range: %lu = %lu * %llu",
pulse_duration,
signal->edge_timings[pos],
internals->factor);
pulse_duration = 100;
}
uint32_t pulse_ticks = (pulse_duration + T_TIM_DIV2) / T_TIM;
internals->reload_reg_remainder = pulse_duration - (pulse_ticks * T_TIM);
if(pulse_ticks > 1) {
signal->reload_reg_buff[internals->reload_reg_entries++] = pulse_ticks - 1;
}
}
}
static void digital_signal_stop_dma() {
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2);
LL_DMA_ClearFlag_TC1(DMA1);
LL_DMA_ClearFlag_TC2(DMA1);
}
static void digital_signal_stop_timer() {
LL_TIM_DisableCounter(TIM2);
LL_TIM_DisableUpdateEvent(TIM2);
LL_TIM_DisableDMAReq_UPDATE(TIM2);
furi_hal_bus_disable(FuriHalBusTIM2);
}
static void digital_signal_setup_timer() {
furi_hal_bus_enable(FuriHalBusTIM2);
LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP);
LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1);
LL_TIM_SetPrescaler(TIM2, 0);
LL_TIM_SetAutoReload(TIM2, SEQ_TIMER_MAX);
LL_TIM_SetCounter(TIM2, 0);
}
static void digital_signal_start_timer() {
LL_TIM_EnableCounter(TIM2);
LL_TIM_EnableUpdateEvent(TIM2);
LL_TIM_EnableDMAReq_UPDATE(TIM2);
LL_TIM_GenerateEvent_UPDATE(TIM2);
}
static bool digital_signal_setup_dma(DigitalSignal* signal) {
furi_assert(signal);
DigitalSignalInternals* internals = signal->internals;
if(!signal->internals->reload_reg_entries) {
return false;
}
digital_signal_stop_dma();
internals->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)internals->gpio_buff;
internals->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) & (internals->gpio->port->BSRR);
internals->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)signal->reload_reg_buff;
internals->dma_config_timer.NbData = signal->internals->reload_reg_entries;
/* set up DMA channel 1 and 2 for GPIO and timer copy operations */
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &internals->dma_config_gpio);
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &internals->dma_config_timer);
/* enable both DMA channels */
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);
return true;
}
void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) {
furi_assert(signal);
if(!signal->edge_cnt) {
return;
}
/* Configure gpio as output */
signal->internals->gpio = gpio;
furi_hal_gpio_init(
signal->internals->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
digital_signal_prepare_arr(signal);
digital_signal_setup_dma(signal);
digital_signal_setup_timer();
digital_signal_start_timer();
while(!LL_DMA_IsActiveFlag_TC2(DMA1)) {
}
digital_signal_stop_timer();
digital_signal_stop_dma();
}
static void digital_sequence_alloc_signals(DigitalSequence* sequence, uint32_t size) {
sequence->signals_size = size;
sequence->signals = malloc(sequence->signals_size * sizeof(DigitalSignal*));
}
static void digital_sequence_alloc_sequence(DigitalSequence* sequence, uint32_t size) {
sequence->sequence_used = 0;
sequence->sequence_size = size;
sequence->sequence = malloc(sequence->sequence_size);
sequence->send_time = 0;
sequence->send_time_active = false;
}
DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio) {
furi_assert(gpio);
DigitalSequence* sequence = malloc(sizeof(DigitalSequence));
sequence->gpio = gpio;
sequence->bake = false;
sequence->dma_buffer = malloc(sizeof(struct ReloadBuffer));
sequence->dma_buffer->size = RINGBUFFER_SIZE;
sequence->dma_buffer->buffer = malloc(sequence->dma_buffer->size * sizeof(uint32_t));
sequence->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
sequence->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR;
sequence->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
sequence->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
sequence->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
sequence->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
sequence->dma_config_gpio.NbData = 2;
sequence->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
sequence->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH;
sequence->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
sequence->dma_config_timer.Mode = LL_DMA_MODE_CIRCULAR;
sequence->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
sequence->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
sequence->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
sequence->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
sequence->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR);
sequence->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)sequence->dma_buffer->buffer;
sequence->dma_config_timer.NbData = sequence->dma_buffer->size;
sequence->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
sequence->dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH;
digital_sequence_alloc_signals(sequence, SEQUENCE_SIGNALS_SIZE);
digital_sequence_alloc_sequence(sequence, size);
return sequence;
}
void digital_sequence_free(DigitalSequence* sequence) {
furi_assert(sequence);
free(sequence->signals);
free(sequence->sequence);
free(sequence->dma_buffer->buffer);
free(sequence->dma_buffer);
free(sequence);
}
void digital_sequence_set_signal(
DigitalSequence* sequence,
uint8_t signal_index,
DigitalSignal* signal) {
furi_assert(sequence);
furi_assert(signal);
furi_assert(signal_index < sequence->signals_size);
sequence->signals[signal_index] = signal;
signal->internals->gpio = sequence->gpio;
signal->internals->reload_reg_remainder = 0;
digital_signal_prepare_arr(signal);
}
void digital_sequence_set_sendtime(DigitalSequence* sequence, uint32_t send_time) {
furi_assert(sequence);
sequence->send_time = send_time;
sequence->send_time_active = true;
}
void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index) {
furi_assert(sequence);
furi_assert(signal_index < sequence->signals_size);
if(sequence->sequence_used >= sequence->sequence_size) {
sequence->sequence_size += SEQUENCE_SIZE_REALLOCATE_INCREMENT;
sequence->sequence = realloc(sequence->sequence, sequence->sequence_size); //-V701
furi_assert(sequence->sequence);
}
sequence->sequence[sequence->sequence_used++] = signal_index;
}
static bool digital_sequence_setup_dma(DigitalSequence* sequence) {
furi_assert(sequence);
digital_signal_stop_dma();
sequence->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)sequence->gpio_buff;
sequence->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) & (sequence->gpio->port->BSRR);
/* set up DMA channel 1 and 2 for GPIO and timer copy operations */
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &sequence->dma_config_gpio);
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &sequence->dma_config_timer);
/* enable both DMA channels */
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);
return true;
}
static DigitalSignal* digital_sequence_bake(DigitalSequence* sequence) {
furi_assert(sequence);
uint32_t edges = 0;
for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) {
uint8_t signal_index = sequence->sequence[pos];
DigitalSignal* sig = sequence->signals[signal_index];
edges += sig->edge_cnt;
}
DigitalSignal* ret = digital_signal_alloc(edges);
for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) {
uint8_t signal_index = sequence->sequence[pos];
DigitalSignal* sig = sequence->signals[signal_index];
digital_signal_append(ret, sig);
}
return ret;
}
static void digital_sequence_finish(DigitalSequence* sequence) {
struct ReloadBuffer* dma_buffer = sequence->dma_buffer;
if(dma_buffer->dma_active) {
uint32_t prev_timer = DWT->CYCCNT;
do {
/* we are finished, when the DMA transferred the SEQ_TIMER_MAX marker */
if(TIM2->ARR == SEQ_TIMER_MAX) {
break;
}
if(DWT->CYCCNT - prev_timer > SEQ_LOCK_WAIT_TICKS) {
dma_buffer->read_pos =
RINGBUFFER_SIZE - LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2);
FURI_LOG_D(
TAG,
"[SEQ] hung %lu ms in finish (ARR 0x%08lx, read %lu, write %lu)",
SEQ_LOCK_WAIT_MS,
TIM2->ARR,
dma_buffer->read_pos,
dma_buffer->write_pos);
break;
}
} while(1);
}
digital_signal_stop_timer();
digital_signal_stop_dma();
}
static void digital_sequence_queue_pulse(DigitalSequence* sequence, uint32_t length) {
struct ReloadBuffer* dma_buffer = sequence->dma_buffer;
if(dma_buffer->dma_active) {
uint32_t prev_timer = DWT->CYCCNT;
do {
dma_buffer->read_pos = RINGBUFFER_SIZE - LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2);
uint32_t free =
(RINGBUFFER_SIZE + dma_buffer->read_pos - dma_buffer->write_pos) % RINGBUFFER_SIZE;
if(free > 2) {
break;
}
if(DWT->CYCCNT - prev_timer > SEQ_LOCK_WAIT_TICKS) {
FURI_LOG_D(
TAG,
"[SEQ] hung %lu ms in queue (ARR 0x%08lx, read %lu, write %lu)",
SEQ_LOCK_WAIT_MS,
TIM2->ARR,
dma_buffer->read_pos,
dma_buffer->write_pos);
break;
}
if(TIM2->ARR == SEQ_TIMER_MAX) {
FURI_LOG_D(
TAG,
"[SEQ] buffer underrun in queue (ARR 0x%08lx, read %lu, write %lu)",
TIM2->ARR,
dma_buffer->read_pos,
dma_buffer->write_pos);
break;
}
} while(1);
}
dma_buffer->buffer[dma_buffer->write_pos] = length;
dma_buffer->write_pos++;
dma_buffer->write_pos %= RINGBUFFER_SIZE;
dma_buffer->buffer[dma_buffer->write_pos] = SEQ_TIMER_MAX;
}
bool digital_sequence_send(DigitalSequence* sequence) {
furi_assert(sequence);
struct ReloadBuffer* dma_buffer = sequence->dma_buffer;
furi_hal_gpio_init(sequence->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
#ifdef DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN
furi_hal_gpio_init(
&DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
#endif
if(sequence->bake) {
DigitalSignal* sig = digital_sequence_bake(sequence);
digital_signal_send(sig, sequence->gpio);
digital_signal_free(sig);
return true;
}
if(!sequence->sequence_used) {
return false;
}
int32_t remainder = 0;
uint32_t trade_for_next = 0;
uint32_t seq_pos_next = 1;
dma_buffer->dma_active = false;
dma_buffer->buffer[0] = SEQ_TIMER_MAX;
dma_buffer->read_pos = 0;
dma_buffer->write_pos = 0;
/* already prepare the current signal pointer */
DigitalSignal* sig = sequence->signals[sequence->sequence[0]];
DigitalSignal* sig_next = NULL;
/* re-use the GPIO buffer from the first signal */
sequence->gpio_buff = sig->internals->gpio_buff;
FURI_CRITICAL_ENTER();
while(sig) {
bool last_signal = (seq_pos_next >= sequence->sequence_used);
if(!last_signal) {
sig_next = sequence->signals[sequence->sequence[seq_pos_next++]];
}
for(uint32_t pulse_pos = 0; pulse_pos < sig->internals->reload_reg_entries; pulse_pos++) {
bool last_pulse = ((pulse_pos + 1) >= sig->internals->reload_reg_entries);
uint32_t pulse_length = sig->reload_reg_buff[pulse_pos] + trade_for_next;
trade_for_next = 0;
/* when we are too late more than half a tick, make the first edge temporarily longer */
if(remainder >= T_TIM_DIV2) {
remainder -= T_TIM;
pulse_length += 1;
}
/* last pulse in current signal and have a next signal? */
if(last_pulse && sig_next) {
/* when a signal ends with the same level as the next signal begins, let the next signal generate the whole pulse.
beware, we do not want the level after the last edge, but the last level before that edge */
bool end_level = sig->start_level ^ ((sig->edge_cnt % 2) == 0);
/* if they have the same level, pass the duration to the next pulse(s) */
if(end_level == sig_next->start_level) {
trade_for_next = pulse_length;
}
}
/* if it was decided, that the next signal's first pulse shall also handle our "length", then do not queue here */
if(!trade_for_next) {
digital_sequence_queue_pulse(sequence, pulse_length);
if(!dma_buffer->dma_active) {
/* start transmission when buffer was filled enough */
bool start_send = sequence->dma_buffer->write_pos >= (RINGBUFFER_SIZE - 2);
/* or it was the last pulse */
if(last_pulse && last_signal) {
start_send = true;
}
/* start transmission */
if(start_send) {
digital_sequence_setup_dma(sequence);
digital_signal_setup_timer();
/* if the send time is specified, wait till the core timer passed beyond that time */
if(sequence->send_time_active) {
sequence->send_time_active = false;
while(sequence->send_time - DWT->CYCCNT < 0x80000000) {
}
}
digital_signal_start_timer();
dma_buffer->dma_active = true;
}
}
}
}
remainder += sig->internals->reload_reg_remainder;
sig = sig_next;
sig_next = NULL;
}
/* wait until last dma transaction was finished */
FURI_CRITICAL_EXIT();
digital_sequence_finish(sequence);
return true;
}
void digital_sequence_clear(DigitalSequence* sequence) {
furi_assert(sequence);
sequence->sequence_used = 0;
}
void digital_sequence_timebase_correction(DigitalSequence* sequence, float factor) {
for(uint32_t sig_pos = 0; sig_pos < sequence->signals_size; sig_pos++) {
DigitalSignal* signal = sequence->signals[sig_pos];
if(signal) {
signal->internals->factor = (uint32_t)(1024 * 1024 * factor);
digital_signal_prepare_arr(signal);
digital_signal_extend_last_period(signal, ticks);
}
}
}
+96 -49
View File
@@ -1,74 +1,121 @@
/**
* @file digital_signal.h
* @brief Simple digital signal container for the DigitalSequence library.
*
* Each signal is represented by its start level (high or low) and one or more periods.
* The output will transition to its inverse value on each period boundary.
*
* Example: A signal with n periods and HIGH start level.
*
* ```
* ----+ +------+ +- ... -+
* t0 | t1 | t2 | t3 | | tn - 1
* +--------+ +----+ +--------
* ```
*
*/
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <furi_hal_gpio.h>
#ifdef __cplusplus
extern "C" {
#endif
/* helper for easier signal generation */
// DigitalSignal uses 10 picosecond time units (1 tick = 10 ps).
// Use the macros below to convert the time from other units.
#define DIGITAL_SIGNAL_MS(x) ((x)*100000000UL)
#define DIGITAL_SIGNAL_US(x) ((x)*100000UL)
#define DIGITAL_SIGNAL_NS(x) ((x)*100UL)
#define DIGITAL_SIGNAL_PS(x) ((x) / 10UL)
/* using an anonymous type for the internals */
typedef struct DigitalSignalInternals DigitalSignalInternals;
typedef struct DigitalSignal DigitalSignal;
/* and a public one for accessing user-side fields */
typedef struct DigitalSignal {
bool start_level;
uint32_t edge_cnt;
uint32_t edges_max_cnt;
uint32_t* edge_timings;
uint32_t* reload_reg_buff; /* internal, but used by unit tests */
DigitalSignalInternals* internals;
} DigitalSignal;
typedef struct DigitalSequence DigitalSequence;
DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt);
/**
* @brief Allocate a DigitalSignal instance with a defined maximum size.
*
* @param[in] max_size the maximum number of periods the instance will be able to contain.
* @returns pointer to the allocated instance.
*/
DigitalSignal* digital_signal_alloc(uint32_t max_size);
/**
* @brief Delete a previously allocated DigitalSignal instance.
*
* @param[in,out] signal pointer to the instance to be deleted.
*/
void digital_signal_free(DigitalSignal* signal);
void digital_signal_add(DigitalSignal* signal, uint32_t ticks);
/**
* @brief Append one period to the end of the DigitalSignal instance.
*
* @param[in,out] signal pointer to a the instance to append to.
* @param[in] ticks the period length, in 10 picosecond units.
*/
void digital_signal_add_period(DigitalSignal* signal, uint32_t ticks);
void digital_signal_add_pulse(DigitalSignal* signal, uint32_t ticks, bool level);
/**
* @brief Append one period to the end of the DigitalSignal instance, with the level specified.
*
* If the level is the same as the last level contained in the instance, then it is extened
* by the given ticks value. Otherwise, the behaviour is identical to digital_signal_add_period().
*
* Example 1: add tc with HIGH level
* ```
* before:
* ... ------+
* ta | tb
* +-------
* after:
* ... ------+ +-------
* ta | tb | tc
* +------+
* ```
* Example 2: add tc with LOW level
* ```
* before:
* ... ------+
* ta | tb
* +-------
* after:
* ... ------+
* ta | tb + tc
* +--------------
* ```
*
* @param[in,out] signal pointer to the instance to append to.
* @param[in] ticks the period length, in 10 picosecond units.
* @param[in] level the level to be set during the period.
*/
void digital_signal_add_period_with_level(DigitalSignal* signal, uint32_t ticks, bool level);
bool digital_signal_append(DigitalSignal* signal_a, DigitalSignal* signal_b);
/**
* @brief Get the current start level contained in the DigitalSignal instance.
*
* If not explicitly set with digital_signal_set_start_level(), it defaults to false.
*
* @param[in] signal pointer to the instance to be queried.
* @returns the start level value.
*/
bool digital_signal_get_start_level(const DigitalSignal* signal);
void digital_signal_prepare_arr(DigitalSignal* signal);
/**
* @brief Set the start level contained in the DigitalSignal instance.
*
* @param[in,out] signal pointer to the instance to be modified.
* @param[in] level signal level to be set as the start level.
*/
void digital_signal_set_start_level(DigitalSignal* signal, bool level);
bool digital_signal_get_start_level(DigitalSignal* signal);
uint32_t digital_signal_get_edges_cnt(DigitalSignal* signal);
uint32_t digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num);
void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio);
DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio);
void digital_sequence_free(DigitalSequence* sequence);
void digital_sequence_set_signal(
DigitalSequence* sequence,
uint8_t signal_index,
DigitalSignal* signal);
void digital_sequence_set_sendtime(DigitalSequence* sequence, uint32_t send_time);
void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index);
bool digital_sequence_send(DigitalSequence* sequence);
void digital_sequence_clear(DigitalSequence* sequence);
void digital_sequence_timebase_correction(DigitalSequence* sequence, float factor);
/**
* @brief Get the number of periods currently stored in a DigitalSignal instance.
*
* @param[in] signal pointer to the instance to be queried.
* @return the number of periods stored in the instance.
*/
uint32_t digital_signal_get_size(const DigitalSignal* signal);
#ifdef __cplusplus
}
+23
View File
@@ -0,0 +1,23 @@
/**
* @file digital_signal_i.h
* @brief DigitalSignal private definitions.
*
* This file is an implementation detail. It must not be included in
* any public API-related headers.
*/
#include <stdint.h>
#include <stdbool.h>
#define DIGITAL_SIGNAL_T_TIM 1562 /**< 15.625 ns *100 */
#define DIGITAL_SIGNAL_T_TIM_DIV2 (DIGITAL_SIGNAL_T_TIM / 2) /**< 15.625 ns / 2 *100 */
/**
* @brief DigitalSignal structure type.
*/
struct DigitalSignal {
bool start_level; /**< The level to begin the signal with. */
uint32_t size; /**< Current period count contained in the instance. */
uint32_t max_size; /**< Maximum period count this instance can hold. */
uint32_t* data; /**< Pointer to the array of time periods. */
int32_t remainder; /**< Remainder left after converting all periods into timer ticks. */
};
@@ -0,0 +1,139 @@
#include "iso14443_3a_signal.h"
#include <digital_signal/digital_sequence.h>
#define BITS_IN_BYTE (8)
#define ISO14443_3A_SIGNAL_BIT_MAX_EDGES (10)
#define ISO14443_3A_SIGNAL_MAX_EDGES (1350)
#define ISO14443_3A_SIGNAL_SEQUENCE_SIZE \
(ISO14443_3A_SIGNAL_MAX_EDGES / (ISO14443_3A_SIGNAL_BIT_MAX_EDGES - 2))
#define ISO14443_3A_SIGNAL_F_SIG (13560000.0)
#define ISO14443_3A_SIGNAL_T_SIG 7374 //73.746ns*100
#define ISO14443_3A_SIGNAL_T_SIG_X8 58992 //T_SIG*8
#define ISO14443_3A_SIGNAL_T_SIG_X8_X8 471936 //T_SIG*8*8
#define ISO14443_3A_SIGNAL_T_SIG_X8_X9 530928 //T_SIG*8*9
typedef enum {
Iso14443_3aSignalIndexZero,
Iso14443_3aSignalIndexOne,
Iso14443_3aSignalIndexCount,
} Iso14443_3aSignalIndex;
typedef DigitalSignal* Iso14443_3aSignalBank[Iso14443_3aSignalIndexCount];
struct Iso14443_3aSignal {
DigitalSequence* tx_sequence;
Iso14443_3aSignalBank signals;
};
static void iso14443_3a_signal_add_byte(Iso14443_3aSignal* instance, uint8_t byte, bool parity) {
for(size_t i = 0; i < BITS_IN_BYTE; i++) {
digital_sequence_add_signal(
instance->tx_sequence,
FURI_BIT(byte, i) ? Iso14443_3aSignalIndexOne : Iso14443_3aSignalIndexZero);
}
digital_sequence_add_signal(
instance->tx_sequence, parity ? Iso14443_3aSignalIndexOne : Iso14443_3aSignalIndexZero);
}
static void iso14443_3a_signal_encode(
Iso14443_3aSignal* instance,
const uint8_t* tx_data,
const uint8_t* tx_parity,
size_t tx_bits) {
furi_assert(instance);
furi_assert(tx_data);
furi_assert(tx_parity);
// Start of frame
digital_sequence_add_signal(instance->tx_sequence, Iso14443_3aSignalIndexOne);
if(tx_bits < BITS_IN_BYTE) {
for(size_t i = 0; i < tx_bits; i++) {
digital_sequence_add_signal(
instance->tx_sequence,
FURI_BIT(tx_data[0], i) ? Iso14443_3aSignalIndexOne : Iso14443_3aSignalIndexZero);
}
} else {
for(size_t i = 0; i < tx_bits / BITS_IN_BYTE; i++) {
bool parity = FURI_BIT(tx_parity[i / BITS_IN_BYTE], i % BITS_IN_BYTE);
iso14443_3a_signal_add_byte(instance, tx_data[i], parity);
}
}
}
static inline void iso14443_3a_signal_set_bit(DigitalSignal* signal, bool bit) {
digital_signal_set_start_level(signal, bit);
if(bit) {
for(uint32_t i = 0; i < 7; ++i) {
digital_signal_add_period(signal, ISO14443_3A_SIGNAL_T_SIG_X8);
}
digital_signal_add_period(signal, ISO14443_3A_SIGNAL_T_SIG_X8_X9);
} else {
digital_signal_add_period(signal, ISO14443_3A_SIGNAL_T_SIG_X8_X8);
for(uint32_t i = 0; i < 8; ++i) {
digital_signal_add_period(signal, ISO14443_3A_SIGNAL_T_SIG_X8);
}
}
}
static inline void iso14443_3a_signal_bank_fill(Iso14443_3aSignalBank bank) {
for(uint32_t i = 0; i < Iso14443_3aSignalIndexCount; ++i) {
bank[i] = digital_signal_alloc(ISO14443_3A_SIGNAL_BIT_MAX_EDGES);
iso14443_3a_signal_set_bit(bank[i], i % Iso14443_3aSignalIndexCount != 0);
}
}
static inline void iso14443_3a_signal_bank_clear(Iso14443_3aSignalBank bank) {
for(uint32_t i = 0; i < Iso14443_3aSignalIndexCount; ++i) {
digital_signal_free(bank[i]);
}
}
static inline void
iso14443_3a_signal_bank_register(Iso14443_3aSignalBank bank, DigitalSequence* sequence) {
for(uint32_t i = 0; i < Iso14443_3aSignalIndexCount; ++i) {
digital_sequence_register_signal(sequence, i, bank[i]);
}
}
Iso14443_3aSignal* iso14443_3a_signal_alloc(const GpioPin* pin) {
furi_assert(pin);
Iso14443_3aSignal* instance = malloc(sizeof(Iso14443_3aSignal));
instance->tx_sequence = digital_sequence_alloc(ISO14443_3A_SIGNAL_SEQUENCE_SIZE, pin);
iso14443_3a_signal_bank_fill(instance->signals);
iso14443_3a_signal_bank_register(instance->signals, instance->tx_sequence);
return instance;
}
void iso14443_3a_signal_free(Iso14443_3aSignal* instance) {
furi_assert(instance);
furi_assert(instance->tx_sequence);
iso14443_3a_signal_bank_clear(instance->signals);
digital_sequence_free(instance->tx_sequence);
free(instance);
}
void iso14443_3a_signal_tx(
Iso14443_3aSignal* instance,
const uint8_t* tx_data,
const uint8_t* tx_parity,
size_t tx_bits) {
furi_assert(instance);
furi_assert(tx_data);
furi_assert(tx_parity);
FURI_CRITICAL_ENTER();
digital_sequence_clear(instance->tx_sequence);
iso14443_3a_signal_encode(instance, tx_data, tx_parity, tx_bits);
digital_sequence_transmit(instance->tx_sequence);
FURI_CRITICAL_EXIT();
}
@@ -0,0 +1,51 @@
/**
* @file iso14443_3a_signal.h
* @brief DigitalSequence preset for generating ISO14443-3A compliant signals.
*/
#pragma once
#include <furi_hal_resources.h>
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct Iso14443_3aSignal Iso14443_3aSignal;
/**
* @brief Allocate an Iso14443_3aSignal instance with a set GPIO pin.
*
* @param[in] pin GPIO pin to use during transmission.
* @returns pointer to the allocated instance.
*/
Iso14443_3aSignal* iso14443_3a_signal_alloc(const GpioPin* pin);
/**
* @brief Delete an Iso14443_3aSignal instance.
*
* @param[in,out] instance pointer to the instance to be deleted.
*/
void iso14443_3a_signal_free(Iso14443_3aSignal* instance);
/**
* @brief Transmit arbitrary bytes using an Iso14443_3aSignal instance.
*
* This function will block until the transmisson has been completed.
*
* @param[in] instance pointer to the instance used in transmission.
* @param[in] tx_data pointer to the data to be transmitted.
* @param[in] tx_parity pointer to the bit-packed parity array.
* @param[in] tx_bits size of the data to be transmitted in bits.
*/
void iso14443_3a_signal_tx(
Iso14443_3aSignal* instance,
const uint8_t* tx_data,
const uint8_t* tx_parity,
size_t tx_bits);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,204 @@
#include "iso15693_signal.h"
#include <digital_signal/digital_sequence.h>
#define BITS_IN_BYTE (8U)
#define ISO15693_SIGNAL_COEFF_HI (1U)
#define ISO15693_SIGNAL_COEFF_LO (4U)
#define ISO15693_SIGNAL_ZERO_EDGES (16U)
#define ISO15693_SIGNAL_ONE_EDGES (ISO15693_SIGNAL_ZERO_EDGES + 1U)
#define ISO15693_SIGNAL_EOF_EDGES (64U)
#define ISO15693_SIGNAL_SOF_EDGES (ISO15693_SIGNAL_EOF_EDGES + 1U)
#define ISO15693_SIGNAL_EDGES (1350U)
#define ISO15693_SIGNAL_FC (13.56e6)
#define ISO15693_SIGNAL_FC_16 (16.0e11 / ISO15693_SIGNAL_FC)
#define ISO15693_SIGNAL_FC_256 (256.0e11 / ISO15693_SIGNAL_FC)
#define ISO15693_SIGNAL_FC_768 (768.0e11 / ISO15693_SIGNAL_FC)
typedef enum {
Iso15693SignalIndexSof,
Iso15693SignalIndexEof,
Iso15693SignalIndexOne,
Iso15693SignalIndexZero,
Iso15693SignalIndexNum,
} Iso15693SignalIndex;
typedef DigitalSignal* Iso15693SignalBank[Iso15693SignalIndexNum];
struct Iso15693Signal {
DigitalSequence* tx_sequence;
Iso15693SignalBank banks[Iso15693SignalDataRateNum];
};
// Add an unmodulated signal for the length of Fc / 256 * k (where k = 1 or 4)
static void iso15693_add_silence(DigitalSignal* signal, Iso15693SignalDataRate data_rate) {
const uint32_t k = data_rate == Iso15693SignalDataRateHi ? ISO15693_SIGNAL_COEFF_HI :
ISO15693_SIGNAL_COEFF_LO;
digital_signal_add_period_with_level(signal, ISO15693_SIGNAL_FC_256 * k, false);
}
// Add 8 * k subcarrier pulses of Fc / 16 (where k = 1 or 4)
static void iso15693_add_subcarrier(DigitalSignal* signal, Iso15693SignalDataRate data_rate) {
const uint32_t k = data_rate == Iso15693SignalDataRateHi ? ISO15693_SIGNAL_COEFF_HI :
ISO15693_SIGNAL_COEFF_LO;
for(uint32_t i = 0; i < ISO15693_SIGNAL_ZERO_EDGES * k; ++i) {
digital_signal_add_period_with_level(signal, ISO15693_SIGNAL_FC_16, !(i % 2));
}
}
static void iso15693_add_bit(DigitalSignal* signal, Iso15693SignalDataRate data_rate, bool bit) {
if(bit) {
iso15693_add_silence(signal, data_rate);
iso15693_add_subcarrier(signal, data_rate);
} else {
iso15693_add_subcarrier(signal, data_rate);
iso15693_add_silence(signal, data_rate);
}
}
static inline void iso15693_add_sof(DigitalSignal* signal, Iso15693SignalDataRate data_rate) {
// Not adding silence since it only increases response time
for(uint32_t i = 0; i < ISO15693_SIGNAL_FC_768 / ISO15693_SIGNAL_FC_256; ++i) {
iso15693_add_subcarrier(signal, data_rate);
}
iso15693_add_bit(signal, data_rate, true);
}
static inline void iso15693_add_eof(DigitalSignal* signal, Iso15693SignalDataRate data_rate) {
iso15693_add_bit(signal, data_rate, false);
for(uint32_t i = 0; i < ISO15693_SIGNAL_FC_768 / ISO15693_SIGNAL_FC_256; ++i) {
iso15693_add_subcarrier(signal, data_rate);
}
// Not adding silence since it does nothing here
}
static inline uint32_t
iso15693_get_sequence_index(Iso15693SignalIndex index, Iso15693SignalDataRate data_rate) {
return index + data_rate * Iso15693SignalIndexNum;
}
static inline void
iso15693_add_byte(Iso15693Signal* instance, Iso15693SignalDataRate data_rate, uint8_t byte) {
for(size_t i = 0; i < BITS_IN_BYTE; i++) {
const uint8_t bit = byte & (1U << i);
digital_sequence_add_signal(
instance->tx_sequence,
iso15693_get_sequence_index(
bit ? Iso15693SignalIndexOne : Iso15693SignalIndexZero, data_rate));
}
}
static inline void iso15693_signal_encode(
Iso15693Signal* instance,
Iso15693SignalDataRate data_rate,
const uint8_t* tx_data,
size_t tx_data_size) {
digital_sequence_add_signal(
instance->tx_sequence, iso15693_get_sequence_index(Iso15693SignalIndexSof, data_rate));
for(size_t i = 0; i < tx_data_size; i++) {
iso15693_add_byte(instance, data_rate, tx_data[i]);
}
digital_sequence_add_signal(
instance->tx_sequence, iso15693_get_sequence_index(Iso15693SignalIndexEof, data_rate));
}
static void iso15693_signal_bank_fill(Iso15693Signal* instance, Iso15693SignalDataRate data_rate) {
const uint32_t k = data_rate == Iso15693SignalDataRateHi ? ISO15693_SIGNAL_COEFF_HI :
ISO15693_SIGNAL_COEFF_LO;
DigitalSignal** bank = instance->banks[data_rate];
bank[Iso15693SignalIndexSof] = digital_signal_alloc(ISO15693_SIGNAL_SOF_EDGES * k);
bank[Iso15693SignalIndexEof] = digital_signal_alloc(ISO15693_SIGNAL_EOF_EDGES * k);
bank[Iso15693SignalIndexOne] = digital_signal_alloc(ISO15693_SIGNAL_ONE_EDGES * k);
bank[Iso15693SignalIndexZero] = digital_signal_alloc(ISO15693_SIGNAL_ZERO_EDGES * k);
iso15693_add_sof(bank[Iso15693SignalIndexSof], data_rate);
iso15693_add_eof(bank[Iso15693SignalIndexEof], data_rate);
iso15693_add_bit(bank[Iso15693SignalIndexOne], data_rate, true);
iso15693_add_bit(bank[Iso15693SignalIndexZero], data_rate, false);
}
static void
iso15693_signal_bank_clear(Iso15693Signal* instance, Iso15693SignalDataRate data_rate) {
DigitalSignal** bank = instance->banks[data_rate];
for(uint32_t i = 0; i < Iso15693SignalIndexNum; ++i) {
digital_signal_free(bank[i]);
}
}
static void
iso15693_signal_bank_register(Iso15693Signal* instance, Iso15693SignalDataRate data_rate) {
for(uint32_t i = 0; i < Iso15693SignalIndexNum; ++i) {
digital_sequence_register_signal(
instance->tx_sequence,
iso15693_get_sequence_index(i, data_rate),
instance->banks[data_rate][i]);
}
}
Iso15693Signal* iso15693_signal_alloc(const GpioPin* pin) {
furi_assert(pin);
Iso15693Signal* instance = malloc(sizeof(Iso15693Signal));
instance->tx_sequence = digital_sequence_alloc(BITS_IN_BYTE * 255 + 2, pin);
for(uint32_t i = 0; i < Iso15693SignalDataRateNum; ++i) {
iso15693_signal_bank_fill(instance, i);
iso15693_signal_bank_register(instance, i);
}
return instance;
}
void iso15693_signal_free(Iso15693Signal* instance) {
furi_assert(instance);
digital_sequence_free(instance->tx_sequence);
for(uint32_t i = 0; i < Iso15693SignalDataRateNum; ++i) {
iso15693_signal_bank_clear(instance, i);
}
free(instance);
}
void iso15693_signal_tx(
Iso15693Signal* instance,
Iso15693SignalDataRate data_rate,
const uint8_t* tx_data,
size_t tx_data_size) {
furi_assert(instance);
furi_assert(data_rate < Iso15693SignalDataRateNum);
furi_assert(tx_data);
FURI_CRITICAL_ENTER();
digital_sequence_clear(instance->tx_sequence);
iso15693_signal_encode(instance, data_rate, tx_data, tx_data_size);
digital_sequence_transmit(instance->tx_sequence);
FURI_CRITICAL_EXIT();
}
void iso15693_signal_tx_sof(Iso15693Signal* instance, Iso15693SignalDataRate data_rate) {
furi_assert(instance);
furi_assert(data_rate < Iso15693SignalDataRateNum);
FURI_CRITICAL_ENTER();
digital_sequence_clear(instance->tx_sequence);
digital_sequence_add_signal(
instance->tx_sequence, iso15693_get_sequence_index(Iso15693SignalIndexSof, data_rate));
digital_sequence_transmit(instance->tx_sequence);
FURI_CRITICAL_EXIT();
}
@@ -0,0 +1,73 @@
/**
* @file iso15693_signal.h
* @brief DigitalSequence preset for generating ISO15693-compliant signals.
*
*/
#pragma once
#include <furi_hal_resources.h>
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct Iso15693Signal Iso15693Signal;
/**
* @brief Supported data rates.
*/
typedef enum {
Iso15693SignalDataRateHi, /**< High data rate. */
Iso15693SignalDataRateLo, /**< Low data rate. */
Iso15693SignalDataRateNum, /**< Data rate mode count. Internal use. */
} Iso15693SignalDataRate;
/**
* @brief Allocate an Iso15693Signal instance with a set GPIO pin.
*
* @param[in] pin GPIO pin to use during transmission.
* @returns pointer to the allocated instance.
*/
Iso15693Signal* iso15693_signal_alloc(const GpioPin* pin);
/**
* @brief Delete an Iso15693Signal instance.
*
* @param[in,out] instance pointer to the instance to be deleted.
*/
void iso15693_signal_free(Iso15693Signal* instance);
/**
* @brief Transmit arbitrary bytes using an Iso15693Signal instance.
* @see Iso15693SignalDataRate
*
* This function will block until the transmisson has been completed.
*
* @param[in] instance pointer to the instance used in transmission.
* @param[in] data_rate data rate to transmit at.
* @param[in] tx_data pointer to the data to be transmitted.
* @param[in] tx_data_size size of the data to be transmitted in bytes.
*/
void iso15693_signal_tx(
Iso15693Signal* instance,
Iso15693SignalDataRate data_rate,
const uint8_t* tx_data,
size_t tx_data_size);
/**
* @brief Transmit Start of Frame using an Iso15693Signal instance.
* @see Iso15693SignalDataRate
*
* This function will block until the transmisson has been completed.
*
* @param[in] instance pointer to the instance used in transmission.
* @param[in] data_rate data rate to transmit at.
*/
void iso15693_signal_tx_sof(Iso15693Signal* instance, Iso15693SignalDataRate data_rate);
#ifdef __cplusplus
}
#endif
+81
View File
@@ -0,0 +1,81 @@
#include "st25r3916.h"
#include <furi.h>
void st25r3916_mask_irq(FuriHalSpiBusHandle* handle, uint32_t mask) {
furi_assert(handle);
uint8_t irq_mask_regs[4] = {
mask & 0xff,
(mask >> 8) & 0xff,
(mask >> 16) & 0xff,
(mask >> 24) & 0xff,
};
st25r3916_write_burst_regs(handle, ST25R3916_REG_IRQ_MASK_MAIN, irq_mask_regs, 4);
}
uint32_t st25r3916_get_irq(FuriHalSpiBusHandle* handle) {
furi_assert(handle);
uint8_t irq_regs[4] = {};
uint32_t irq = 0;
st25r3916_read_burst_regs(handle, ST25R3916_REG_IRQ_MASK_MAIN, irq_regs, 4);
// FURI_LOG_I(
// "Mask Irq", "%02X %02X %02X %02X", irq_regs[0], irq_regs[1], irq_regs[2], irq_regs[3]);
st25r3916_read_burst_regs(handle, ST25R3916_REG_IRQ_MAIN, irq_regs, 4);
irq = (uint32_t)irq_regs[0];
irq |= (uint32_t)irq_regs[1] << 8;
irq |= (uint32_t)irq_regs[2] << 16;
irq |= (uint32_t)irq_regs[3] << 24;
// FURI_LOG_I("iRQ", "%02X %02X %02X %02X", irq_regs[0], irq_regs[1], irq_regs[2], irq_regs[3]);
return irq;
}
void st25r3916_write_fifo(FuriHalSpiBusHandle* handle, const uint8_t* buff, size_t bits) {
furi_assert(handle);
furi_assert(buff);
size_t bytes = (bits + 7) / 8;
st25r3916_write_reg(handle, ST25R3916_REG_NUM_TX_BYTES2, (uint8_t)(bits & 0xFFU));
st25r3916_write_reg(handle, ST25R3916_REG_NUM_TX_BYTES1, (uint8_t)((bits >> 8) & 0xFFU));
st25r3916_reg_write_fifo(handle, buff, bytes);
}
bool st25r3916_read_fifo(
FuriHalSpiBusHandle* handle,
uint8_t* buff,
size_t buff_size,
size_t* buff_bits) {
furi_assert(handle);
furi_assert(buff);
bool read_success = false;
do {
uint8_t fifo_status[2] = {};
st25r3916_read_burst_regs(handle, ST25R3916_REG_FIFO_STATUS1, fifo_status, 2);
size_t bytes = ((fifo_status[1] & ST25R3916_REG_FIFO_STATUS2_fifo_b_mask) >>
ST25R3916_REG_FIFO_STATUS2_fifo_b_shift) |
fifo_status[0];
uint8_t bits =
((fifo_status[1] & ST25R3916_REG_FIFO_STATUS2_fifo_lb_mask) >>
ST25R3916_REG_FIFO_STATUS2_fifo_lb_shift);
if(bytes == 0) break;
if(bytes > buff_size) break;
st25r3916_reg_read_fifo(handle, buff, bytes);
if(bits) {
*buff_bits = (bytes - 1) * 8 + bits;
} else {
*buff_bits = bytes * 8;
}
read_success = true;
} while(false);
return read_success;
}
+113
View File
@@ -0,0 +1,113 @@
#pragma once
#include "st25r3916_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ST25R3916_IRQ_MASK_ALL (uint32_t)(0xFFFFFFFFUL) /** All ST25R3916 interrupt sources */
#define ST25R3916_IRQ_MASK_NONE (uint32_t)(0x00000000UL) /**No ST25R3916 interrupt source */
/** Main interrupt register */
#define ST25R3916_IRQ_MASK_OSC (uint32_t)(0x00000080U) /** ST25R3916 oscillator stable interrupt */
#define ST25R3916_IRQ_MASK_FWL (uint32_t)(0x00000040U) /** ST25R3916 FIFO water level interrupt */
#define ST25R3916_IRQ_MASK_RXS (uint32_t)(0x00000020U) /** ST25R3916 start of receive interrupt */
#define ST25R3916_IRQ_MASK_RXE (uint32_t)(0x00000010U) /** ST25R3916 end of receive interrupt */
#define ST25R3916_IRQ_MASK_TXE \
(uint32_t)(0x00000008U) /** ST25R3916 end of transmission interrupt */
#define ST25R3916_IRQ_MASK_COL (uint32_t)(0x00000004U) /** ST25R3916 bit collision interrupt */
#define ST25R3916_IRQ_MASK_RX_REST \
(uint32_t)(0x00000002U) /** ST25R3916 automatic reception restart interrupt */
#define ST25R3916_IRQ_MASK_RFU (uint32_t)(0x00000001U) /** ST25R3916 RFU interrupt */
/** Timer and NFC interrupt register */
#define ST25R3916_IRQ_MASK_DCT \
(uint32_t)(0x00008000U) /** ST25R3916 termination of direct command interrupt. */
#define ST25R3916_IRQ_MASK_NRE \
(uint32_t)(0x00004000U) /** ST25R3916 no-response timer expired interrupt */
#define ST25R3916_IRQ_MASK_GPE \
(uint32_t)(0x00002000U) /** ST25R3916 general purpose timer expired interrupt */
#define ST25R3916_IRQ_MASK_EON (uint32_t)(0x00001000U) /** ST25R3916 external field on interrupt */
#define ST25R3916_IRQ_MASK_EOF \
(uint32_t)(0x00000800U) /** ST25R3916 external field off interrupt */
#define ST25R3916_IRQ_MASK_CAC \
(uint32_t)(0x00000400U) /** ST25R3916 collision during RF collision avoidance */
#define ST25R3916_IRQ_MASK_CAT \
(uint32_t)(0x00000200U) /** ST25R3916 minimum guard time expired interrupt */
#define ST25R3916_IRQ_MASK_NFCT \
(uint32_t)(0x00000100U) /** ST25R3916 initiator bit rate recognised interrupt */
/** Error and wake-up interrupt register */
#define ST25R3916_IRQ_MASK_CRC (uint32_t)(0x00800000U) /** ST25R3916 CRC error interrupt */
#define ST25R3916_IRQ_MASK_PAR (uint32_t)(0x00400000U) /** ST25R3916 parity error interrupt */
#define ST25R3916_IRQ_MASK_ERR2 \
(uint32_t)(0x00200000U) /** ST25R3916 soft framing error interrupt */
#define ST25R3916_IRQ_MASK_ERR1 \
(uint32_t)(0x00100000U) /** ST25R3916 hard framing error interrupt */
#define ST25R3916_IRQ_MASK_WT (uint32_t)(0x00080000U) /** ST25R3916 wake-up interrupt */
#define ST25R3916_IRQ_MASK_WAM \
(uint32_t)(0x00040000U) /** ST25R3916 wake-up due to amplitude interrupt */
#define ST25R3916_IRQ_MASK_WPH \
(uint32_t)(0x00020000U) /** ST25R3916 wake-up due to phase interrupt */
#define ST25R3916_IRQ_MASK_WCAP \
(uint32_t)(0x00010000U) /** ST25R3916 wake-up due to capacitance measurement */
/** Passive Target Interrupt Register */
#define ST25R3916_IRQ_MASK_PPON2 \
(uint32_t)(0x80000000U) /** ST25R3916 PPON2 Field on waiting Timer interrupt */
#define ST25R3916_IRQ_MASK_SL_WL \
(uint32_t)(0x40000000U) /** ST25R3916 Passive target slot number water level interrupt */
#define ST25R3916_IRQ_MASK_APON \
(uint32_t)(0x20000000U) /** ST25R3916 Anticollision done and Field On interrupt */
#define ST25R3916_IRQ_MASK_RXE_PTA \
(uint32_t)(0x10000000U) /** ST25R3916 RXE with an automatic response interrupt */
#define ST25R3916_IRQ_MASK_WU_F \
(uint32_t)(0x08000000U) /** ST25R3916 212/424b/s Passive target interrupt: Active */
#define ST25R3916_IRQ_MASK_RFU2 (uint32_t)(0x04000000U) /** ST25R3916 RFU2 interrupt */
#define ST25R3916_IRQ_MASK_WU_A_X \
(uint32_t)(0x02000000U) /** ST25R3916 106kb/s Passive target state interrupt: Active* */
#define ST25R3916_IRQ_MASK_WU_A \
(uint32_t)(0x01000000U) /** ST25R3916 106kb/s Passive target state interrupt: Active */
/** Mask st25r3916 interrupts
*
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param mask - mask of interrupts to be disabled
*/
void st25r3916_mask_irq(FuriHalSpiBusHandle* handle, uint32_t mask);
/** Get st25r3916 interrupts
*
* @param handle - pointer to FuriHalSpiBusHandle instance
*
* @return received interrupts
*/
uint32_t st25r3916_get_irq(FuriHalSpiBusHandle* handle);
/** Write FIFO
*
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param buff - buffer to write to FIFO
* @param bits - number of bits to write
*/
void st25r3916_write_fifo(FuriHalSpiBusHandle* handle, const uint8_t* buff, size_t bits);
/** Read FIFO
*
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param buff - buffer to read from FIFO
* @param buff_size - buffer size n bytes
* @param buff_bits - pointer to number of bits read
*
* @return true if read success, false otherwise
*/
bool st25r3916_read_fifo(
FuriHalSpiBusHandle* handle,
uint8_t* buff,
size_t buff_size,
size_t* buff_bits);
#ifdef __cplusplus
}
#endif
+257
View File
@@ -0,0 +1,257 @@
#include "st25r3916_reg.h"
#include <furi.h>
#define ST25R3916_WRITE_MODE \
(0U << 6) /*!< ST25R3916 Operation Mode: Write */
#define ST25R3916_READ_MODE \
(1U << 6) /*!< ST25R3916 Operation Mode: Read */
#define ST25R3916_CMD_MODE \
(3U << 6) /*!< ST25R3916 Operation Mode: Direct Command */
#define ST25R3916_FIFO_LOAD \
(0x80U) /*!< ST25R3916 Operation Mode: FIFO Load */
#define ST25R3916_FIFO_READ \
(0x9FU) /*!< ST25R3916 Operation Mode: FIFO Read */
#define ST25R3916_PT_A_CONFIG_LOAD \
(0xA0U) /*!< ST25R3916 Operation Mode: Passive Target Memory A-Config Load */
#define ST25R3916_PT_F_CONFIG_LOAD \
(0xA8U) /*!< ST25R3916 Operation Mode: Passive Target Memory F-Config Load */
#define ST25R3916_PT_TSN_DATA_LOAD \
(0xACU) /*!< ST25R3916 Operation Mode: Passive Target Memory TSN Load */
#define ST25R3916_PT_MEM_READ \
(0xBFU) /*!< ST25R3916 Operation Mode: Passive Target Memory Read */
#define ST25R3916_CMD_LEN \
(1U) /*!< ST25R3916 CMD length */
#define ST25R3916_FIFO_DEPTH (512U)
#define ST25R3916_BUF_LEN \
(ST25R3916_CMD_LEN + \
ST25R3916_FIFO_DEPTH) /*!< ST25R3916 communication buffer: CMD + FIFO length */
static void st25r3916_reg_tx_byte(FuriHalSpiBusHandle* handle, uint8_t byte) {
uint8_t val = byte;
furi_hal_spi_bus_tx(handle, &val, 1, 5);
}
void st25r3916_read_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* val) {
furi_assert(handle);
st25r3916_read_burst_regs(handle, reg, val, 1);
}
void st25r3916_read_burst_regs(
FuriHalSpiBusHandle* handle,
uint8_t reg_start,
uint8_t* values,
uint8_t length) {
furi_assert(handle);
furi_assert(values);
furi_assert(length);
furi_hal_gpio_write(handle->cs, false);
if(reg_start & ST25R3916_SPACE_B) {
// Send direct command first
st25r3916_reg_tx_byte(handle, ST25R3916_CMD_SPACE_B_ACCESS);
}
st25r3916_reg_tx_byte(handle, (reg_start & ~ST25R3916_SPACE_B) | ST25R3916_READ_MODE);
furi_hal_spi_bus_rx(handle, values, length, 5);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_write_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t val) {
furi_assert(handle);
uint8_t reg_val = val;
st25r3916_write_burst_regs(handle, reg, &reg_val, 1);
}
void st25r3916_write_burst_regs(
FuriHalSpiBusHandle* handle,
uint8_t reg_start,
const uint8_t* values,
uint8_t length) {
furi_assert(handle);
furi_assert(values);
furi_assert(length);
furi_hal_gpio_write(handle->cs, false);
if(reg_start & ST25R3916_SPACE_B) {
// Send direct command first
st25r3916_reg_tx_byte(handle, ST25R3916_CMD_SPACE_B_ACCESS);
}
st25r3916_reg_tx_byte(handle, (reg_start & ~ST25R3916_SPACE_B) | ST25R3916_WRITE_MODE);
furi_hal_spi_bus_tx(handle, values, length, 5);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_reg_write_fifo(FuriHalSpiBusHandle* handle, const uint8_t* buff, size_t length) {
furi_assert(handle);
furi_assert(buff);
furi_assert(length);
furi_assert(length <= ST25R3916_FIFO_DEPTH);
furi_hal_gpio_write(handle->cs, false);
st25r3916_reg_tx_byte(handle, ST25R3916_FIFO_LOAD);
furi_hal_spi_bus_tx(handle, buff, length, 200);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_reg_read_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, size_t length) {
furi_assert(handle);
furi_assert(buff);
furi_assert(length);
furi_assert(length <= ST25R3916_FIFO_DEPTH);
furi_hal_gpio_write(handle->cs, false);
st25r3916_reg_tx_byte(handle, ST25R3916_FIFO_READ);
furi_hal_spi_bus_rx(handle, buff, length, 200);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_write_pta_mem(FuriHalSpiBusHandle* handle, const uint8_t* values, size_t length) {
furi_assert(handle);
furi_assert(values);
furi_assert(length);
furi_assert(length <= ST25R3916_PTM_LEN);
furi_hal_gpio_write(handle->cs, false);
st25r3916_reg_tx_byte(handle, ST25R3916_PT_A_CONFIG_LOAD);
furi_hal_spi_bus_tx(handle, values, length, 200);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_read_pta_mem(FuriHalSpiBusHandle* handle, uint8_t* buff, size_t length) {
furi_assert(handle);
furi_assert(buff);
furi_assert(length);
furi_assert(length <= ST25R3916_PTM_LEN);
uint8_t tmp_buff[ST25R3916_PTM_LEN + 1];
furi_hal_gpio_write(handle->cs, false);
st25r3916_reg_tx_byte(handle, ST25R3916_PT_MEM_READ);
furi_hal_spi_bus_rx(handle, tmp_buff, length + 1, 200);
furi_hal_gpio_write(handle->cs, true);
memcpy(buff, tmp_buff + 1, length);
}
void st25r3916_write_ptf_mem(FuriHalSpiBusHandle* handle, const uint8_t* values, size_t length) {
furi_assert(handle);
furi_assert(values);
furi_hal_gpio_write(handle->cs, false);
st25r3916_reg_tx_byte(handle, ST25R3916_PT_F_CONFIG_LOAD);
furi_hal_spi_bus_tx(handle, values, length, 200);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_write_pttsn_mem(FuriHalSpiBusHandle* handle, uint8_t* buff, size_t length) {
furi_assert(handle);
furi_assert(buff);
furi_hal_gpio_write(handle->cs, false);
st25r3916_reg_tx_byte(handle, ST25R3916_PT_TSN_DATA_LOAD);
furi_hal_spi_bus_tx(handle, buff, length, 200);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_direct_cmd(FuriHalSpiBusHandle* handle, uint8_t cmd) {
furi_assert(handle);
furi_hal_gpio_write(handle->cs, false);
st25r3916_reg_tx_byte(handle, cmd | ST25R3916_CMD_MODE);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_read_test_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* val) {
furi_assert(handle);
furi_hal_gpio_write(handle->cs, false);
st25r3916_reg_tx_byte(handle, ST25R3916_CMD_TEST_ACCESS);
st25r3916_reg_tx_byte(handle, reg | ST25R3916_READ_MODE);
furi_hal_spi_bus_rx(handle, val, 1, 5);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_write_test_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t val) {
furi_assert(handle);
furi_hal_gpio_write(handle->cs, false);
st25r3916_reg_tx_byte(handle, ST25R3916_CMD_TEST_ACCESS);
st25r3916_reg_tx_byte(handle, reg | ST25R3916_WRITE_MODE);
furi_hal_spi_bus_tx(handle, &val, 1, 5);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_clear_reg_bits(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t clr_mask) {
furi_assert(handle);
uint8_t reg_val = 0;
st25r3916_read_reg(handle, reg, &reg_val);
if((reg_val & ~clr_mask) != reg_val) {
reg_val &= ~clr_mask;
st25r3916_write_reg(handle, reg, reg_val);
}
}
void st25r3916_set_reg_bits(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t set_mask) {
furi_assert(handle);
uint8_t reg_val = 0;
st25r3916_read_reg(handle, reg, &reg_val);
if((reg_val | set_mask) != reg_val) {
reg_val |= set_mask;
st25r3916_write_reg(handle, reg, reg_val);
}
}
void st25r3916_change_reg_bits(
FuriHalSpiBusHandle* handle,
uint8_t reg,
uint8_t mask,
uint8_t value) {
furi_assert(handle);
st25r3916_modify_reg(handle, reg, mask, (mask & value));
}
void st25r3916_modify_reg(
FuriHalSpiBusHandle* handle,
uint8_t reg,
uint8_t clr_mask,
uint8_t set_mask) {
furi_assert(handle);
uint8_t reg_val = 0;
uint8_t new_val = 0;
st25r3916_read_reg(handle, reg, &reg_val);
new_val = (reg_val & ~clr_mask) | set_mask;
if(new_val != reg_val) {
st25r3916_write_reg(handle, reg, new_val);
}
}
void st25r3916_change_test_reg_bits(
FuriHalSpiBusHandle* handle,
uint8_t reg,
uint8_t mask,
uint8_t value) {
furi_assert(handle);
uint8_t reg_val = 0;
uint8_t new_val = 0;
st25r3916_read_test_reg(handle, reg, &reg_val);
new_val = (reg_val & ~mask) | (mask & value);
if(new_val != reg_val) {
st25r3916_write_test_reg(handle, reg, new_val);
}
}
bool st25r3916_check_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t mask, uint8_t val) {
furi_assert(handle);
uint8_t reg_val = 0;
st25r3916_read_reg(handle, reg, &reg_val);
return ((reg_val & mask) == val);
}
@@ -1,262 +1,202 @@
#pragma once
/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include <furi_hal_spi.h>
/*
* PROJECT: ST25R3916 firmware
* Revision:
* LANGUAGE: ISO C99
*/
#ifdef __cplusplus
extern "C" {
#endif
/*! \file
*
* \author Gustavo Patricio
*
* \brief ST25R3916 communication declaration file
*
* This driver provides basic abstraction for communication with the ST25R3916
*
*
* \addtogroup RFAL
* @{
*
* \addtogroup RFAL-HAL
* \brief RFAL Hardware Abstraction Layer
* @{
*
* \addtogroup ST25R3916
* \brief RFAL ST25R3916 Driver
* @{
*
* \addtogroup ST25R3916_COM
* \brief RFAL ST25R3916 Communications
* @{
*
*/
/** ST25R3916 direct commands */
#define ST25R3916_CMD_SET_DEFAULT \
0xC1U /** Puts the chip in default state (same as after power-up */
#define ST25R3916_CMD_STOP 0xC2U /*!< Stops all activities and clears FIFO */
#define ST25R3916_CMD_TRANSMIT_WITH_CRC 0xC4U /** Transmit with CRC */
#define ST25R3916_CMD_TRANSMIT_WITHOUT_CRC 0xC5U /** Transmit without CRC */
#define ST25R3916_CMD_TRANSMIT_REQA 0xC6U /** Transmit REQA */
#define ST25R3916_CMD_TRANSMIT_WUPA 0xC7U /** Transmit WUPA */
#define ST25R3916_CMD_INITIAL_RF_COLLISION \
0xC8U /** NFC transmit with Initial RF Collision Avoidance */
#define ST25R3916_CMD_RESPONSE_RF_COLLISION_N \
0xC9U /** NFC transmit with Response RF Collision Avoidance */
#define ST25R3916_CMD_GOTO_SENSE 0xCDU /** Passive target logic to Sense/Idle state */
#define ST25R3916_CMD_GOTO_SLEEP 0xCEU /** Passive target logic to Sleep/Halt state */
#define ST25R3916_CMD_MASK_RECEIVE_DATA 0xD0U /** Mask receive data */
#define ST25R3916_CMD_UNMASK_RECEIVE_DATA 0xD1U /** Unmask receive data */
#define ST25R3916_CMD_AM_MOD_STATE_CHANGE 0xD2U /** AM Modulation state change */
#define ST25R3916_CMD_MEASURE_AMPLITUDE 0xD3U /** Measure singal amplitude on RFI inputs */
#define ST25R3916_CMD_RESET_RXGAIN 0xD5U /** Reset RX Gain */
#define ST25R3916_CMD_ADJUST_REGULATORS 0xD6U /** Adjust regulators */
#define ST25R3916_CMD_CALIBRATE_DRIVER_TIMING \
0xD8U /** Starts the sequence to adjust the driver timing */
#define ST25R3916_CMD_MEASURE_PHASE 0xD9U /** Measure phase between RFO and RFI signal */
#define ST25R3916_CMD_CLEAR_RSSI 0xDAU /** Clear RSSI bits and restart the measurement */
#define ST25R3916_CMD_CLEAR_FIFO 0xDBU /** Clears FIFO, Collision and IRQ status */
#define ST25R3916_CMD_TRANSPARENT_MODE 0xDCU /** Transparent mode */
#define ST25R3916_CMD_CALIBRATE_C_SENSOR 0xDDU /** Calibrate the capacitive sensor */
#define ST25R3916_CMD_MEASURE_CAPACITANCE 0xDEU /** Measure capacitance */
#define ST25R3916_CMD_MEASURE_VDD 0xDFU /** Measure power supply voltage */
#define ST25R3916_CMD_START_GP_TIMER 0xE0U /** Start the general purpose timer */
#define ST25R3916_CMD_START_WUP_TIMER 0xE1U /** Start the wake-up timer */
#define ST25R3916_CMD_START_MASK_RECEIVE_TIMER 0xE2U /** Start the mask-receive timer */
#define ST25R3916_CMD_START_NO_RESPONSE_TIMER 0xE3U /** Start the no-response timer */
#define ST25R3916_CMD_START_PPON2_TIMER 0xE4U /** Start PPon2 timer */
#define ST25R3916_CMD_STOP_NRT 0xE8U /** Stop No Response Timer */
#define ST25R3916_CMD_SPACE_B_ACCESS 0xFBU /** Enable R/W access to the test registers */
#define ST25R3916_CMD_TEST_ACCESS 0xFCU /** Enable R/W access to the test registers */
#ifndef ST25R3916_COM_H
#define ST25R3916_COM_H
#define ST25R3916_SPACE_B 0x40U /** ST25R3916 Space-B indicator */
#define ST25R3916_SPACE_B_REG_LEN 16U /** Number of register in the space B */
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "platform.h"
#include "st_errno.h"
#define ST25R3916_FIFO_STATUS_LEN 2 /** Number of FIFO Status Register */
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
#define ST25R3916_SPACE_B 0x40U /*!< ST25R3916 Space-B indicator */
#define ST25R3916_SPACE_B_REG_LEN 16U /*!< Number of register in the space B */
#define ST25R3916_PTM_A_LEN 15U /** Passive target memory A config length */
#define ST25R3916_PTM_B_LEN 0U /** Passive target memory B config length */
#define ST25R3916_PTM_F_LEN 21U /** Passive target memory F config length */
#define ST25R3916_PTM_TSN_LEN 12U /** Passive target memory TSN data length */
#define ST25R3916_FIFO_STATUS_LEN 2 /*!< Number of FIFO Status Register */
#define ST25R3916_PTM_A_LEN 15U /*!< Passive target memory A config length */
#define ST25R3916_PTM_B_LEN 0U /*!< Passive target memory B config length */
#define ST25R3916_PTM_F_LEN 21U /*!< Passive target memory F config length */
#define ST25R3916_PTM_TSN_LEN 12U /*!< Passive target memory TSN data length */
/*! Full Passive target memory length */
/** Full Passive target memory length */
#define ST25R3916_PTM_LEN \
(ST25R3916_PTM_A_LEN + ST25R3916_PTM_B_LEN + ST25R3916_PTM_F_LEN + ST25R3916_PTM_TSN_LEN)
/* IO configuration registers */
#define ST25R3916_REG_IO_CONF1 0x00U /*!< RW IO Configuration Register 1 */
#define ST25R3916_REG_IO_CONF2 0x01U /*!< RW IO Configuration Register 2 */
/** IO configuration registers */
#define ST25R3916_REG_IO_CONF1 0x00U /** RW IO Configuration Register 1 */
#define ST25R3916_REG_IO_CONF2 0x01U /** RW IO Configuration Register 2 */
/* Operation control and mode definition registers */
#define ST25R3916_REG_OP_CONTROL 0x02U /*!< RW Operation Control Register */
#define ST25R3916_REG_MODE 0x03U /*!< RW Mode Definition Register */
#define ST25R3916_REG_BIT_RATE 0x04U /*!< RW Bit Rate Definition Register */
/** Operation control and mode definition */
#define ST25R3916_REG_OP_CONTROL 0x02U /** RW Operation Control Register */
#define ST25R3916_REG_MODE 0x03U /** RW Mode Definition Register */
#define ST25R3916_REG_BIT_RATE 0x04U /** RW Bit Rate Definition Register */
/* Protocol Configuration registers */
#define ST25R3916_REG_ISO14443A_NFC \
0x05U /*!< RW ISO14443A and NFC 106 kBit/s Settings Register */
/** Protocol Configuration registers */
#define ST25R3916_REG_ISO14443A_NFC 0x05U /** RW ISO14443A and NFC 106 kBit/s Settings Register */
#define ST25R3916_REG_EMD_SUP_CONF \
(ST25R3916_SPACE_B | 0x05U) /*!< RW EMD Suppression Configuration Register */
#define ST25R3916_REG_ISO14443B_1 \
0x06U /*!< RW ISO14443B Settings Register 1 */
(ST25R3916_SPACE_B | 0x05U) /*!< RW EMD Suppression Configuration Register */
#define ST25R3916_REG_ISO14443B_1 0x06U /** RW ISO14443B Settings Register 1 */
#define ST25R3916_REG_SUBC_START_TIME \
(ST25R3916_SPACE_B | 0x06U) /*!< RW Subcarrier Start Time Register */
#define ST25R3916_REG_ISO14443B_2 \
0x07U /*!< RW ISO14443B Settings Register 2 */
#define ST25R3916_REG_PASSIVE_TARGET \
0x08U /*!< RW Passive Target Definition Register */
#define ST25R3916_REG_STREAM_MODE \
0x09U /*!< RW Stream Mode Definition Register */
#define ST25R3916_REG_AUX 0x0AU /*!< RW Auxiliary Definition Register */
(ST25R3916_SPACE_B | 0x06U) /*!< RW Subcarrier Start Time Register */
#define ST25R3916_REG_ISO14443B_2 0x07U /** RW ISO14443B Settings Register 2 */
#define ST25R3916_REG_PASSIVE_TARGET 0x08U /** RW Passive Target Definition Register */
#define ST25R3916_REG_STREAM_MODE 0x09U /** RW Stream Mode Definition Register */
#define ST25R3916_REG_AUX 0x0AU /** RW Auxiliary Definition Register */
/* Receiver Configuration registers */
#define ST25R3916_REG_RX_CONF1 0x0BU /*!< RW Receiver Configuration Register 1 */
#define ST25R3916_REG_RX_CONF2 0x0CU /*!< RW Receiver Configuration Register 2 */
#define ST25R3916_REG_RX_CONF3 0x0DU /*!< RW Receiver Configuration Register 3 */
#define ST25R3916_REG_RX_CONF4 0x0EU /*!< RW Receiver Configuration Register 4 */
/** Receiver Configuration registers */
#define ST25R3916_REG_RX_CONF1 0x0BU /** RW Receiver Configuration Register 1 */
#define ST25R3916_REG_RX_CONF2 0x0CU /** RW Receiver Configuration Register 2 */
#define ST25R3916_REG_RX_CONF3 0x0DU /** RW Receiver Configuration Register 3 */
#define ST25R3916_REG_RX_CONF4 0x0EU /** RW Receiver Configuration Register 4 */
#define ST25R3916_REG_P2P_RX_CONF \
(ST25R3916_SPACE_B | 0x0BU) /*!< RW P2P Receiver Configuration Register 1 */
(ST25R3916_SPACE_B | 0x0BU) /** RW P2P Receiver Configuration Register 1 */
#define ST25R3916_REG_CORR_CONF1 \
(ST25R3916_SPACE_B | 0x0CU) /*!< RW Correlator configuration register 1 */
(ST25R3916_SPACE_B | 0x0CU) /** RW Correlator configuration register 1 */
#define ST25R3916_REG_CORR_CONF2 \
(ST25R3916_SPACE_B | 0x0DU) /*!< RW Correlator configuration register 2 */
(ST25R3916_SPACE_B | 0x0DU) /** RW Correlator configuration register 2 */
/* Timer definition registers */
#define ST25R3916_REG_MASK_RX_TIMER \
0x0FU /*!< RW Mask Receive Timer Register */
#define ST25R3916_REG_NO_RESPONSE_TIMER1 \
0x10U /*!< RW No-response Timer Register 1 */
#define ST25R3916_REG_NO_RESPONSE_TIMER2 \
0x11U /*!< RW No-response Timer Register 2 */
#define ST25R3916_REG_TIMER_EMV_CONTROL \
0x12U /*!< RW Timer and EMV Control */
#define ST25R3916_REG_GPT1 0x13U /*!< RW General Purpose Timer Register 1 */
#define ST25R3916_REG_GPT2 0x14U /*!< RW General Purpose Timer Register 2 */
#define ST25R3916_REG_PPON2 0x15U /*!< RW PPON2 Field waiting Timer Register */
#define ST25R3916_REG_SQUELCH_TIMER \
(ST25R3916_SPACE_B | 0x0FU) /*!< RW Squelch timeout Register */
#define ST25R3916_REG_FIELD_ON_GT \
(ST25R3916_SPACE_B | 0x15U) /*!< RW NFC Field on guard time */
/** Timer definition registers */
#define ST25R3916_REG_MASK_RX_TIMER 0x0FU /** RW Mask Receive Timer Register */
#define ST25R3916_REG_NO_RESPONSE_TIMER1 0x10U /** RW No-response Timer Register 1 */
#define ST25R3916_REG_NO_RESPONSE_TIMER2 0x11U /** RW No-response Timer Register 2 */
#define ST25R3916_REG_TIMER_EMV_CONTROL 0x12U /** RW Timer and EMV Control */
#define ST25R3916_REG_GPT1 0x13U /** RW General Purpose Timer Register 1 */
#define ST25R3916_REG_GPT2 0x14U /** RW General Purpose Timer Register 2 */
#define ST25R3916_REG_PPON2 0x15U /** RW PPON2 Field waiting Timer Register */
#define ST25R3916_REG_SQUELCH_TIMER (ST25R3916_SPACE_B | 0x0FU) /** RW Squelch timeout Register */
#define ST25R3916_REG_FIELD_ON_GT (ST25R3916_SPACE_B | 0x15U) /** RW NFC Field on guard time */
/* Interrupt and associated reporting registers */
#define ST25R3916_REG_IRQ_MASK_MAIN \
0x16U /*!< RW Mask Main Interrupt Register */
#define ST25R3916_REG_IRQ_MASK_TIMER_NFC \
0x17U /*!< RW Mask Timer and NFC Interrupt Register */
#define ST25R3916_REG_IRQ_MASK_ERROR_WUP \
0x18U /*!< RW Mask Error and Wake-up Interrupt Register */
#define ST25R3916_REG_IRQ_MASK_TARGET \
0x19U /*!< RW Mask 3916 Target Interrupt Register */
#define ST25R3916_REG_IRQ_MAIN 0x1AU /*!< R Main Interrupt Register */
#define ST25R3916_REG_IRQ_TIMER_NFC \
0x1BU /*!< R Timer and NFC Interrupt Register */
#define ST25R3916_REG_IRQ_ERROR_WUP \
0x1CU /*!< R Error and Wake-up Interrupt Register */
#define ST25R3916_REG_IRQ_TARGET 0x1DU /*!< R ST25R3916 Target Interrupt Register */
#define ST25R3916_REG_FIFO_STATUS1 \
0x1EU /*!< R FIFO Status Register 1 */
#define ST25R3916_REG_FIFO_STATUS2 \
0x1FU /*!< R FIFO Status Register 2 */
#define ST25R3916_REG_COLLISION_STATUS \
0x20U /*!< R Collision Display Register */
#define ST25R3916_REG_PASSIVE_TARGET_STATUS \
0x21U /*!< R Passive target state status */
/** Interrupt and associated reporting registers */
#define ST25R3916_REG_IRQ_MASK_MAIN 0x16U /** RW Mask Main Interrupt Register */
#define ST25R3916_REG_IRQ_MASK_TIMER_NFC 0x17U /** RW Mask Timer and NFC Interrupt Register */
#define ST25R3916_REG_IRQ_MASK_ERROR_WUP 0x18U /** RW Mask Error and Wake-up Interrupt Register */
#define ST25R3916_REG_IRQ_MASK_TARGET 0x19U /** RW Mask 3916 Target Interrupt Register */
#define ST25R3916_REG_IRQ_MAIN 0x1AU /** R Main Interrupt Register */
#define ST25R3916_REG_IRQ_TIMER_NFC 0x1BU /** R Timer and NFC Interrupt Register */
#define ST25R3916_REG_IRQ_ERROR_WUP 0x1CU /** R Error and Wake-up Interrupt Register */
#define ST25R3916_REG_IRQ_TARGET 0x1DU /*!< R ST25R3916 Target Interrupt Register */
#define ST25R3916_REG_FIFO_STATUS1 0x1EU /** R FIFO Status Register 1 */
#define ST25R3916_REG_FIFO_STATUS2 0x1FU /** R FIFO Status Register 2 */
#define ST25R3916_REG_COLLISION_STATUS 0x20U /** R Collision Display Register */
#define ST25R3916_REG_PASSIVE_TARGET_STATUS 0x21U /** R Passive target state status */
/* Definition of number of transmitted bytes */
#define ST25R3916_REG_NUM_TX_BYTES1 \
0x22U /*!< RW Number of Transmitted Bytes Register 1 */
#define ST25R3916_REG_NUM_TX_BYTES2 \
0x23U /*!< RW Number of Transmitted Bytes Register 2 */
/** Definition of number of transmitted bytes */
#define ST25R3916_REG_NUM_TX_BYTES1 0x22U /** RW Number of Transmitted Bytes Register 1 */
#define ST25R3916_REG_NUM_TX_BYTES2 0x23U /** RW Number of Transmitted Bytes Register 2 */
/* NFCIP Bit Rate Display Register */
#define ST25R3916_REG_NFCIP1_BIT_RATE \
0x24U /*!< R NFCIP Bit Rate Detection Display Register */
/** NFCIP Bit Rate Display Register */
#define ST25R3916_REG_NFCIP1_BIT_RATE 0x24U /** R NFCIP Bit Rate Detection Display Register */
/* A/D Converter Output Register */
#define ST25R3916_REG_AD_RESULT 0x25U /*!< R A/D Converter Output Register */
/** A/D Converter Output Register */
#define ST25R3916_REG_AD_RESULT 0x25U /** R A/D Converter Output Register */
/* Antenna tuning registers */
#define ST25R3916_REG_ANT_TUNE_A 0x26U /*!< RW Antenna Tuning Control (AAT-A) Register 1 */
#define ST25R3916_REG_ANT_TUNE_B 0x27U /*!< RW Antenna Tuning Control (AAT-B) Register 2 */
/** Antenna tuning registers */
#define ST25R3916_REG_ANT_TUNE_A 0x26U /** RW Antenna Tuning Control (AAT-A) Register 1 */
#define ST25R3916_REG_ANT_TUNE_B 0x27U /** RW Antenna Tuning Control (AAT-B) Register 2 */
/* Antenna Driver and Modulation registers */
#define ST25R3916_REG_TX_DRIVER 0x28U /*!< RW TX driver register */
#define ST25R3916_REG_PT_MOD 0x29U /*!< RW PT modulation Register */
#define ST25R3916_REG_AUX_MOD \
(ST25R3916_SPACE_B | 0x28U) /*!< RW Aux Modulation setting Register */
/** Antenna Driver and Modulation registers */
#define ST25R3916_REG_TX_DRIVER 0x28U /** RW TX driver register */
#define ST25R3916_REG_PT_MOD 0x29U /** RW PT modulation Register */
#define ST25R3916_REG_AUX_MOD (ST25R3916_SPACE_B | 0x28U) /** RW Aux Modulation setting Register */
#define ST25R3916_REG_TX_DRIVER_TIMING \
(ST25R3916_SPACE_B | 0x29U) /*!< RW TX driver timing Register */
(ST25R3916_SPACE_B | 0x29U) /** RW TX driver timing Register */
#define ST25R3916_REG_RES_AM_MOD \
(ST25R3916_SPACE_B | 0x2AU) /*!< RW Resistive AM modulation register */
(ST25R3916_SPACE_B | 0x2AU) /** RW Resistive AM modulation register */
#define ST25R3916_REG_TX_DRIVER_STATUS \
(ST25R3916_SPACE_B | 0x2BU) /*!< R TX driver timing readout Register */
(ST25R3916_SPACE_B | 0x2BU) /** R TX driver timing readout Register */
/* External Field Detector Threshold Registers */
/** External Field Detector Threshold Registers */
#define ST25R3916_REG_FIELD_THRESHOLD_ACTV \
0x2AU /*!< RW External Field Detector Activation Threshold Reg */
0x2AU /** RW External Field Detector Activation Threshold Reg */
#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV \
0x2BU /*!< RW External Field Detector Deactivation Threshold Reg*/
0x2BU /** RW External Field Detector Deactivation Threshold Reg */
/* Regulator registers */
#define ST25R3916_REG_REGULATOR_CONTROL \
0x2CU /*!< RW Regulated Voltage Control Register */
/** Regulator registers */
#define ST25R3916_REG_REGULATOR_CONTROL 0x2CU /** RW Regulated Voltage Control Register */
#define ST25R3916_REG_REGULATOR_RESULT \
(ST25R3916_SPACE_B | 0x2CU) /*!< R Regulator Display Register */
(ST25R3916_SPACE_B | 0x2CU) /** R Regulator Display Register */
/* Receiver State Display Register */
#define ST25R3916_REG_RSSI_RESULT \
0x2DU /*!< R RSSI Display Register */
#define ST25R3916_REG_GAIN_RED_STATE \
0x2EU /*!< R Gain Reduction State Register */
#define ST25R3916_REG_CAP_SENSOR_CONTROL \
0x2FU /*!< RW Capacitive Sensor Control Register */
#define ST25R3916_REG_CAP_SENSOR_RESULT \
0x30U /*!< R Capacitive Sensor Display Register */
#define ST25R3916_REG_AUX_DISPLAY \
0x31U /*!< R Auxiliary Display Register */
/** Receiver State Display Register */
#define ST25R3916_REG_RSSI_RESULT 0x2DU /** R RSSI Display Register */
#define ST25R3916_REG_GAIN_RED_STATE 0x2EU /** R Gain Reduction State Register */
#define ST25R3916_REG_CAP_SENSOR_CONTROL 0x2FU /** RW Capacitive Sensor Control Register */
#define ST25R3916_REG_CAP_SENSOR_RESULT 0x30U /** R Capacitive Sensor Display Register */
#define ST25R3916_REG_AUX_DISPLAY 0x31U /** R Auxiliary Display Register */
/* Over/Undershoot Protection Configuration Registers */
/** Over/Undershoot Protection Configuration Registers */
#define ST25R3916_REG_OVERSHOOT_CONF1 \
(ST25R3916_SPACE_B | 0x30U) /*!< RW Overshoot Protection Configuration Register 1 */
(ST25R3916_SPACE_B | 0x30U) /** RW Overshoot Protection Configuration Register 1 */
#define ST25R3916_REG_OVERSHOOT_CONF2 \
(ST25R3916_SPACE_B | 0x31U) /*!< RW Overshoot Protection Configuration Register 2 */
(ST25R3916_SPACE_B | 0x31U) /** RW Overshoot Protection Configuration Register 2 */
#define ST25R3916_REG_UNDERSHOOT_CONF1 \
(ST25R3916_SPACE_B | 0x32U) /*!< RW Undershoot Protection Configuration Register 1 */
(ST25R3916_SPACE_B | 0x32U) /** RW Undershoot Protection Configuration Register 1 */
#define ST25R3916_REG_UNDERSHOOT_CONF2 \
(ST25R3916_SPACE_B | 0x33U) /*!< RW Undershoot Protection Configuration Register 2 */
(ST25R3916_SPACE_B | 0x33U) /** RW Undershoot Protection Configuration Register 2 */
/* Detection of card presence */
#define ST25R3916_REG_WUP_TIMER_CONTROL \
0x32U /*!< RW Wake-up Timer Control Register */
/** Detection of card presence */
#define ST25R3916_REG_WUP_TIMER_CONTROL 0x32U /** RW Wake-up Timer Control Register */
#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF \
0x33U /*!< RW Amplitude Measurement Configuration Register */
0x33U /** RW Amplitude Measurement Configuration Register */
#define ST25R3916_REG_AMPLITUDE_MEASURE_REF \
0x34U /*!< RW Amplitude Measurement Reference Register */
0x34U /** RW Amplitude Measurement Reference Register */
#define ST25R3916_REG_AMPLITUDE_MEASURE_AA_RESULT \
0x35U /*!< R Amplitude Measurement Auto Averaging Display Reg */
0x35U /** R Amplitude Measurement Auto Averaging Display Reg */
#define ST25R3916_REG_AMPLITUDE_MEASURE_RESULT \
0x36U /*!< R Amplitude Measurement Display Register */
#define ST25R3916_REG_PHASE_MEASURE_CONF \
0x37U /*!< RW Phase Measurement Configuration Register */
#define ST25R3916_REG_PHASE_MEASURE_REF \
0x38U /*!< RW Phase Measurement Reference Register */
0x36U /** R Amplitude Measurement Display Register */
#define ST25R3916_REG_PHASE_MEASURE_CONF 0x37U /** RW Phase Measurement Configuration Register */
#define ST25R3916_REG_PHASE_MEASURE_REF 0x38U /** RW Phase Measurement Reference Register */
#define ST25R3916_REG_PHASE_MEASURE_AA_RESULT \
0x39U /*!< R Phase Measurement Auto Averaging Display Register */
#define ST25R3916_REG_PHASE_MEASURE_RESULT \
0x3AU /*!< R Phase Measurement Display Register */
0x39U /** R Phase Measurement Auto Averaging Display */
#define ST25R3916_REG_PHASE_MEASURE_RESULT 0x3AU /** R Phase Measurement Display Register */
#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF \
0x3BU /*!< RW Capacitance Measurement Configuration Register */
0x3BU /** RW Capacitance Measurement Configuration Register */
#define ST25R3916_REG_CAPACITANCE_MEASURE_REF \
0x3CU /*!< RW Capacitance Measurement Reference Register */
0x3CU /** RW Capacitance Measurement Reference Register */
#define ST25R3916_REG_CAPACITANCE_MEASURE_AA_RESULT \
0x3DU /*!< R Capacitance Measurement Auto Averaging Display Reg*/
0x3DU /** R Capacitance Measurement Auto Averaging Display Reg */
#define ST25R3916_REG_CAPACITANCE_MEASURE_RESULT \
0x3EU /*!< R Capacitance Measurement Display Register */
0x3EU /** R Capacitance Measurement Display Register */
/* IC identity */
#define ST25R3916_REG_IC_IDENTITY \
0x3FU /*!< R Chip Id: 0 for old silicon, v2 silicon: 0x09 */
/** IC identity */
#define ST25R3916_REG_IC_IDENTITY 0x3FU /** R Chip Id: 0 for old silicon, v2 silicon: 0x09 */
/*! Register bit definitions \cond DOXYGEN_SUPRESS */
/** Register bit definitions */
#define ST25R3916_REG_IO_CONF1_single (1U << 7)
#define ST25R3916_REG_IO_CONF1_rfo2 (1U << 6)
@@ -1021,364 +961,184 @@
#define ST25R3916_REG_IC_IDENTITY_ic_rev_mask (7U << 0)
#define ST25R3916_REG_IC_IDENTITY_ic_rev_shift (0U)
/*! \endcond DOXYGEN_SUPRESS */
/*
******************************************************************************
* GLOBAL FUNCTION PROTOTYPES
******************************************************************************
*/
/*!
*****************************************************************************
* \brief Returns the content of a register within the ST25R3916
/** Read register
*
* This function is used to read out the content of ST25R3916 registers.
*
* \param[in] reg: Address of register to read.
* \param[out] val: Returned value.
*
* \return ERR_NONE : Operation successful
* \return ERR_PARAM : Invalid parameter
* \return ERR_SEND : Transmission error or acknowledge not received
*****************************************************************************
* @param handle - pointer t FuriHalSpiBusHandle instance
* @param reg - register address
* @param val - pointer to the variable to store the read value
*/
ReturnCode st25r3916ReadRegister(uint8_t reg, uint8_t* val);
void st25r3916_read_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* val);
/*!
*****************************************************************************
* \brief Reads from multiple ST25R3916 registers
/** Read multiple registers
*
* This function is used to read from multiple registers using the
* auto-increment feature. That is, after each read the address pointer
* inside the ST25R3916 gets incremented automatically.
*
* \param[in] reg: Address of the first register to read from.
* \param[in] values: pointer to a buffer where the result shall be written to.
* \param[in] length: Number of registers to be read out.
*
* \return ERR_NONE : Operation successful
* \return ERR_PARAM : Invalid parameter
* \return ERR_SEND : Transmission error or acknowledge not received
*****************************************************************************
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param reg_start - start register address
* @param values - pointer to the buffer to store the read values
* @param length - number of registers to read
*/
ReturnCode st25r3916ReadMultipleRegisters(uint8_t reg, uint8_t* values, uint8_t length);
void st25r3916_read_burst_regs(
FuriHalSpiBusHandle* handle,
uint8_t reg_start,
uint8_t* values,
uint8_t length);
/*!
*****************************************************************************
* \brief Writes a given value to a register within the ST25R3916
/** Write register
*
* This function is used to write \a val to address \a reg within the ST25R3916.
*
* \param[in] reg: Address of the register to write.
* \param[in] val: Value to be written.
*
* \return ERR_NONE : Operation successful
* \return ERR_PARAM : Invalid parameter
* \return ERR_SEND : Transmission error or acknowledge not received
*****************************************************************************
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param reg - register address
* @param val - value to write
*/
ReturnCode st25r3916WriteRegister(uint8_t reg, uint8_t val);
void st25r3916_write_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t val);
/*!
*****************************************************************************
* \brief Writes multiple values to ST25R3916 registers
/** Write multiple registers
*
* This function is used to write multiple values to the ST25R3916 using the
* auto-increment feature. That is, after each write the address pointer
* inside the ST25R3916 gets incremented automatically.
*
* \param[in] reg: Address of the first register to write.
* \param[in] values: pointer to a buffer containing the values to be written.
* \param[in] length: Number of values to be written.
*
* \return ERR_NONE : Operation successful
* \return ERR_PARAM : Invalid parameter
* \return ERR_SEND : Transmission error or acknowledge not received
*****************************************************************************
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param reg_start - start register address
* @param values - pointer to buffer to write
* @param length - number of registers to write
*/
ReturnCode st25r3916WriteMultipleRegisters(uint8_t reg, const uint8_t* values, uint8_t length);
void st25r3916_write_burst_regs(
FuriHalSpiBusHandle* handle,
uint8_t reg_start,
const uint8_t* values,
uint8_t length);
/*!
*****************************************************************************
* \brief Writes values to ST25R3916 FIFO
/** Write fifo register
*
* This function needs to be called in order to write to the ST25R3916 FIFO.
*
* \param[in] values: pointer to a buffer containing the values to be written
* to the FIFO.
* \param[in] length: Number of values to be written.
*
* \return ERR_NONE : Operation successful
* \return ERR_PARAM : Invalid parameter
* \return ERR_SEND : Transmission error or acknowledge not received
*****************************************************************************
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param buff - buffer to write to FIFO
* @param length - number of bytes to write
*/
ReturnCode st25r3916WriteFifo(const uint8_t* values, uint16_t length);
void st25r3916_reg_write_fifo(FuriHalSpiBusHandle* handle, const uint8_t* buff, size_t length);
/*!
*****************************************************************************
* \brief Read values from ST25R3916 FIFO
/** Read fifo register
*
* This function needs to be called in order to read from ST25R3916 FIFO.
*
* \param[out] buf: pointer to a buffer where the FIFO content shall be
* written to.
* \param[in] length: Number of bytes to read.
*
* \note: This function doesn't check whether \a length is really the
* number of available bytes in FIFO
*
* \return ERR_NONE : Operation successful
* \return ERR_PARAM : Invalid parameter
* \return ERR_SEND : Transmission error or acknowledge not received
*****************************************************************************
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param buff - buffer to store the read values
* @param length - number of bytes to read
*/
ReturnCode st25r3916ReadFifo(uint8_t* buf, uint16_t length);
void st25r3916_reg_read_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, size_t length);
/*!
*****************************************************************************
* \brief Writes values to ST25R3916 PTM
/** Write PTA memory register
*
* Accesses to the begging of ST25R3916 Passive Target Memory (PTM A Config)
* and writes the given values
*
* \param[in] values: pointer to a buffer containing the values to be written
* to the Passive Target Memory.
* \param[in] length: Number of values to be written.
*
* \return ERR_NONE : Operation successful
* \return ERR_PARAM : Invalid parameter
* \return ERR_SEND : Transmission error or acknowledge not received
*****************************************************************************
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param values - pointer to buffer to write
* @param length - number of bytes to write
*/
ReturnCode st25r3916WritePTMem(const uint8_t* values, uint16_t length);
void st25r3916_write_pta_mem(FuriHalSpiBusHandle* handle, const uint8_t* values, size_t length);
/*!
*****************************************************************************
* \brief Reads the ST25R3916 PTM
/** Read PTA memory register
*
* Accesses to the begging of ST25R3916 Passive Target Memory (PTM A Config)
* and reads the memory for the given length
*
* \param[out] values: pointer to a buffer where the PTM content shall be
* written to.
* \param[in] length: Number of bytes to read.
*
* \return ERR_NONE : Operation successful
* \return ERR_PARAM : Invalid parameter
* \return ERR_SEND : Transmission error or acknowledge not received
*****************************************************************************
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param values - buffer to store the read values
* @param length - number of bytes to read
*/
ReturnCode st25r3916ReadPTMem(uint8_t* values, uint16_t length);
void st25r3916_read_pta_mem(FuriHalSpiBusHandle* handle, uint8_t* values, size_t length);
/*!
*****************************************************************************
* \brief Writes values to ST25R3916 PTM F config
/** Write PTF memory register
*
* Accesses ST25R3916 Passive Target Memory F config and writes the given values
*
* \param[in] values: pointer to a buffer containing the values to be written
* to the Passive Target Memory
* \param[in] length: Number of values to be written.
*
* \return ERR_NONE : Operation successful
* \return ERR_PARAM : Invalid parameter
* \return ERR_SEND : Transmission error or acknowledge not received
*****************************************************************************
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param values - pointer to buffer to write
* @param length - number of bytes to write
*/
ReturnCode st25r3916WritePTMemF(const uint8_t* values, uint16_t length);
void st25r3916_write_ptf_mem(FuriHalSpiBusHandle* handle, const uint8_t* values, size_t length);
/*!
*****************************************************************************
* \brief Writes values to ST25R3916 PTM TSN Data
/** Read PTTSN memory register
*
* Accesses ST25R3916 Passive Target Memory TSN data and writes the given values
*
* \param[in] values: pointer to a buffer containing the values to be written
* to the Passive Target Memory.
* \param[in] length: Number of values to be written.
*
* \return ERR_NONE : Operation successful
* \return ERR_PARAM : Invalid parameter
* \return ERR_SEND : Transmission error or acknowledge not received
*****************************************************************************
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param values - pointer to buffer to write
* @param length - number of bytes to write
*/
ReturnCode st25r3916WritePTMemTSN(const uint8_t* values, uint16_t length);
void st25r3916_write_pttsn_mem(FuriHalSpiBusHandle* handle, uint8_t* values, size_t length);
/*!
*****************************************************************************
* \brief Execute a direct command
/** Send Direct command
*
* This function is used to start so-called direct command. These commands
* are implemented inside the chip and each command has unique code (see
* datasheet).
*
* \param[in] cmd : code of the direct command to be executed.
*
* \return ERR_NONE : Operation successful
* \return ERR_PARAM : Invalid parameter
* \return ERR_SEND : Transmission error or acknowledge not received
*****************************************************************************
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param cmd - direct command
*/
ReturnCode st25r3916ExecuteCommand(uint8_t cmd);
void st25r3916_direct_cmd(FuriHalSpiBusHandle* handle, uint8_t cmd);
/*!
*****************************************************************************
* \brief Read a test register within the ST25R3916
*
* This function is used to read the content of test address \a reg within the ST25R3916
*
* \param[in] reg: Address of the register to read
* \param[out] val: Returned read value
*
* \return ERR_NONE : Operation successful
* \return ERR_PARAM : Invalid parameter
* \return ERR_SEND : Transmission error or acknowledge not received
*****************************************************************************
/** Read test register
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param reg - register address
* @param val - pointer to the variable to store the read value
*/
ReturnCode st25r3916ReadTestRegister(uint8_t reg, uint8_t* val);
void st25r3916_read_test_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* val);
/*!
*****************************************************************************
* \brief Writes a given value to a test register within the ST25R3916
/** Write test register
*
* This function is used to write \a val to test address \a reg within the ST25R3916
*
* \param[in] reg: Address of the register to write
* \param[in] val: Value to be written
*
* \return ERR_NONE : Operation successful
* \return ERR_PARAM : Invalid parameter
* \return ERR_SEND : Transmission error or acknowledge not received
*****************************************************************************
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param reg - register address
* @param val - value to write
*/
ReturnCode st25r3916WriteTestRegister(uint8_t reg, uint8_t val);
void st25r3916_write_test_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t val);
/*!
*****************************************************************************
* \brief Cleart bits on Register
/** Clear register bits
*
* This function clears the given bitmask on the register
*
* \param[in] reg: Address of the register clear
* \param[in] clr_mask: Bitmask of bit to be cleared
*
* \return ERR_NONE : Operation successful
* \return ERR_PARAM : Invalid parameter
* \return ERR_SEND : Transmission error or acknowledge not received
*****************************************************************************
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param reg - register address
* @param clr_mask - bit mask to clear
*/
ReturnCode st25r3916ClrRegisterBits(uint8_t reg, uint8_t clr_mask);
void st25r3916_clear_reg_bits(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t clr_mask);
/*!
*****************************************************************************
* \brief Set bits on Register
/** Set register bits
*
* This function sets the given bitmask on the register
*
* \param[in] reg: Address of the register clear
* \param[in] set_mask: Bitmask of bit to be cleared
*
* \return ERR_NONE : Operation successful
* \return ERR_PARAM : Invalid parameter
* \return ERR_SEND : Transmission error or acknowledge not received
*****************************************************************************
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param reg - register address
* @param set_mask - bit mask to set
*/
ReturnCode st25r3916SetRegisterBits(uint8_t reg, uint8_t set_mask);
void st25r3916_set_reg_bits(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t set_mask);
/*!
*****************************************************************************
* \brief Changes the given bits on a ST25R3916 register
/** Change register bits
*
* This function is used if only a particular bits should be changed within
* an ST25R3916 register.
*
* \param[in] reg: Address of the register to change.
* \param[in] valueMask: bitmask of bits to be changed
* \param[in] value: the bits to be written on the enabled valueMask bits
*
* \return ERR_NONE : Operation successful
* \return ERR_PARAM : Invalid parameter
* \return ERR_SEND : Transmission error or acknowledge not received
*****************************************************************************
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param reg - register address
* @param mask - bit mask to change
* @param value - new register value to write
*/
ReturnCode st25r3916ChangeRegisterBits(uint8_t reg, uint8_t valueMask, uint8_t value);
void st25r3916_change_reg_bits(
FuriHalSpiBusHandle* handle,
uint8_t reg,
uint8_t mask,
uint8_t value);
/*!
*****************************************************************************
* \brief Modifies a value within a ST25R3916 register
/** Modify register
*
* This function is used if only a particular bits should be changed within
* an ST25R3916 register.
*
* \param[in] reg: Address of the register to write.
* \param[in] clr_mask: bitmask of bits to be cleared to 0.
* \param[in] set_mask: bitmask of bits to be set to 1.
*
* \return ERR_NONE : Operation successful
* \return ERR_PARAM : Invalid parameter
* \return ERR_SEND : Transmission error or acknowledge not received
*****************************************************************************
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param reg - register address
* @param clr_mask - bit mask to clear
* @param set_mask - bit mask to set
*/
ReturnCode st25r3916ModifyRegister(uint8_t reg, uint8_t clr_mask, uint8_t set_mask);
void st25r3916_modify_reg(
FuriHalSpiBusHandle* handle,
uint8_t reg,
uint8_t clr_mask,
uint8_t set_mask);
/*!
*****************************************************************************
* \brief Changes the given bits on a ST25R3916 Test register
/** Change test register bits
*
* This function is used if only a particular bits should be changed within
* an ST25R3916 register.
*
* \param[in] reg: Address of the Test register to change.
* \param[in] valueMask: bitmask of bits to be changed
* \param[in] value: the bits to be written on the enabled valueMask bits
*
* \return ERR_NONE : Operation successful
* \return ERR_PARAM : Invalid parameter
* \return ERR_SEND : Transmission error or acknowledge not received
*****************************************************************************
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param reg - register address
* @param mask - bit mask to change
* @param value - new register value to write
*/
ReturnCode st25r3916ChangeTestRegisterBits(uint8_t reg, uint8_t valueMask, uint8_t value);
void st25r3916_change_test_reg_bits(
FuriHalSpiBusHandle* handle,
uint8_t reg,
uint8_t mask,
uint8_t value);
/*!
*****************************************************************************
* \brief Checks if register contains a expected value
/** Check register
*
* This function checks if the given reg contains a value that once masked
* equals the expected value
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param reg - register address
* @param mask - bit mask to check
* @param val - expected register value
*
* \param reg : the register to check the value
* \param mask : the mask apply on register value
* \param val : expected value to be compared to
*
* \return true when reg contains the expected value | false otherwise
* @return true if register value matches the expected value, false otherwise
*/
bool st25r3916CheckReg(uint8_t reg, uint8_t mask, uint8_t val);
bool st25r3916_check_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t mask, uint8_t val);
/*!
*****************************************************************************
* \brief Check if register ID is valid
*
* Checks if the given register ID a valid ST25R3916 register
*
* \param[in] reg: Address of register to check
*
* \return true if is a valid register ID
* \return false otherwise
*
*****************************************************************************
*/
bool st25r3916IsRegValid(uint8_t reg);
#endif /* ST25R3916_COM_H */
/**
* @}
*
* @}
*
* @}
*
* @}
*/
#ifdef __cplusplus
}
#endif
+3
View File
@@ -15,6 +15,9 @@ env.Append(
],
SDK_HEADERS=[
File("micro-ecc/uECC.h"),
File("nanopb/pb.h"),
File("nanopb/pb_decode.h"),
File("nanopb/pb_encode.h"),
],
)
+40 -7
View File
@@ -5,20 +5,53 @@ env.Append(
"#/lib/nfc",
],
SDK_HEADERS=[
# Main
File("nfc.h"),
File("nfc_device.h"),
File("nfc_worker.h"),
File("nfc_types.h"),
File("helpers/mfkey32.h"),
File("parsers/nfc_supported_card.h"),
File("helpers/nfc_generators.h"),
File("protocols/nfc_util.h"),
File("nfc_listener.h"),
File("nfc_poller.h"),
File("nfc_scanner.h"),
# Protocols
File("protocols/iso14443_3a/iso14443_3a.h"),
File("protocols/iso14443_3b/iso14443_3b.h"),
File("protocols/iso14443_4a/iso14443_4a.h"),
File("protocols/iso14443_4b/iso14443_4b.h"),
File("protocols/mf_ultralight/mf_ultralight.h"),
File("protocols/mf_classic/mf_classic.h"),
File("protocols/mf_desfire/mf_desfire.h"),
File("protocols/slix/slix.h"),
File("protocols/st25tb/st25tb.h"),
# Pollers
File("protocols/iso14443_3a/iso14443_3a_poller.h"),
File("protocols/iso14443_3b/iso14443_3b_poller.h"),
File("protocols/iso14443_4a/iso14443_4a_poller.h"),
File("protocols/iso14443_4b/iso14443_4b_poller.h"),
File("protocols/mf_ultralight/mf_ultralight_poller.h"),
File("protocols/mf_classic/mf_classic_poller.h"),
File("protocols/mf_desfire/mf_desfire_poller.h"),
File("protocols/st25tb/st25tb_poller.h"),
# Listeners
File("protocols/iso14443_3a/iso14443_3a_listener.h"),
File("protocols/iso14443_4a/iso14443_4a_listener.h"),
File("protocols/mf_ultralight/mf_ultralight_listener.h"),
File("protocols/mf_classic/mf_classic_listener.h"),
# Sync API
File("protocols/iso14443_3a/iso14443_3a_poller_sync_api.h"),
File("protocols/mf_ultralight/mf_ultralight_poller_sync_api.h"),
File("protocols/mf_classic/mf_classic_poller_sync_api.h"),
# Misc
File("helpers/nfc_util.h"),
File("helpers/iso14443_crc.h"),
File("helpers/iso13239_crc.h"),
File("helpers/nfc_data_generator.h"),
File("helpers/nfc_dict.h"),
],
)
libenv = env.Clone(FW_LIB_NAME="nfc")
libenv.ApplyLibFlags()
sources = libenv.GlobRecursive("*.c*")
sources = libenv.GlobRecursive("*.c*", exclude="deprecated/*c")
lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources)
libenv.Install("${LIB_DIST_DIR}", lib)
+52
View File
@@ -0,0 +1,52 @@
#include "felica_crc.h"
#include <furi/furi.h>
#define FELICA_CRC_POLY (0x1021U) // Polynomial: x^16 + x^12 + x^5 + 1
#define FELICA_CRC_INIT (0x0000U)
uint16_t felica_crc_calculate(const uint8_t* data, size_t length) {
uint16_t crc = FELICA_CRC_INIT;
for(size_t i = 0; i < length; i++) {
crc ^= ((uint16_t)data[i] << 8);
for(size_t j = 0; j < 8; j++) {
if(crc & 0x8000) {
crc <<= 1;
crc ^= FELICA_CRC_POLY;
} else {
crc <<= 1;
}
}
}
return (crc << 8) | (crc >> 8);
}
void felica_crc_append(BitBuffer* buf) {
const uint8_t* data = bit_buffer_get_data(buf);
const size_t data_size = bit_buffer_get_size_bytes(buf);
const uint16_t crc = felica_crc_calculate(data, data_size);
bit_buffer_append_bytes(buf, (const uint8_t*)&crc, FELICA_CRC_SIZE);
}
bool felica_crc_check(const BitBuffer* buf) {
const size_t data_size = bit_buffer_get_size_bytes(buf);
if(data_size <= FELICA_CRC_SIZE) return false;
uint16_t crc_received;
bit_buffer_write_bytes_mid(buf, &crc_received, data_size - FELICA_CRC_SIZE, FELICA_CRC_SIZE);
const uint8_t* data = bit_buffer_get_data(buf);
const uint16_t crc_calc = felica_crc_calculate(data, data_size - FELICA_CRC_SIZE);
return (crc_calc == crc_received);
}
void felica_crc_trim(BitBuffer* buf) {
const size_t data_size = bit_buffer_get_size_bytes(buf);
furi_assert(data_size > FELICA_CRC_SIZE);
bit_buffer_set_size_bytes(buf, data_size - FELICA_CRC_SIZE);
}
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include "bit_buffer.h"
#ifdef __cplusplus
extern "C" {
#endif
#define FELICA_CRC_SIZE sizeof(uint16_t)
void felica_crc_append(BitBuffer* buf);
bool felica_crc_check(const BitBuffer* buf);
void felica_crc_trim(BitBuffer* buf);
#ifdef __cplusplus
}
#endif
+62
View File
@@ -0,0 +1,62 @@
#include "iso13239_crc.h"
#include <core/check.h>
#define ISO13239_CRC_INIT_DEFAULT (0xFFFFU)
#define ISO13239_CRC_INIT_PICOPASS (0xE012U)
#define ISO13239_CRC_POLY (0x8408U)
static uint16_t
iso13239_crc_calculate(Iso13239CrcType type, const uint8_t* data, size_t data_size) {
uint16_t crc;
if(type == Iso13239CrcTypeDefault) {
crc = ISO13239_CRC_INIT_DEFAULT;
} else if(type == Iso13239CrcTypePicopass) {
crc = ISO13239_CRC_INIT_PICOPASS;
} else {
furi_crash("Wrong ISO13239 CRC type");
}
for(size_t i = 0; i < data_size; ++i) {
crc ^= (uint16_t)data[i];
for(size_t j = 0; j < 8; ++j) {
if(crc & 1U) {
crc = (crc >> 1) ^ ISO13239_CRC_POLY;
} else {
crc >>= 1;
}
}
}
return type == Iso13239CrcTypePicopass ? crc : ~crc;
}
void iso13239_crc_append(Iso13239CrcType type, BitBuffer* buf) {
const uint8_t* data = bit_buffer_get_data(buf);
const size_t data_size = bit_buffer_get_size_bytes(buf);
const uint16_t crc = iso13239_crc_calculate(type, data, data_size);
bit_buffer_append_bytes(buf, (const uint8_t*)&crc, ISO13239_CRC_SIZE);
}
bool iso13239_crc_check(Iso13239CrcType type, const BitBuffer* buf) {
const size_t data_size = bit_buffer_get_size_bytes(buf);
if(data_size <= ISO13239_CRC_SIZE) return false;
uint16_t crc_received;
bit_buffer_write_bytes_mid(
buf, &crc_received, data_size - ISO13239_CRC_SIZE, ISO13239_CRC_SIZE);
const uint8_t* data = bit_buffer_get_data(buf);
const uint16_t crc_calc = iso13239_crc_calculate(type, data, data_size - ISO13239_CRC_SIZE);
return (crc_calc == crc_received);
}
void iso13239_crc_trim(BitBuffer* buf) {
const size_t data_size = bit_buffer_get_size_bytes(buf);
furi_assert(data_size > ISO13239_CRC_SIZE);
bit_buffer_set_size_bytes(buf, data_size - ISO13239_CRC_SIZE);
}
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <toolbox/bit_buffer.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ISO13239_CRC_SIZE sizeof(uint16_t)
typedef enum {
Iso13239CrcTypeDefault,
Iso13239CrcTypePicopass,
} Iso13239CrcType;
void iso13239_crc_append(Iso13239CrcType type, BitBuffer* buf);
bool iso13239_crc_check(Iso13239CrcType type, const BitBuffer* buf);
void iso13239_crc_trim(BitBuffer* buf);
#ifdef __cplusplus
}
#endif
+64
View File
@@ -0,0 +1,64 @@
#include "iso14443_4_layer.h"
#include <furi.h>
#define ISO14443_4_BLOCK_PCB (1U << 1)
#define ISO14443_4_BLOCK_PCB_I (0U)
#define ISO14443_4_BLOCK_PCB_R (5U << 5)
#define ISO14443_4_BLOCK_PCB_S (3U << 6)
struct Iso14443_4Layer {
uint8_t pcb;
uint8_t pcb_prev;
};
static inline void iso14443_4_layer_update_pcb(Iso14443_4Layer* instance) {
instance->pcb_prev = instance->pcb;
instance->pcb ^= (uint8_t)0x01;
}
Iso14443_4Layer* iso14443_4_layer_alloc() {
Iso14443_4Layer* instance = malloc(sizeof(Iso14443_4Layer));
iso14443_4_layer_reset(instance);
return instance;
}
void iso14443_4_layer_free(Iso14443_4Layer* instance) {
furi_assert(instance);
free(instance);
}
void iso14443_4_layer_reset(Iso14443_4Layer* instance) {
furi_assert(instance);
instance->pcb = ISO14443_4_BLOCK_PCB_I | ISO14443_4_BLOCK_PCB;
}
void iso14443_4_layer_encode_block(
Iso14443_4Layer* instance,
const BitBuffer* input_data,
BitBuffer* block_data) {
furi_assert(instance);
bit_buffer_append_byte(block_data, instance->pcb);
bit_buffer_append(block_data, input_data);
iso14443_4_layer_update_pcb(instance);
}
bool iso14443_4_layer_decode_block(
Iso14443_4Layer* instance,
BitBuffer* output_data,
const BitBuffer* block_data) {
furi_assert(instance);
bool ret = false;
do {
if(!bit_buffer_starts_with_byte(block_data, instance->pcb_prev)) break;
bit_buffer_copy_right(output_data, block_data, 1);
ret = true;
} while(false);
return ret;
}
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include <toolbox/bit_buffer.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct Iso14443_4Layer Iso14443_4Layer;
Iso14443_4Layer* iso14443_4_layer_alloc();
void iso14443_4_layer_free(Iso14443_4Layer* instance);
void iso14443_4_layer_reset(Iso14443_4Layer* instance);
void iso14443_4_layer_encode_block(
Iso14443_4Layer* instance,
const BitBuffer* input_data,
BitBuffer* block_data);
bool iso14443_4_layer_decode_block(
Iso14443_4Layer* instance,
BitBuffer* output_data,
const BitBuffer* block_data);
#ifdef __cplusplus
}
#endif
+57
View File
@@ -0,0 +1,57 @@
#include "iso14443_crc.h"
#include <core/check.h>
#define ISO14443_3A_CRC_INIT (0x6363U)
#define ISO14443_3B_CRC_INIT (0xFFFFU)
static uint16_t
iso14443_crc_calculate(Iso14443CrcType type, const uint8_t* data, size_t data_size) {
uint16_t crc;
if(type == Iso14443CrcTypeA) {
crc = ISO14443_3A_CRC_INIT;
} else if(type == Iso14443CrcTypeB) {
crc = ISO14443_3B_CRC_INIT;
} else {
furi_crash("Wrong ISO14443 CRC type");
}
for(size_t i = 0; i < data_size; i++) {
uint8_t byte = data[i];
byte ^= (uint8_t)(crc & 0xff);
byte ^= byte << 4;
crc = (crc >> 8) ^ (((uint16_t)byte) << 8) ^ (((uint16_t)byte) << 3) ^ (byte >> 4);
}
return type == Iso14443CrcTypeA ? crc : ~crc;
}
void iso14443_crc_append(Iso14443CrcType type, BitBuffer* buf) {
const uint8_t* data = bit_buffer_get_data(buf);
const size_t data_size = bit_buffer_get_size_bytes(buf);
const uint16_t crc = iso14443_crc_calculate(type, data, data_size);
bit_buffer_append_bytes(buf, (const uint8_t*)&crc, ISO14443_CRC_SIZE);
}
bool iso14443_crc_check(Iso14443CrcType type, const BitBuffer* buf) {
const size_t data_size = bit_buffer_get_size_bytes(buf);
if(data_size <= ISO14443_CRC_SIZE) return false;
uint16_t crc_received;
bit_buffer_write_bytes_mid(
buf, &crc_received, data_size - ISO14443_CRC_SIZE, ISO14443_CRC_SIZE);
const uint8_t* data = bit_buffer_get_data(buf);
const uint16_t crc_calc = iso14443_crc_calculate(type, data, data_size - ISO14443_CRC_SIZE);
return (crc_calc == crc_received);
}
void iso14443_crc_trim(BitBuffer* buf) {
const size_t data_size = bit_buffer_get_size_bytes(buf);
furi_assert(data_size > ISO14443_CRC_SIZE);
bit_buffer_set_size_bytes(buf, data_size - ISO14443_CRC_SIZE);
}
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <toolbox/bit_buffer.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ISO14443_CRC_SIZE sizeof(uint16_t)
typedef enum {
Iso14443CrcTypeA,
Iso14443CrcTypeB,
} Iso14443CrcType;
void iso14443_crc_append(Iso14443CrcType type, BitBuffer* buf);
bool iso14443_crc_check(Iso14443CrcType type, const BitBuffer* buf);
void iso14443_crc_trim(BitBuffer* buf);
#ifdef __cplusplus
}
#endif
-349
View File
@@ -1,349 +0,0 @@
#include "mf_classic_dict.h"
#include <lib/toolbox/args.h>
#include <lib/flipper_format/flipper_format.h>
#define MF_CLASSIC_DICT_FLIPPER_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc")
#define MF_CLASSIC_DICT_USER_PATH EXT_PATH("nfc/assets/mf_classic_dict_user.nfc")
#define MF_CLASSIC_DICT_UNIT_TEST_PATH EXT_PATH("unit_tests/mf_classic_dict.nfc")
#define TAG "MfClassicDict"
#define NFC_MF_CLASSIC_KEY_LEN (13)
struct MfClassicDict {
Stream* stream;
uint32_t total_keys;
};
bool mf_classic_dict_check_presence(MfClassicDictType dict_type) {
Storage* storage = furi_record_open(RECORD_STORAGE);
bool dict_present = false;
if(dict_type == MfClassicDictTypeSystem) {
dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_FLIPPER_PATH, NULL) == FSE_OK;
} else if(dict_type == MfClassicDictTypeUser) {
dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_USER_PATH, NULL) == FSE_OK;
} else if(dict_type == MfClassicDictTypeUnitTest) {
dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_UNIT_TEST_PATH, NULL) ==
FSE_OK;
}
furi_record_close(RECORD_STORAGE);
return dict_present;
}
MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type) {
MfClassicDict* dict = malloc(sizeof(MfClassicDict));
Storage* storage = furi_record_open(RECORD_STORAGE);
dict->stream = buffered_file_stream_alloc(storage);
furi_record_close(RECORD_STORAGE);
bool dict_loaded = false;
do {
if(dict_type == MfClassicDictTypeSystem) {
if(!buffered_file_stream_open(
dict->stream,
MF_CLASSIC_DICT_FLIPPER_PATH,
FSAM_READ_WRITE,
FSOM_OPEN_EXISTING)) {
buffered_file_stream_close(dict->stream);
break;
}
} else if(dict_type == MfClassicDictTypeUser) {
if(!buffered_file_stream_open(
dict->stream, MF_CLASSIC_DICT_USER_PATH, FSAM_READ_WRITE, FSOM_OPEN_ALWAYS)) {
buffered_file_stream_close(dict->stream);
break;
}
} else if(dict_type == MfClassicDictTypeUnitTest) {
if(!buffered_file_stream_open(
dict->stream,
MF_CLASSIC_DICT_UNIT_TEST_PATH,
FSAM_READ_WRITE,
FSOM_OPEN_ALWAYS)) {
buffered_file_stream_close(dict->stream);
break;
}
}
// Check for new line ending
if(!stream_eof(dict->stream)) {
if(!stream_seek(dict->stream, -1, StreamOffsetFromEnd)) break;
uint8_t last_char = 0;
if(stream_read(dict->stream, &last_char, 1) != 1) break;
if(last_char != '\n') {
FURI_LOG_D(TAG, "Adding new line ending");
if(stream_write_char(dict->stream, '\n') != 1) break;
}
if(!stream_rewind(dict->stream)) break;
}
// Read total amount of keys
FuriString* next_line;
next_line = furi_string_alloc();
while(true) {
if(!stream_read_line(dict->stream, next_line)) {
FURI_LOG_T(TAG, "No keys left in dict");
break;
}
FURI_LOG_T(
TAG,
"Read line: %s, len: %zu",
furi_string_get_cstr(next_line),
furi_string_size(next_line));
if(furi_string_get_char(next_line, 0) == '#') continue;
if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue;
dict->total_keys++;
}
furi_string_free(next_line);
stream_rewind(dict->stream);
dict_loaded = true;
FURI_LOG_I(TAG, "Loaded dictionary with %lu keys", dict->total_keys);
} while(false);
if(!dict_loaded) {
buffered_file_stream_close(dict->stream);
free(dict);
dict = NULL;
}
return dict;
}
void mf_classic_dict_free(MfClassicDict* dict) {
furi_assert(dict);
furi_assert(dict->stream);
buffered_file_stream_close(dict->stream);
stream_free(dict->stream);
free(dict);
}
static void mf_classic_dict_int_to_str(uint8_t* key_int, FuriString* key_str) {
furi_string_reset(key_str);
for(size_t i = 0; i < 6; i++) {
furi_string_cat_printf(key_str, "%02X", key_int[i]);
}
}
static void mf_classic_dict_str_to_int(FuriString* key_str, uint64_t* key_int) {
uint8_t key_byte_tmp;
*key_int = 0ULL;
for(uint8_t i = 0; i < 12; i += 2) {
args_char_to_hex(
furi_string_get_char(key_str, i), furi_string_get_char(key_str, i + 1), &key_byte_tmp);
*key_int |= (uint64_t)key_byte_tmp << (8 * (5 - i / 2));
}
}
uint32_t mf_classic_dict_get_total_keys(MfClassicDict* dict) {
furi_assert(dict);
return dict->total_keys;
}
bool mf_classic_dict_rewind(MfClassicDict* dict) {
furi_assert(dict);
furi_assert(dict->stream);
return stream_rewind(dict->stream);
}
bool mf_classic_dict_get_next_key_str(MfClassicDict* dict, FuriString* key) {
furi_assert(dict);
furi_assert(dict->stream);
bool key_read = false;
furi_string_reset(key);
while(!key_read) {
if(!stream_read_line(dict->stream, key)) break;
if(furi_string_get_char(key, 0) == '#') continue;
if(furi_string_size(key) != NFC_MF_CLASSIC_KEY_LEN) continue;
furi_string_left(key, 12);
key_read = true;
}
return key_read;
}
bool mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key) {
furi_assert(dict);
furi_assert(dict->stream);
FuriString* temp_key;
temp_key = furi_string_alloc();
bool key_read = mf_classic_dict_get_next_key_str(dict, temp_key);
if(key_read) {
mf_classic_dict_str_to_int(temp_key, key);
}
furi_string_free(temp_key);
return key_read;
}
bool mf_classic_dict_is_key_present_str(MfClassicDict* dict, FuriString* key) {
furi_assert(dict);
furi_assert(dict->stream);
FuriString* next_line;
next_line = furi_string_alloc();
bool key_found = false;
stream_rewind(dict->stream);
while(!key_found) { //-V654
if(!stream_read_line(dict->stream, next_line)) break;
if(furi_string_get_char(next_line, 0) == '#') continue;
if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue;
furi_string_left(next_line, 12);
if(!furi_string_equal(key, next_line)) continue;
key_found = true;
}
furi_string_free(next_line);
return key_found;
}
bool mf_classic_dict_is_key_present(MfClassicDict* dict, uint8_t* key) {
FuriString* temp_key;
temp_key = furi_string_alloc();
mf_classic_dict_int_to_str(key, temp_key);
bool key_found = mf_classic_dict_is_key_present_str(dict, temp_key);
furi_string_free(temp_key);
return key_found;
}
bool mf_classic_dict_add_key_str(MfClassicDict* dict, FuriString* key) {
furi_assert(dict);
furi_assert(dict->stream);
furi_string_cat_printf(key, "\n");
bool key_added = false;
do {
if(!stream_seek(dict->stream, 0, StreamOffsetFromEnd)) break;
if(!stream_insert_string(dict->stream, key)) break;
dict->total_keys++;
key_added = true;
} while(false);
furi_string_left(key, 12);
return key_added;
}
bool mf_classic_dict_add_key(MfClassicDict* dict, uint8_t* key) {
furi_assert(dict);
furi_assert(dict->stream);
FuriString* temp_key;
temp_key = furi_string_alloc();
mf_classic_dict_int_to_str(key, temp_key);
bool key_added = mf_classic_dict_add_key_str(dict, temp_key);
furi_string_free(temp_key);
return key_added;
}
bool mf_classic_dict_get_key_at_index_str(MfClassicDict* dict, FuriString* key, uint32_t target) {
furi_assert(dict);
furi_assert(dict->stream);
FuriString* next_line;
uint32_t index = 0;
next_line = furi_string_alloc();
furi_string_reset(key);
bool key_found = false;
while(!key_found) {
if(!stream_read_line(dict->stream, next_line)) break;
if(furi_string_get_char(next_line, 0) == '#') continue;
if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue;
if(index++ != target) continue;
furi_string_set_n(key, next_line, 0, 12);
key_found = true;
}
furi_string_free(next_line);
return key_found;
}
bool mf_classic_dict_get_key_at_index(MfClassicDict* dict, uint64_t* key, uint32_t target) {
furi_assert(dict);
furi_assert(dict->stream);
FuriString* temp_key;
temp_key = furi_string_alloc();
bool key_found = mf_classic_dict_get_key_at_index_str(dict, temp_key, target);
if(key_found) {
mf_classic_dict_str_to_int(temp_key, key);
}
furi_string_free(temp_key);
return key_found;
}
bool mf_classic_dict_find_index_str(MfClassicDict* dict, FuriString* key, uint32_t* target) {
furi_assert(dict);
furi_assert(dict->stream);
FuriString* next_line;
next_line = furi_string_alloc();
bool key_found = false;
uint32_t index = 0;
stream_rewind(dict->stream);
while(!key_found) { //-V654
if(!stream_read_line(dict->stream, next_line)) break;
if(furi_string_get_char(next_line, 0) == '#') continue;
if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue;
furi_string_left(next_line, 12);
if(!furi_string_equal(key, next_line)) continue;
key_found = true;
*target = index;
}
furi_string_free(next_line);
return key_found;
}
bool mf_classic_dict_find_index(MfClassicDict* dict, uint8_t* key, uint32_t* target) {
furi_assert(dict);
furi_assert(dict->stream);
FuriString* temp_key;
temp_key = furi_string_alloc();
mf_classic_dict_int_to_str(key, temp_key);
bool key_found = mf_classic_dict_find_index_str(dict, temp_key, target);
furi_string_free(temp_key);
return key_found;
}
bool mf_classic_dict_delete_index(MfClassicDict* dict, uint32_t target) {
furi_assert(dict);
furi_assert(dict->stream);
FuriString* next_line;
next_line = furi_string_alloc();
uint32_t index = 0;
bool key_removed = false;
stream_rewind(dict->stream);
while(!key_removed) {
if(!stream_read_line(dict->stream, next_line)) break;
if(furi_string_get_char(next_line, 0) == '#') continue;
if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue;
if(index++ != target) continue;
stream_seek(dict->stream, -NFC_MF_CLASSIC_KEY_LEN, StreamOffsetFromCurrent);
if(!stream_delete(dict->stream, NFC_MF_CLASSIC_KEY_LEN)) break;
dict->total_keys--;
key_removed = true;
}
stream_rewind(dict->stream);
furi_string_free(next_line);
return key_removed;
}
-107
View File
@@ -1,107 +0,0 @@
#pragma once
#include <stdbool.h>
#include <storage/storage.h>
#include <lib/flipper_format/flipper_format.h>
#include <lib/toolbox/stream/file_stream.h>
#include <lib/toolbox/stream/buffered_file_stream.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
MfClassicDictTypeUser,
MfClassicDictTypeSystem,
MfClassicDictTypeUnitTest,
} MfClassicDictType;
typedef struct MfClassicDict MfClassicDict;
bool mf_classic_dict_check_presence(MfClassicDictType dict_type);
/** Allocate MfClassicDict instance
*
* @param[in] dict_type The dictionary type
*
* @return MfClassicDict instance
*/
MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type);
/** Free MfClassicDict instance
*
* @param dict MfClassicDict instance
*/
void mf_classic_dict_free(MfClassicDict* dict);
/** Get total keys count
*
* @param dict MfClassicDict instance
*
* @return total keys count
*/
uint32_t mf_classic_dict_get_total_keys(MfClassicDict* dict);
/** Rewind to the beginning
*
* @param dict MfClassicDict instance
*
* @return true on success
*/
bool mf_classic_dict_rewind(MfClassicDict* dict);
bool mf_classic_dict_is_key_present(MfClassicDict* dict, uint8_t* key);
bool mf_classic_dict_is_key_present_str(MfClassicDict* dict, FuriString* key);
bool mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key);
bool mf_classic_dict_get_next_key_str(MfClassicDict* dict, FuriString* key);
/** Get key at target offset as uint64_t
*
* @param dict MfClassicDict instance
* @param[out] key Pointer to the uint64_t key
* @param[in] target Target offset from current position
*
* @return true on success
*/
bool mf_classic_dict_get_key_at_index(MfClassicDict* dict, uint64_t* key, uint32_t target);
/** Get key at target offset as FuriString*
*
* @param dict MfClassicDict instance
* @param[out] key Found key destination buffer
* @param[in] target Target offset from current position
*
* @return true on success
*/
bool mf_classic_dict_get_key_at_index_str(MfClassicDict* dict, FuriString* key, uint32_t target);
bool mf_classic_dict_add_key(MfClassicDict* dict, uint8_t* key);
/** Add string representation of the key
*
* @param dict MfClassicDict instance
* @param[in] key String representation of the key
*
* @return true on success
*/
bool mf_classic_dict_add_key_str(MfClassicDict* dict, FuriString* key);
bool mf_classic_dict_find_index(MfClassicDict* dict, uint8_t* key, uint32_t* target);
bool mf_classic_dict_find_index_str(MfClassicDict* dict, FuriString* key, uint32_t* target);
/** Delete key at target offset
*
* @param dict MfClassicDict instance
* @param[in] target Target offset from current position
*
* @return true on success
*/
bool mf_classic_dict_delete_index(MfClassicDict* dict, uint32_t target);
#ifdef __cplusplus
}
#endif
-228
View File
@@ -1,228 +0,0 @@
#include "mfkey32.h"
#include <furi/furi.h>
#include <storage/storage.h>
#include <stream/stream.h>
#include <stream/buffered_file_stream.h>
#include <m-array.h>
#include <lib/nfc/protocols/mifare_classic.h>
#include <lib/nfc/protocols/nfc_util.h>
#define TAG "Mfkey32"
#define MFKEY32_LOGS_PATH EXT_PATH("nfc/.mfkey32.log")
typedef enum {
Mfkey32StateIdle,
Mfkey32StateAuthReceived,
Mfkey32StateAuthNtSent,
Mfkey32StateAuthArNrReceived,
} Mfkey32State;
typedef struct {
uint32_t cuid;
uint8_t sector;
MfClassicKey key;
uint32_t nt0;
uint32_t nr0;
uint32_t ar0;
uint32_t nt1;
uint32_t nr1;
uint32_t ar1;
} Mfkey32Params;
ARRAY_DEF(Mfkey32Params, Mfkey32Params, M_POD_OPLIST);
typedef struct {
uint8_t sector;
MfClassicKey key;
uint32_t nt;
uint32_t nr;
uint32_t ar;
} Mfkey32Nonce;
struct Mfkey32 {
Mfkey32State state;
Stream* file_stream;
Mfkey32Params_t params_arr;
Mfkey32Nonce nonce;
uint32_t cuid;
Mfkey32ParseDataCallback callback;
void* context;
};
Mfkey32* mfkey32_alloc(uint32_t cuid) {
Mfkey32* instance = malloc(sizeof(Mfkey32));
instance->cuid = cuid;
instance->state = Mfkey32StateIdle;
Storage* storage = furi_record_open(RECORD_STORAGE);
instance->file_stream = buffered_file_stream_alloc(storage);
if(!buffered_file_stream_open(
instance->file_stream, MFKEY32_LOGS_PATH, FSAM_WRITE, FSOM_OPEN_APPEND)) {
buffered_file_stream_close(instance->file_stream);
stream_free(instance->file_stream);
free(instance);
instance = NULL;
} else {
Mfkey32Params_init(instance->params_arr);
}
furi_record_close(RECORD_STORAGE);
return instance;
}
void mfkey32_free(Mfkey32* instance) {
furi_assert(instance != NULL);
Mfkey32Params_clear(instance->params_arr);
buffered_file_stream_close(instance->file_stream);
stream_free(instance->file_stream);
free(instance);
}
void mfkey32_set_callback(Mfkey32* instance, Mfkey32ParseDataCallback callback, void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
}
static bool mfkey32_write_params(Mfkey32* instance, Mfkey32Params* params) {
FuriString* str = furi_string_alloc_printf(
"Sec %d key %c cuid %08lx nt0 %08lx nr0 %08lx ar0 %08lx nt1 %08lx nr1 %08lx ar1 %08lx\n",
params->sector,
params->key == MfClassicKeyA ? 'A' : 'B',
params->cuid,
params->nt0,
params->nr0,
params->ar0,
params->nt1,
params->nr1,
params->ar1);
bool write_success = stream_write_string(instance->file_stream, str);
furi_string_free(str);
return write_success;
}
static void mfkey32_add_params(Mfkey32* instance) {
Mfkey32Nonce* nonce = &instance->nonce;
bool nonce_added = false;
// Search if we partially collected params
if(Mfkey32Params_size(instance->params_arr)) {
Mfkey32Params_it_t it;
for(Mfkey32Params_it(it, instance->params_arr); !Mfkey32Params_end_p(it);
Mfkey32Params_next(it)) {
Mfkey32Params* params = Mfkey32Params_ref(it);
if((params->sector == nonce->sector) && (params->key == nonce->key)) {
params->nt1 = nonce->nt;
params->nr1 = nonce->nr;
params->ar1 = nonce->ar;
nonce_added = true;
FURI_LOG_I(
TAG,
"Params for sector %d key %c collected",
params->sector,
params->key == MfClassicKeyA ? 'A' : 'B');
// Write on sd card
if(mfkey32_write_params(instance, params)) {
Mfkey32Params_remove(instance->params_arr, it);
if(instance->callback) {
instance->callback(Mfkey32EventParamCollected, instance->context);
}
}
}
}
}
if(!nonce_added) {
Mfkey32Params params = {
.sector = nonce->sector,
.key = nonce->key,
.cuid = instance->cuid,
.nt0 = nonce->nt,
.nr0 = nonce->nr,
.ar0 = nonce->ar,
};
Mfkey32Params_push_back(instance->params_arr, params);
}
}
void mfkey32_process_data(
Mfkey32* instance,
uint8_t* data,
uint16_t len,
bool reader_to_tag,
bool crc_dropped) {
furi_assert(instance);
furi_assert(data);
Mfkey32Nonce* nonce = &instance->nonce;
uint16_t data_len = len;
if((data_len > 3) && !crc_dropped) {
data_len -= 2;
}
bool data_processed = false;
if(instance->state == Mfkey32StateIdle) {
if(reader_to_tag) {
if((data[0] == 0x60) || (data[0] == 0x61)) {
nonce->key = data[0] == 0x60 ? MfClassicKeyA : MfClassicKeyB;
nonce->sector = mf_classic_get_sector_by_block(data[1]);
instance->state = Mfkey32StateAuthReceived;
data_processed = true;
}
}
} else if(instance->state == Mfkey32StateAuthReceived) {
if(!reader_to_tag) {
if(len == 4) {
nonce->nt = nfc_util_bytes2num(data, 4);
instance->state = Mfkey32StateAuthNtSent;
data_processed = true;
}
}
} else if(instance->state == Mfkey32StateAuthNtSent) {
if(reader_to_tag) {
if(len == 8) {
nonce->nr = nfc_util_bytes2num(data, 4);
nonce->ar = nfc_util_bytes2num(&data[4], 4);
mfkey32_add_params(instance);
instance->state = Mfkey32StateIdle;
}
}
}
if(!data_processed) {
instance->state = Mfkey32StateIdle;
}
}
uint16_t mfkey32_get_auth_sectors(FuriString* data_str) {
furi_assert(data_str);
uint16_t nonces_num = 0;
Storage* storage = furi_record_open(RECORD_STORAGE);
Stream* file_stream = buffered_file_stream_alloc(storage);
FuriString* temp_str;
temp_str = furi_string_alloc();
do {
if(!buffered_file_stream_open(
file_stream, MFKEY32_LOGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING))
break;
while(true) {
if(!stream_read_line(file_stream, temp_str)) break;
size_t uid_pos = furi_string_search(temp_str, "cuid");
furi_string_left(temp_str, uid_pos);
furi_string_push_back(temp_str, '\n');
furi_string_cat(data_str, temp_str);
nonces_num++;
}
} while(false);
buffered_file_stream_close(file_stream);
stream_free(file_stream);
furi_string_free(temp_str);
return nonces_num;
}
-34
View File
@@ -1,34 +0,0 @@
#pragma once
#include <lib/nfc/protocols/mifare_classic.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct Mfkey32 Mfkey32;
typedef enum {
Mfkey32EventParamCollected,
} Mfkey32Event;
typedef void (*Mfkey32ParseDataCallback)(Mfkey32Event event, void* context);
Mfkey32* mfkey32_alloc(uint32_t cuid);
void mfkey32_free(Mfkey32* instance);
void mfkey32_process_data(
Mfkey32* instance,
uint8_t* data,
uint16_t len,
bool reader_to_tag,
bool crc_dropped);
void mfkey32_set_callback(Mfkey32* instance, Mfkey32ParseDataCallback callback, void* context);
uint16_t mfkey32_get_auth_sectors(FuriString* string);
#ifdef __cplusplus
}
#endif
+566
View File
@@ -0,0 +1,566 @@
#include "nfc_data_generator.h"
#include <furi/furi.h>
#include <furi_hal_random.h>
#include <nfc/protocols/iso14443_3a/iso14443_3a.h>
#include <nfc/protocols/mf_classic/mf_classic.h>
#include <nfc/protocols/mf_ultralight/mf_ultralight.h>
#define NXP_MANUFACTURER_ID (0x04)
typedef void (*NfcDataGeneratorHandler)(NfcDevice* nfc_device);
typedef struct {
const char* name;
NfcDataGeneratorHandler handler;
} NfcDataGenerator;
static const uint8_t version_bytes_mf0ulx1[] = {0x00, 0x04, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03};
static const uint8_t version_bytes_ntag21x[] = {0x00, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x03};
static const uint8_t version_bytes_ntag_i2c[] = {0x00, 0x04, 0x04, 0x05, 0x02, 0x00, 0x00, 0x03};
static const uint8_t default_data_ntag203[] =
{0xE1, 0x10, 0x12, 0x00, 0x01, 0x03, 0xA0, 0x10, 0x44, 0x03, 0x00, 0xFE};
static const uint8_t default_data_ntag213[] = {0x01, 0x03, 0xA0, 0x0C, 0x34, 0x03, 0x00, 0xFE};
static const uint8_t default_data_ntag215_216[] = {0x03, 0x00, 0xFE};
static const uint8_t default_data_ntag_i2c[] = {0xE1, 0x10, 0x00, 0x00, 0x03, 0x00, 0xFE};
static const uint8_t default_config_ntag_i2c[] = {0x01, 0x00, 0xF8, 0x48, 0x08, 0x01, 0x00, 0x00};
static void nfc_generate_mf_ul_uid(uint8_t* uid) {
uid[0] = NXP_MANUFACTURER_ID;
furi_hal_random_fill_buf(&uid[1], 6);
// I'm not sure how this is generated, but the upper nybble always seems to be 8
uid[6] &= 0x0F;
uid[6] |= 0x80;
}
static void nfc_generate_mf_ul_common(MfUltralightData* mfu_data) {
mfu_data->iso14443_3a_data->uid_len = 7;
nfc_generate_mf_ul_uid(mfu_data->iso14443_3a_data->uid);
mfu_data->iso14443_3a_data->atqa[0] = 0x44;
mfu_data->iso14443_3a_data->atqa[1] = 0x00;
mfu_data->iso14443_3a_data->sak = 0x00;
}
static void nfc_generate_calc_bcc(uint8_t* uid, uint8_t* bcc0, uint8_t* bcc1) {
*bcc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2];
*bcc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6];
}
static void nfc_generate_mf_ul_copy_uid_with_bcc(MfUltralightData* mfu_data) {
memcpy(mfu_data->page[0].data, mfu_data->iso14443_3a_data->uid, 3);
memcpy(mfu_data->page[1].data, &mfu_data->iso14443_3a_data->uid[3], 4);
nfc_generate_calc_bcc(
mfu_data->iso14443_3a_data->uid, &mfu_data->page[0].data[3], &mfu_data->page[2].data[0]);
}
static void nfc_generate_mf_ul_orig(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_mf_ul_common(mfu_data);
mfu_data->type = MfUltralightTypeUnknown;
mfu_data->pages_total = 16;
mfu_data->pages_read = 16;
nfc_generate_mf_ul_copy_uid_with_bcc(mfu_data);
memset(&mfu_data->page[4], 0xff, sizeof(MfUltralightPage));
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_mf_ul_with_config_common(MfUltralightData* mfu_data, uint8_t num_pages) {
nfc_generate_mf_ul_common(mfu_data);
mfu_data->pages_total = num_pages;
mfu_data->pages_read = num_pages;
nfc_generate_mf_ul_copy_uid_with_bcc(mfu_data);
uint16_t config_index = (num_pages - 4);
mfu_data->page[config_index].data[0] = 0x04; // STRG_MOD_EN
mfu_data->page[config_index].data[3] = 0xff; // AUTH0
mfu_data->page[config_index + 1].data[1] = 0x05; // VCTID
memset(&mfu_data->page[config_index + 2], 0xff, sizeof(MfUltralightPage)); // Default PWD
if(num_pages > 20) {
mfu_data->page[config_index - 1].data[3] = MF_ULTRALIGHT_TEARING_FLAG_DEFAULT;
}
}
static void nfc_generate_mf_ul_ev1_common(MfUltralightData* mfu_data, uint8_t num_pages) {
nfc_generate_mf_ul_with_config_common(mfu_data, num_pages);
memcpy(&mfu_data->version, version_bytes_mf0ulx1, sizeof(MfUltralightVersion));
for(size_t i = 0; i < 3; ++i) {
mfu_data->tearing_flag[i].data = MF_ULTRALIGHT_TEARING_FLAG_DEFAULT;
}
}
static void nfc_generate_mf_ul_11(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_mf_ul_ev1_common(mfu_data, 20);
mfu_data->type = MfUltralightTypeUL11;
mfu_data->version.prod_subtype = 0x01;
mfu_data->version.storage_size = 0x0B;
mfu_data->page[16].data[0] = 0x00; // Low capacitance version does not have STRG_MOD_EN
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_mf_ul_h11(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_mf_ul_ev1_common(mfu_data, 20);
mfu_data->type = MfUltralightTypeUL11;
mfu_data->version.prod_subtype = 0x02;
mfu_data->version.storage_size = 0x0B;
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_mf_ul_21(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_mf_ul_ev1_common(mfu_data, 41);
mfu_data->type = MfUltralightTypeUL21;
mfu_data->version.prod_subtype = 0x01;
mfu_data->version.storage_size = 0x0E;
mfu_data->page[37].data[0] = 0x00; // Low capacitance version does not have STRG_MOD_EN
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_mf_ul_h21(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_mf_ul_ev1_common(mfu_data, 41);
mfu_data->type = MfUltralightTypeUL21;
mfu_data->version.prod_subtype = 0x02;
mfu_data->version.storage_size = 0x0E;
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_ntag203(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_mf_ul_common(mfu_data);
mfu_data->type = MfUltralightTypeNTAG203;
mfu_data->pages_total = 42;
mfu_data->pages_read = 42;
nfc_generate_mf_ul_copy_uid_with_bcc(mfu_data);
mfu_data->page[2].data[1] = 0x48; // Internal byte
memcpy(&mfu_data->page[3], default_data_ntag203, sizeof(MfUltralightPage)); //-V1086
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_ntag21x_common(MfUltralightData* mfu_data, uint8_t num_pages) {
nfc_generate_mf_ul_with_config_common(mfu_data, num_pages);
memcpy(&mfu_data->version, version_bytes_ntag21x, sizeof(MfUltralightVersion));
mfu_data->page[2].data[1] = 0x48; // Internal byte
// Capability container
mfu_data->page[3].data[0] = 0xE1;
mfu_data->page[3].data[1] = 0x10;
}
static void nfc_generate_ntag213(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_ntag21x_common(mfu_data, 45);
mfu_data->type = MfUltralightTypeNTAG213;
mfu_data->version.storage_size = 0x0F;
mfu_data->page[3].data[2] = 0x12;
// Default contents
memcpy(&mfu_data->page[4], default_data_ntag213, sizeof(default_data_ntag213));
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_ntag215(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_ntag21x_common(mfu_data, 135);
mfu_data->type = MfUltralightTypeNTAG215;
mfu_data->version.storage_size = 0x11;
mfu_data->page[3].data[2] = 0x3E;
// Default contents
memcpy(&mfu_data->page[4], default_data_ntag215_216, sizeof(default_data_ntag215_216));
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_ntag216(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_ntag21x_common(mfu_data, 231);
mfu_data->type = MfUltralightTypeNTAG216;
mfu_data->version.storage_size = 0x13;
mfu_data->page[3].data[2] = 0x6D;
// Default contents
memcpy(&mfu_data->page[4], default_data_ntag215_216, sizeof(default_data_ntag215_216));
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_ntag_i2c_common(
MfUltralightData* mfu_data,
MfUltralightType type,
uint16_t num_pages) {
nfc_generate_mf_ul_common(mfu_data);
mfu_data->type = type;
memcpy(&mfu_data->version, version_bytes_ntag_i2c, sizeof(version_bytes_ntag_i2c));
mfu_data->pages_total = num_pages;
mfu_data->pages_read = num_pages;
memcpy(
mfu_data->page[0].data,
mfu_data->iso14443_3a_data->uid,
mfu_data->iso14443_3a_data->uid_len);
mfu_data->page[1].data[3] = mfu_data->iso14443_3a_data->sak;
mfu_data->page[2].data[0] = mfu_data->iso14443_3a_data->atqa[0];
mfu_data->page[2].data[1] = mfu_data->iso14443_3a_data->atqa[1];
uint16_t config_register_page = 0;
uint16_t session_register_page = 0;
// Sync with mifare_ultralight.c
switch(type) {
case MfUltralightTypeNTAGI2C1K:
config_register_page = 227;
session_register_page = 229;
break;
case MfUltralightTypeNTAGI2C2K:
config_register_page = 481;
session_register_page = 483;
break;
case MfUltralightTypeNTAGI2CPlus1K:
case MfUltralightTypeNTAGI2CPlus2K:
config_register_page = 232;
session_register_page = 234;
break;
default:
furi_crash("Unknown MFUL");
break;
}
memcpy(
&mfu_data->page[config_register_page],
default_config_ntag_i2c,
sizeof(default_config_ntag_i2c));
memcpy(
&mfu_data->page[session_register_page],
default_config_ntag_i2c,
sizeof(default_config_ntag_i2c));
}
static void nfc_generate_ntag_i2c_1k(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_ntag_i2c_common(mfu_data, MfUltralightTypeNTAGI2C1K, 231);
mfu_data->version.prod_ver_minor = 0x01;
mfu_data->version.storage_size = 0x13;
memcpy(&mfu_data->page[3], default_data_ntag_i2c, sizeof(default_data_ntag_i2c));
mfu_data->page[3].data[2] = 0x6D; // Size of tag in CC
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_ntag_i2c_2k(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_ntag_i2c_common(mfu_data, MfUltralightTypeNTAGI2C2K, 485);
mfu_data->version.prod_ver_minor = 0x01;
mfu_data->version.storage_size = 0x15;
memcpy(&mfu_data->page[3], default_data_ntag_i2c, sizeof(default_data_ntag_i2c));
mfu_data->page[3].data[2] = 0xEA; // Size of tag in CC
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_ntag_i2c_plus_common(
MfUltralightData* mfu_data,
MfUltralightType type,
uint16_t num_pages) {
nfc_generate_ntag_i2c_common(mfu_data, type, num_pages);
uint16_t config_index = 227;
mfu_data->page[config_index].data[3] = 0xff; // AUTH0
memset(&mfu_data->page[config_index + 2], 0xFF, sizeof(MfUltralightPage)); // Default PWD
}
static void nfc_generate_ntag_i2c_plus_1k(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_ntag_i2c_plus_common(mfu_data, MfUltralightTypeNTAGI2CPlus1K, 236);
mfu_data->version.prod_ver_minor = 0x02;
mfu_data->version.storage_size = 0x13;
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_ntag_i2c_plus_2k(NfcDevice* nfc_device) {
MfUltralightData* mfu_data = mf_ultralight_alloc();
nfc_generate_ntag_i2c_plus_common(mfu_data, MfUltralightTypeNTAGI2CPlus2K, 492);
mfu_data->version.prod_ver_minor = 0x02;
mfu_data->version.storage_size = 0x15;
nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data);
mf_ultralight_free(mfu_data);
}
static void nfc_generate_mf_classic_uid(uint8_t* uid, uint8_t length) {
uid[0] = NXP_MANUFACTURER_ID;
furi_hal_random_fill_buf(&uid[1], length - 1);
}
static void
nfc_generate_mf_classic_common(MfClassicData* data, uint8_t uid_len, MfClassicType type) {
data->iso14443_3a_data->uid_len = uid_len;
data->iso14443_3a_data->atqa[0] = 0x44;
data->iso14443_3a_data->atqa[1] = 0x00;
data->iso14443_3a_data->sak = 0x08;
data->type = type;
}
static void nfc_generate_mf_classic_sector_trailer(MfClassicData* data, uint8_t block) {
// All keys are set to FFFF FFFF FFFFh at chip delivery and the bytes 6, 7 and 8 are set to FF0780h.
MfClassicSectorTrailer* sec_tr = (MfClassicSectorTrailer*)data->block[block].data;
sec_tr->access_bits.data[0] = 0xFF;
sec_tr->access_bits.data[1] = 0x07;
sec_tr->access_bits.data[2] = 0x80;
sec_tr->access_bits.data[3] = 0x69; // Nice
mf_classic_set_block_read(data, block, &data->block[block]);
mf_classic_set_key_found(
data, mf_classic_get_sector_by_block(block), MfClassicKeyTypeA, 0xFFFFFFFFFFFF);
mf_classic_set_key_found(
data, mf_classic_get_sector_by_block(block), MfClassicKeyTypeB, 0xFFFFFFFFFFFF);
}
static void nfc_generate_mf_classic_block_0(
uint8_t* block,
uint8_t uid_len,
uint8_t sak,
uint8_t atqa0,
uint8_t atqa1) {
// Block length is always 16 bytes, and the UID can be either 4 or 7 bytes
furi_assert(uid_len == 4 || uid_len == 7);
furi_assert(block);
if(uid_len == 4) {
// Calculate BCC
block[uid_len] = 0;
for(int i = 0; i < uid_len; i++) {
block[uid_len] ^= block[i];
}
} else {
uid_len -= 1;
}
block[uid_len + 1] = sak;
block[uid_len + 2] = atqa0;
block[uid_len + 3] = atqa1;
for(int i = uid_len + 4; i < 16; i++) {
block[i] = 0xFF;
}
}
static void nfc_generate_mf_classic(NfcDevice* nfc_device, uint8_t uid_len, MfClassicType type) {
MfClassicData* mfc_data = mf_classic_alloc();
nfc_generate_mf_classic_uid(mfc_data->block[0].data, uid_len);
nfc_generate_mf_classic_common(mfc_data, uid_len, type);
// Set the UID
mfc_data->iso14443_3a_data->uid[0] = NXP_MANUFACTURER_ID;
for(int i = 1; i < uid_len; i++) {
mfc_data->iso14443_3a_data->uid[i] = mfc_data->block[0].data[i];
}
mf_classic_set_block_read(mfc_data, 0, &mfc_data->block[0]);
uint16_t block_num = mf_classic_get_total_block_num(type);
if(type == MfClassicType4k) {
// Set every block to 0xFF
for(uint16_t i = 1; i < block_num; i++) {
if(mf_classic_is_sector_trailer(i)) {
nfc_generate_mf_classic_sector_trailer(mfc_data, i);
} else {
memset(&mfc_data->block[i].data, 0xFF, 16);
}
mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]);
}
// Set SAK to 18
mfc_data->iso14443_3a_data->sak = 0x18;
} else if(type == MfClassicType1k) {
// Set every block to 0xFF
for(uint16_t i = 1; i < block_num; i++) {
if(mf_classic_is_sector_trailer(i)) {
nfc_generate_mf_classic_sector_trailer(mfc_data, i);
} else {
memset(&mfc_data->block[i].data, 0xFF, 16);
}
mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]);
}
// Set SAK to 08
mfc_data->iso14443_3a_data->sak = 0x08;
} else if(type == MfClassicTypeMini) {
// Set every block to 0xFF
for(uint16_t i = 1; i < block_num; i++) {
if(mf_classic_is_sector_trailer(i)) {
nfc_generate_mf_classic_sector_trailer(mfc_data, i);
} else {
memset(&mfc_data->block[i].data, 0xFF, 16);
}
mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]);
}
// Set SAK to 09
mfc_data->iso14443_3a_data->sak = 0x09;
}
nfc_generate_mf_classic_block_0(
mfc_data->block[0].data,
uid_len,
mfc_data->iso14443_3a_data->sak,
mfc_data->iso14443_3a_data->atqa[0],
mfc_data->iso14443_3a_data->atqa[1]);
mfc_data->type = type;
nfc_device_set_data(nfc_device, NfcProtocolMfClassic, mfc_data);
mf_classic_free(mfc_data);
}
static void nfc_generate_mf_classic_mini(NfcDevice* nfc_device) {
nfc_generate_mf_classic(nfc_device, 4, MfClassicTypeMini);
}
static void nfc_generate_mf_classic_1k_4b_uid(NfcDevice* nfc_device) {
nfc_generate_mf_classic(nfc_device, 4, MfClassicType1k);
}
static void nfc_generate_mf_classic_1k_7b_uid(NfcDevice* nfc_device) {
nfc_generate_mf_classic(nfc_device, 7, MfClassicType1k);
}
static void nfc_generate_mf_classic_4k_4b_uid(NfcDevice* nfc_device) {
nfc_generate_mf_classic(nfc_device, 4, MfClassicType4k);
}
static void nfc_generate_mf_classic_4k_7b_uid(NfcDevice* nfc_device) {
nfc_generate_mf_classic(nfc_device, 7, MfClassicType4k);
}
static const NfcDataGenerator nfc_data_generator[NfcDataGeneratorTypeNum] = {
[NfcDataGeneratorTypeMfUltralight] =
{
.name = "Mifare Ultralight",
.handler = nfc_generate_mf_ul_orig,
},
[NfcDataGeneratorTypeMfUltralightEV1_11] =
{
.name = "Mifare Ultralight EV1 11",
.handler = nfc_generate_mf_ul_11,
},
[NfcDataGeneratorTypeMfUltralightEV1_H11] =
{
.name = "Mifare Ultralight EV1 H11",
.handler = nfc_generate_mf_ul_h11,
},
[NfcDataGeneratorTypeMfUltralightEV1_21] =
{
.name = "Mifare Ultralight EV1 21",
.handler = nfc_generate_mf_ul_21,
},
[NfcDataGeneratorTypeMfUltralightEV1_H21] =
{
.name = "Mifare Ultralight EV1 H21",
.handler = nfc_generate_mf_ul_h21,
},
[NfcDataGeneratorTypeNTAG203] =
{
.name = "NTAG203",
.handler = nfc_generate_ntag203,
},
[NfcDataGeneratorTypeNTAG213] =
{
.name = "NTAG213",
.handler = nfc_generate_ntag213,
},
[NfcDataGeneratorTypeNTAG215] =
{
.name = "NTAG215",
.handler = nfc_generate_ntag215,
},
[NfcDataGeneratorTypeNTAG216] =
{
.name = "NTAG216",
.handler = nfc_generate_ntag216,
},
[NfcDataGeneratorTypeNTAGI2C1k] =
{
.name = "NTAG I2C 1k",
.handler = nfc_generate_ntag_i2c_1k,
},
[NfcDataGeneratorTypeNTAGI2C2k] =
{
.name = "NTAG I2C 2k",
.handler = nfc_generate_ntag_i2c_2k,
},
[NfcDataGeneratorTypeNTAGI2CPlus1k] =
{
.name = "NTAG I2C Plus 1k",
.handler = nfc_generate_ntag_i2c_plus_1k,
},
[NfcDataGeneratorTypeNTAGI2CPlus2k] =
{
.name = "NTAG I2C Plus 2k",
.handler = nfc_generate_ntag_i2c_plus_2k,
},
[NfcDataGeneratorTypeMfClassicMini] =
{
.name = "Mifare Mini",
.handler = nfc_generate_mf_classic_mini,
},
[NfcDataGeneratorTypeMfClassic1k_4b] =
{
.name = "Mifare Classic 1k 4byte UID",
.handler = nfc_generate_mf_classic_1k_4b_uid,
},
[NfcDataGeneratorTypeMfClassic1k_7b] =
{
.name = "Mifare Classic 1k 7byte UID",
.handler = nfc_generate_mf_classic_1k_7b_uid,
},
[NfcDataGeneratorTypeMfClassic4k_4b] =
{
.name = "Mifare Classic 4k 4byte UID",
.handler = nfc_generate_mf_classic_4k_4b_uid,
},
[NfcDataGeneratorTypeMfClassic4k_7b] =
{
.name = "Mifare Classic 4k 7byte UID",
.handler = nfc_generate_mf_classic_4k_7b_uid,
},
};
const char* nfc_data_generator_get_name(NfcDataGeneratorType type) {
return nfc_data_generator[type].name;
}
void nfc_data_generator_fill_data(NfcDataGeneratorType type, NfcDevice* nfc_device) {
nfc_data_generator[type].handler(nfc_device);
}
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include <nfc/nfc_device.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
NfcDataGeneratorTypeMfUltralight,
NfcDataGeneratorTypeMfUltralightEV1_11,
NfcDataGeneratorTypeMfUltralightEV1_H11,
NfcDataGeneratorTypeMfUltralightEV1_21,
NfcDataGeneratorTypeMfUltralightEV1_H21,
NfcDataGeneratorTypeNTAG203,
NfcDataGeneratorTypeNTAG213,
NfcDataGeneratorTypeNTAG215,
NfcDataGeneratorTypeNTAG216,
NfcDataGeneratorTypeNTAGI2C1k,
NfcDataGeneratorTypeNTAGI2C2k,
NfcDataGeneratorTypeNTAGI2CPlus1k,
NfcDataGeneratorTypeNTAGI2CPlus2k,
NfcDataGeneratorTypeMfClassicMini,
NfcDataGeneratorTypeMfClassic1k_4b,
NfcDataGeneratorTypeMfClassic1k_7b,
NfcDataGeneratorTypeMfClassic4k_4b,
NfcDataGeneratorTypeMfClassic4k_7b,
NfcDataGeneratorTypeNum,
} NfcDataGeneratorType;
const char* nfc_data_generator_get_name(NfcDataGeneratorType type);
void nfc_data_generator_fill_data(NfcDataGeneratorType type, NfcDevice* nfc_device);
#ifdef __cplusplus
}
#endif
-71
View File
@@ -1,71 +0,0 @@
#include "nfc_debug_log.h"
#include <storage/storage.h>
#include <stream/buffered_file_stream.h>
#define TAG "NfcDebugLog"
#define NFC_DEBUG_PCAP_FILENAME EXT_PATH("nfc/debug.txt")
struct NfcDebugLog {
Stream* file_stream;
FuriString* data_str;
};
NfcDebugLog* nfc_debug_log_alloc() {
NfcDebugLog* instance = malloc(sizeof(NfcDebugLog));
Storage* storage = furi_record_open(RECORD_STORAGE);
instance->file_stream = buffered_file_stream_alloc(storage);
if(!buffered_file_stream_open(
instance->file_stream, NFC_DEBUG_PCAP_FILENAME, FSAM_WRITE, FSOM_OPEN_APPEND)) {
buffered_file_stream_close(instance->file_stream);
stream_free(instance->file_stream);
instance->file_stream = NULL;
}
if(!instance->file_stream) {
free(instance);
instance = NULL;
} else {
instance->data_str = furi_string_alloc();
}
furi_record_close(RECORD_STORAGE);
return instance;
}
void nfc_debug_log_free(NfcDebugLog* instance) {
furi_assert(instance);
furi_assert(instance->file_stream);
furi_assert(instance->data_str);
buffered_file_stream_close(instance->file_stream);
stream_free(instance->file_stream);
furi_string_free(instance->data_str);
free(instance);
}
void nfc_debug_log_process_data(
NfcDebugLog* instance,
uint8_t* data,
uint16_t len,
bool reader_to_tag,
bool crc_dropped) {
furi_assert(instance);
furi_assert(instance->file_stream);
furi_assert(instance->data_str);
furi_assert(data);
UNUSED(crc_dropped);
furi_string_printf(instance->data_str, "%lu %c:", furi_get_tick(), reader_to_tag ? 'R' : 'T');
uint16_t data_len = len;
for(size_t i = 0; i < data_len; i++) {
furi_string_cat_printf(instance->data_str, " %02x", data[i]);
}
furi_string_push_back(instance->data_str, '\n');
stream_write_string(instance->file_stream, instance->data_str);
}
-17
View File
@@ -1,17 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
typedef struct NfcDebugLog NfcDebugLog;
NfcDebugLog* nfc_debug_log_alloc();
void nfc_debug_log_free(NfcDebugLog* instance);
void nfc_debug_log_process_data(
NfcDebugLog* instance,
uint8_t* data,
uint16_t len,
bool reader_to_tag,
bool crc_dropped);
-130
View File
@@ -1,130 +0,0 @@
#include "nfc_debug_pcap.h"
#include <storage/storage.h>
#include <stream/buffered_file_stream.h>
#include <furi_hal_nfc.h>
#include <furi_hal_rtc.h>
#define TAG "NfcDebugPcap"
#define PCAP_MAGIC 0xa1b2c3d4
#define PCAP_MAJOR 2
#define PCAP_MINOR 4
#define DLT_ISO_14443 264
#define DATA_PICC_TO_PCD 0xFF
#define DATA_PCD_TO_PICC 0xFE
#define DATA_PICC_TO_PCD_CRC_DROPPED 0xFB
#define DATA_PCD_TO_PICC_CRC_DROPPED 0xFA
#define NFC_DEBUG_PCAP_FILENAME EXT_PATH("nfc/debug.pcap")
struct NfcDebugPcap {
Stream* file_stream;
};
static Stream* nfc_debug_pcap_open(Storage* storage) {
Stream* stream = NULL;
stream = buffered_file_stream_alloc(storage);
if(!buffered_file_stream_open(stream, NFC_DEBUG_PCAP_FILENAME, FSAM_WRITE, FSOM_OPEN_APPEND)) {
buffered_file_stream_close(stream);
stream_free(stream);
stream = NULL;
} else {
if(!stream_tell(stream)) {
struct {
uint32_t magic;
uint16_t major, minor;
uint32_t reserved[2];
uint32_t snaplen;
uint32_t link_type;
} __attribute__((__packed__)) pcap_hdr = {
.magic = PCAP_MAGIC,
.major = PCAP_MAJOR,
.minor = PCAP_MINOR,
.snaplen = FURI_HAL_NFC_DATA_BUFF_SIZE,
.link_type = DLT_ISO_14443,
};
if(stream_write(stream, (uint8_t*)&pcap_hdr, sizeof(pcap_hdr)) != sizeof(pcap_hdr)) {
FURI_LOG_E(TAG, "Failed to write pcap header");
buffered_file_stream_close(stream);
stream_free(stream);
stream = NULL;
}
}
}
return stream;
}
NfcDebugPcap* nfc_debug_pcap_alloc() {
NfcDebugPcap* instance = malloc(sizeof(NfcDebugPcap));
Storage* storage = furi_record_open(RECORD_STORAGE);
instance->file_stream = nfc_debug_pcap_open(storage);
if(!instance->file_stream) {
free(instance);
instance = NULL;
}
furi_record_close(RECORD_STORAGE);
return instance;
}
void nfc_debug_pcap_free(NfcDebugPcap* instance) {
furi_assert(instance);
furi_assert(instance->file_stream);
buffered_file_stream_close(instance->file_stream);
stream_free(instance->file_stream);
free(instance);
}
void nfc_debug_pcap_process_data(
NfcDebugPcap* instance,
uint8_t* data,
uint16_t len,
bool reader_to_tag,
bool crc_dropped) {
furi_assert(instance);
furi_assert(data);
FuriHalRtcDateTime datetime;
furi_hal_rtc_get_datetime(&datetime);
uint8_t event = 0;
if(reader_to_tag) {
if(crc_dropped) {
event = DATA_PCD_TO_PICC_CRC_DROPPED;
} else {
event = DATA_PCD_TO_PICC;
}
} else {
if(crc_dropped) {
event = DATA_PICC_TO_PCD_CRC_DROPPED;
} else {
event = DATA_PICC_TO_PCD;
}
}
struct {
// https://wiki.wireshark.org/Development/LibpcapFileFormat#record-packet-header
uint32_t ts_sec;
uint32_t ts_usec;
uint32_t incl_len;
uint32_t orig_len;
// https://www.kaiser.cx/posts/pcap-iso14443/#_packet_data
uint8_t version;
uint8_t event;
uint16_t len;
} __attribute__((__packed__)) pkt_hdr = {
.ts_sec = furi_hal_rtc_datetime_to_timestamp(&datetime),
.ts_usec = 0,
.incl_len = len + 4,
.orig_len = len + 4,
.version = 0,
.event = event,
.len = len << 8 | len >> 8,
};
stream_write(instance->file_stream, (uint8_t*)&pkt_hdr, sizeof(pkt_hdr));
stream_write(instance->file_stream, data, len);
}
-17
View File
@@ -1,17 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
typedef struct NfcDebugPcap NfcDebugPcap;
NfcDebugPcap* nfc_debug_pcap_alloc();
void nfc_debug_pcap_free(NfcDebugPcap* instance);
void nfc_debug_pcap_process_data(
NfcDebugPcap* instance,
uint8_t* data,
uint16_t len,
bool reader_to_tag,
bool crc_dropped);
+270
View File
@@ -0,0 +1,270 @@
#include "nfc_dict.h"
#include <storage/storage.h>
#include <flipper_format/flipper_format.h>
#include <toolbox/stream/file_stream.h>
#include <toolbox/stream/buffered_file_stream.h>
#include <toolbox/args.h>
#include <nfc/helpers/nfc_util.h>
#define TAG "NfcDict"
struct NfcDict {
Stream* stream;
size_t key_size;
size_t key_size_symbols;
uint32_t total_keys;
};
typedef struct {
const char* path;
FS_OpenMode open_mode;
} NfcDictFile;
bool nfc_dict_check_presence(const char* path) {
furi_assert(path);
Storage* storage = furi_record_open(RECORD_STORAGE);
bool dict_present = storage_common_stat(storage, path, NULL) == FSE_OK;
furi_record_close(RECORD_STORAGE);
return dict_present;
}
NfcDict* nfc_dict_alloc(const char* path, NfcDictMode mode, size_t key_size) {
furi_assert(path);
NfcDict* instance = malloc(sizeof(NfcDict));
Storage* storage = furi_record_open(RECORD_STORAGE);
instance->stream = buffered_file_stream_alloc(storage);
furi_record_close(RECORD_STORAGE);
FS_OpenMode open_mode = FSOM_OPEN_EXISTING;
if(mode == NfcDictModeOpenAlways) {
open_mode = FSOM_OPEN_ALWAYS;
}
instance->key_size = key_size;
// Byte = 2 symbols + 1 end of line
instance->key_size_symbols = key_size * 2 + 1;
bool dict_loaded = false;
do {
if(!buffered_file_stream_open(instance->stream, path, FSAM_READ_WRITE, open_mode)) {
buffered_file_stream_close(instance->stream);
break;
}
// Check for new line ending
if(!stream_eof(instance->stream)) {
if(!stream_seek(instance->stream, -1, StreamOffsetFromEnd)) break;
uint8_t last_char = 0;
if(stream_read(instance->stream, &last_char, 1) != 1) break;
if(last_char != '\n') {
FURI_LOG_D(TAG, "Adding new line ending");
if(stream_write_char(instance->stream, '\n') != 1) break;
}
if(!stream_rewind(instance->stream)) break;
}
// Read total amount of keys
FuriString* next_line;
next_line = furi_string_alloc();
while(true) {
if(!stream_read_line(instance->stream, next_line)) {
FURI_LOG_T(TAG, "No keys left in dict");
break;
}
FURI_LOG_T(
TAG,
"Read line: %s, len: %zu",
furi_string_get_cstr(next_line),
furi_string_size(next_line));
if(furi_string_get_char(next_line, 0) == '#') continue;
if(furi_string_size(next_line) != instance->key_size_symbols) continue;
instance->total_keys++;
}
furi_string_free(next_line);
stream_rewind(instance->stream);
dict_loaded = true;
FURI_LOG_I(TAG, "Loaded dictionary with %lu keys", instance->total_keys);
} while(false);
if(!dict_loaded) {
buffered_file_stream_close(instance->stream);
free(instance);
instance = NULL;
}
return instance;
}
void nfc_dict_free(NfcDict* instance) {
furi_assert(instance);
furi_assert(instance->stream);
buffered_file_stream_close(instance->stream);
stream_free(instance->stream);
free(instance);
}
static void nfc_dict_int_to_str(NfcDict* instance, const uint8_t* key_int, FuriString* key_str) {
furi_string_reset(key_str);
for(size_t i = 0; i < instance->key_size; i++) {
furi_string_cat_printf(key_str, "%02X", key_int[i]);
}
}
static void nfc_dict_str_to_int(NfcDict* instance, FuriString* key_str, uint64_t* key_int) {
uint8_t key_byte_tmp;
*key_int = 0ULL;
for(uint8_t i = 0; i < instance->key_size * 2; i += 2) {
args_char_to_hex(
furi_string_get_char(key_str, i), furi_string_get_char(key_str, i + 1), &key_byte_tmp);
*key_int |= (uint64_t)key_byte_tmp << (8 * (instance->key_size - 1 - i / 2));
}
}
uint32_t nfc_dict_get_total_keys(NfcDict* instance) {
furi_assert(instance);
return instance->total_keys;
}
bool nfc_dict_rewind(NfcDict* instance) {
furi_assert(instance);
furi_assert(instance->stream);
return stream_rewind(instance->stream);
}
static bool nfc_dict_get_next_key_str(NfcDict* instance, FuriString* key) {
furi_assert(instance);
furi_assert(instance->stream);
bool key_read = false;
furi_string_reset(key);
while(!key_read) {
if(!stream_read_line(instance->stream, key)) break;
if(furi_string_get_char(key, 0) == '#') continue;
if(furi_string_size(key) != instance->key_size_symbols) continue;
furi_string_left(key, instance->key_size_symbols - 1);
key_read = true;
}
return key_read;
}
bool nfc_dict_get_next_key(NfcDict* instance, uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(instance->key_size == key_size);
FuriString* temp_key = furi_string_alloc();
uint64_t key_int = 0;
bool key_read = nfc_dict_get_next_key_str(instance, temp_key);
if(key_read) {
nfc_dict_str_to_int(instance, temp_key, &key_int);
nfc_util_num2bytes(key_int, key_size, key);
}
furi_string_free(temp_key);
return key_read;
}
static bool nfc_dict_is_key_present_str(NfcDict* instance, FuriString* key) {
furi_assert(instance);
furi_assert(instance->stream);
FuriString* next_line;
next_line = furi_string_alloc();
bool key_found = false;
stream_rewind(instance->stream);
while(!key_found) { //-V654
if(!stream_read_line(instance->stream, next_line)) break;
if(furi_string_get_char(next_line, 0) == '#') continue;
if(furi_string_size(next_line) != instance->key_size_symbols) continue;
furi_string_left(next_line, instance->key_size_symbols - 1);
if(!furi_string_equal(key, next_line)) continue;
key_found = true;
}
furi_string_free(next_line);
return key_found;
}
bool nfc_dict_is_key_present(NfcDict* instance, const uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(key);
furi_assert(instance->stream);
furi_assert(instance->key_size == key_size);
FuriString* temp_key = furi_string_alloc();
nfc_dict_int_to_str(instance, key, temp_key);
bool key_found = nfc_dict_is_key_present_str(instance, temp_key);
furi_string_free(temp_key);
return key_found;
}
static bool nfc_dict_add_key_str(NfcDict* instance, FuriString* key) {
furi_assert(instance);
furi_assert(instance->stream);
furi_string_cat_printf(key, "\n");
bool key_added = false;
do {
if(!stream_seek(instance->stream, 0, StreamOffsetFromEnd)) break;
if(!stream_insert_string(instance->stream, key)) break;
instance->total_keys++;
key_added = true;
} while(false);
furi_string_left(key, instance->key_size_symbols - 1);
return key_added;
}
bool nfc_dict_add_key(NfcDict* instance, const uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(key);
furi_assert(instance->stream);
furi_assert(instance->key_size == key_size);
FuriString* temp_key = furi_string_alloc();
nfc_dict_int_to_str(instance, key, temp_key);
bool key_added = nfc_dict_add_key_str(instance, temp_key);
furi_string_free(temp_key);
return key_added;
}
bool nfc_dict_delete_key(NfcDict* instance, const uint8_t* key, size_t key_size) {
furi_assert(instance);
furi_assert(instance->stream);
furi_assert(key);
furi_assert(instance->key_size == key_size);
bool key_removed = false;
uint8_t* temp_key = malloc(key_size);
nfc_dict_rewind(instance);
while(!key_removed) {
if(!nfc_dict_get_next_key(instance, temp_key, key_size)) break;
if(memcmp(temp_key, key, key_size) == 0) {
int32_t offset = (-1) * (instance->key_size_symbols);
stream_seek(instance->stream, offset, StreamOffsetFromCurrent);
if(!stream_delete(instance->stream, instance->key_size_symbols)) break;
instance->total_keys--;
key_removed = true;
}
}
nfc_dict_rewind(instance);
free(temp_key);
return key_removed;
}
+103
View File
@@ -0,0 +1,103 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
NfcDictModeOpenExisting,
NfcDictModeOpenAlways,
} NfcDictMode;
typedef struct NfcDict NfcDict;
/** Check dictionary presence
*
* @param path - dictionary path
*
* @return true if dictionary exists, false otherwise
*/
bool nfc_dict_check_presence(const char* path);
/** Open or create dictionary
* Depending on mode, dictionary will be opened or created.
*
* @param path - dictionary path
* @param mode - NfcDictMode value
* @param key_size - size of dictionary keys in bytes
*
* @return NfcDict dictionary instance
*/
NfcDict* nfc_dict_alloc(const char* path, NfcDictMode mode, size_t key_size);
/** Close dictionary
*
* @param instance - NfcDict dictionary instance
*/
void nfc_dict_free(NfcDict* instance);
/** Get total number of keys in dictionary
*
* @param instance - NfcDict dictionary instance
*
* @return total number of keys in dictionary
*/
uint32_t nfc_dict_get_total_keys(NfcDict* instance);
/** Rewind dictionary
*
* @param instance - NfcDict dictionary instance
*
* @return true if rewind was successful, false otherwise
*/
bool nfc_dict_rewind(NfcDict* instance);
/** Check if key is present in dictionary
*
* @param instance - NfcDict dictionary instance
* @param key - key to check
* @param key_size - size of key in bytes
*
* @return true if key is present, false otherwise
*/
bool nfc_dict_is_key_present(NfcDict* instance, const uint8_t* key, size_t key_size);
/** Get next key from dictionary
* This function will return next key from dictionary. If there are no more
* keys, it will return false, and nfc_dict_rewind() should be called.
*
* @param instance - NfcDict dictionary instance
* @param key - buffer to store key
* @param key_size - size of key in bytes
*
* @return true if key was successfully retrieved, false otherwise
*/
bool nfc_dict_get_next_key(NfcDict* instance, uint8_t* key, size_t key_size);
/** Add key to dictionary
*
* @param instance - NfcDict dictionary instance
* @param key - key to add
* @param key_size - size of key in bytes
*
* @return true if key was successfully added, false otherwise
*/
bool nfc_dict_add_key(NfcDict* instance, const uint8_t* key, size_t key_size);
/** Delete key from dictionary
*
* @param instance - NfcDict dictionary instance
* @param key - key to delete
* @param key_size - size of key in bytes
*
* @return true if key was successfully deleted, false otherwise
*/
bool nfc_dict_delete_key(NfcDict* instance, const uint8_t* key, size_t key_size);
#ifdef __cplusplus
}
#endif
-548
View File
@@ -1,548 +0,0 @@
#include <furi_hal_random.h>
#include "nfc_generators.h"
#define NXP_MANUFACTURER_ID (0x04)
static const uint8_t version_bytes_mf0ulx1[] = {0x00, 0x04, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03};
static const uint8_t version_bytes_ntag21x[] = {0x00, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x03};
static const uint8_t version_bytes_ntag_i2c[] = {0x00, 0x04, 0x04, 0x05, 0x02, 0x00, 0x00, 0x03};
static const uint8_t default_data_ntag203[] =
{0xE1, 0x10, 0x12, 0x00, 0x01, 0x03, 0xA0, 0x10, 0x44, 0x03, 0x00, 0xFE};
static const uint8_t default_data_ntag213[] = {0x01, 0x03, 0xA0, 0x0C, 0x34, 0x03, 0x00, 0xFE};
static const uint8_t default_data_ntag215_216[] = {0x03, 0x00, 0xFE};
static const uint8_t default_data_ntag_i2c[] = {0xE1, 0x10, 0x00, 0x00, 0x03, 0x00, 0xFE};
static const uint8_t default_config_ntag_i2c[] = {0x01, 0x00, 0xF8, 0x48, 0x08, 0x01, 0x00, 0x00};
static void nfc_generate_common_start(NfcDeviceData* data) {
nfc_device_data_clear(data);
}
static void nfc_generate_mf_ul_uid(uint8_t* uid) {
uid[0] = NXP_MANUFACTURER_ID;
furi_hal_random_fill_buf(&uid[1], 6);
// I'm not sure how this is generated, but the upper nybble always seems to be 8
uid[6] &= 0x0F;
uid[6] |= 0x80;
}
static void nfc_generate_mf_classic_uid(uint8_t* uid, uint8_t length) {
uid[0] = NXP_MANUFACTURER_ID;
furi_hal_random_fill_buf(&uid[1], length - 1);
}
static void nfc_generate_mf_classic_block_0(
uint8_t* block,
uint8_t uid_len,
uint8_t sak,
uint8_t atqa0,
uint8_t atqa1) {
// Block length is always 16 bytes, and the UID can be either 4 or 7 bytes
furi_assert(uid_len == 4 || uid_len == 7);
furi_assert(block);
if(uid_len == 4) {
// Calculate BCC
block[uid_len] = 0;
for(int i = 0; i < uid_len; i++) {
block[uid_len] ^= block[i];
}
} else {
uid_len -= 1;
}
block[uid_len + 1] = sak;
block[uid_len + 2] = atqa0;
block[uid_len + 3] = atqa1;
for(int i = uid_len + 4; i < 16; i++) {
block[i] = 0xFF;
}
}
static void nfc_generate_mf_classic_sector_trailer(MfClassicData* data, uint8_t block) {
// All keys are set to FFFF FFFF FFFFh at chip delivery and the bytes 6, 7 and 8 are set to FF0780h.
MfClassicSectorTrailer* sec_tr = (MfClassicSectorTrailer*)data->block[block].value;
sec_tr->access_bits[0] = 0xFF;
sec_tr->access_bits[1] = 0x07;
sec_tr->access_bits[2] = 0x80;
sec_tr->access_bits[3] = 0x69; // Nice
memset(sec_tr->key_a, 0xff, sizeof(sec_tr->key_a));
memset(sec_tr->key_b, 0xff, sizeof(sec_tr->key_b));
mf_classic_set_block_read(data, block, &data->block[block]);
mf_classic_set_key_found(
data, mf_classic_get_sector_by_block(block), MfClassicKeyA, 0xFFFFFFFFFFFF);
mf_classic_set_key_found(
data, mf_classic_get_sector_by_block(block), MfClassicKeyB, 0xFFFFFFFFFFFF);
}
static void nfc_generate_mf_ul_common(NfcDeviceData* data) {
data->nfc_data.type = FuriHalNfcTypeA;
data->nfc_data.interface = FuriHalNfcInterfaceRf;
data->nfc_data.uid_len = 7;
nfc_generate_mf_ul_uid(data->nfc_data.uid);
data->nfc_data.atqa[0] = 0x44;
data->nfc_data.atqa[1] = 0x00;
data->nfc_data.sak = 0x00;
data->protocol = NfcDeviceProtocolMifareUl;
}
static void
nfc_generate_mf_classic_common(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) {
data->nfc_data.type = FuriHalNfcTypeA;
data->nfc_data.interface = FuriHalNfcInterfaceRf;
data->nfc_data.uid_len = uid_len;
data->nfc_data.atqa[0] = 0x44;
data->nfc_data.atqa[1] = 0x00;
data->nfc_data.sak = 0x08;
data->protocol = NfcDeviceProtocolMifareClassic;
data->mf_classic_data.type = type;
}
static void nfc_generate_calc_bcc(uint8_t* uid, uint8_t* bcc0, uint8_t* bcc1) {
*bcc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2];
*bcc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6];
}
static void nfc_generate_mf_ul_copy_uid_with_bcc(NfcDeviceData* data) {
MfUltralightData* mful = &data->mf_ul_data;
memcpy(mful->data, data->nfc_data.uid, 3);
memcpy(&mful->data[4], &data->nfc_data.uid[3], 4);
nfc_generate_calc_bcc(data->nfc_data.uid, &mful->data[3], &mful->data[8]);
}
static void nfc_generate_mf_ul_orig(NfcDeviceData* data) {
nfc_generate_common_start(data);
nfc_generate_mf_ul_common(data);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeUnknown;
mful->data_size = 16 * 4;
mful->data_read = mful->data_size;
nfc_generate_mf_ul_copy_uid_with_bcc(data);
// TODO: what's internal byte on page 2?
memset(&mful->data[4 * 4], 0xFF, 4);
}
static void nfc_generate_mf_ul_ntag203(NfcDeviceData* data) {
nfc_generate_common_start(data);
nfc_generate_mf_ul_common(data);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeNTAG203;
mful->data_size = 42 * 4;
mful->data_read = mful->data_size;
nfc_generate_mf_ul_copy_uid_with_bcc(data);
mful->data[9] = 0x48; // Internal byte
memcpy(&mful->data[3 * 4], default_data_ntag203, sizeof(default_data_ntag203));
}
static void nfc_generate_mf_ul_with_config_common(NfcDeviceData* data, uint8_t num_pages) {
nfc_generate_common_start(data);
nfc_generate_mf_ul_common(data);
MfUltralightData* mful = &data->mf_ul_data;
mful->data_size = num_pages * 4;
mful->data_read = mful->data_size;
nfc_generate_mf_ul_copy_uid_with_bcc(data);
uint16_t config_index = (num_pages - 4) * 4;
mful->data[config_index] = 0x04; // STRG_MOD_EN
mful->data[config_index + 3] = 0xFF; // AUTH0
mful->data[config_index + 5] = 0x05; // VCTID
memset(&mful->data[config_index + 8], 0xFF, 4); // Default PWD
if(num_pages > 20) mful->data[config_index - 1] = MF_UL_TEARING_FLAG_DEFAULT;
}
static void nfc_generate_mf_ul_ev1_common(NfcDeviceData* data, uint8_t num_pages) {
nfc_generate_mf_ul_with_config_common(data, num_pages);
MfUltralightData* mful = &data->mf_ul_data;
memcpy(&mful->version, version_bytes_mf0ulx1, sizeof(version_bytes_mf0ulx1));
for(size_t i = 0; i < 3; ++i) {
mful->tearing[i] = MF_UL_TEARING_FLAG_DEFAULT;
}
// TODO: what's internal byte on page 2?
}
static void nfc_generate_mf_ul_11(NfcDeviceData* data) {
nfc_generate_mf_ul_ev1_common(data, 20);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeUL11;
mful->version.prod_subtype = 0x01;
mful->version.storage_size = 0x0B;
mful->data[16 * 4] = 0x00; // Low capacitance version does not have STRG_MOD_EN
}
static void nfc_generate_mf_ul_h11(NfcDeviceData* data) {
nfc_generate_mf_ul_ev1_common(data, 20);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeUL11;
mful->version.prod_subtype = 0x02;
mful->version.storage_size = 0x0B;
}
static void nfc_generate_mf_ul_21(NfcDeviceData* data) {
nfc_generate_mf_ul_ev1_common(data, 41);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeUL21;
mful->version.prod_subtype = 0x01;
mful->version.storage_size = 0x0E;
mful->data[37 * 4] = 0x00; // Low capacitance version does not have STRG_MOD_EN
}
static void nfc_generate_mf_ul_h21(NfcDeviceData* data) {
nfc_generate_mf_ul_ev1_common(data, 41);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeUL21;
mful->version.prod_subtype = 0x02;
mful->version.storage_size = 0x0E;
}
static void nfc_generate_ntag21x_common(NfcDeviceData* data, uint8_t num_pages) {
nfc_generate_mf_ul_with_config_common(data, num_pages);
MfUltralightData* mful = &data->mf_ul_data;
memcpy(&mful->version, version_bytes_ntag21x, sizeof(version_bytes_mf0ulx1));
mful->data[9] = 0x48; // Internal byte
// Capability container
mful->data[12] = 0xE1;
mful->data[13] = 0x10;
}
static void nfc_generate_ntag213(NfcDeviceData* data) {
nfc_generate_ntag21x_common(data, 45);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeNTAG213;
mful->version.storage_size = 0x0F;
mful->data[14] = 0x12;
// Default contents
memcpy(&mful->data[16], default_data_ntag213, sizeof(default_data_ntag213));
}
static void nfc_generate_ntag215(NfcDeviceData* data) {
nfc_generate_ntag21x_common(data, 135);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeNTAG215;
mful->version.storage_size = 0x11;
mful->data[14] = 0x3E;
// Default contents
memcpy(&mful->data[16], default_data_ntag215_216, sizeof(default_data_ntag215_216));
}
static void nfc_generate_ntag216(NfcDeviceData* data) {
nfc_generate_ntag21x_common(data, 231);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeNTAG216;
mful->version.storage_size = 0x13;
mful->data[14] = 0x6D;
// Default contents
memcpy(&mful->data[16], default_data_ntag215_216, sizeof(default_data_ntag215_216));
}
static void
nfc_generate_ntag_i2c_common(NfcDeviceData* data, MfUltralightType type, uint16_t num_pages) {
nfc_generate_common_start(data);
nfc_generate_mf_ul_common(data);
MfUltralightData* mful = &data->mf_ul_data;
mful->type = type;
memcpy(&mful->version, version_bytes_ntag_i2c, sizeof(version_bytes_ntag_i2c));
mful->data_size = num_pages * 4;
mful->data_read = mful->data_size;
memcpy(mful->data, data->nfc_data.uid, data->nfc_data.uid_len);
mful->data[7] = data->nfc_data.sak;
mful->data[8] = data->nfc_data.atqa[0];
mful->data[9] = data->nfc_data.atqa[1];
uint16_t config_register_page;
uint16_t session_register_page;
// Sync with mifare_ultralight.c
switch(type) {
case MfUltralightTypeNTAGI2C1K:
config_register_page = 227;
session_register_page = 229;
break;
case MfUltralightTypeNTAGI2C2K:
config_register_page = 481;
session_register_page = 483;
break;
case MfUltralightTypeNTAGI2CPlus1K:
case MfUltralightTypeNTAGI2CPlus2K:
config_register_page = 232;
session_register_page = 234;
break;
default:
furi_crash("Unknown MFUL");
break;
}
memcpy(
&mful->data[config_register_page * 4],
default_config_ntag_i2c,
sizeof(default_config_ntag_i2c));
memcpy(
&mful->data[session_register_page * 4],
default_config_ntag_i2c,
sizeof(default_config_ntag_i2c));
}
static void nfc_generate_ntag_i2c_1k(NfcDeviceData* data) {
nfc_generate_ntag_i2c_common(data, MfUltralightTypeNTAGI2C1K, 231);
MfUltralightData* mful = &data->mf_ul_data;
mful->version.prod_ver_minor = 0x01;
mful->version.storage_size = 0x13;
memcpy(&mful->data[12], default_data_ntag_i2c, sizeof(default_data_ntag_i2c));
mful->data[14] = 0x6D; // Size of tag in CC
}
static void nfc_generate_ntag_i2c_2k(NfcDeviceData* data) {
nfc_generate_ntag_i2c_common(data, MfUltralightTypeNTAGI2C2K, 485);
MfUltralightData* mful = &data->mf_ul_data;
mful->version.prod_ver_minor = 0x01;
mful->version.storage_size = 0x15;
memcpy(&mful->data[12], default_data_ntag_i2c, sizeof(default_data_ntag_i2c));
mful->data[14] = 0xEA; // Size of tag in CC
}
static void nfc_generate_ntag_i2c_plus_common(
NfcDeviceData* data,
MfUltralightType type,
uint16_t num_pages) {
nfc_generate_ntag_i2c_common(data, type, num_pages);
MfUltralightData* mful = &data->mf_ul_data;
uint16_t config_index = 227 * 4;
mful->data[config_index + 3] = 0xFF; // AUTH0
memset(&mful->data[config_index + 8], 0xFF, 4); // Default PWD
}
static void nfc_generate_ntag_i2c_plus_1k(NfcDeviceData* data) {
nfc_generate_ntag_i2c_plus_common(data, MfUltralightTypeNTAGI2CPlus1K, 236);
MfUltralightData* mful = &data->mf_ul_data;
mful->version.prod_ver_minor = 0x02;
mful->version.storage_size = 0x13;
}
static void nfc_generate_ntag_i2c_plus_2k(NfcDeviceData* data) {
nfc_generate_ntag_i2c_plus_common(data, MfUltralightTypeNTAGI2CPlus2K, 492);
MfUltralightData* mful = &data->mf_ul_data;
mful->version.prod_ver_minor = 0x02;
mful->version.storage_size = 0x15;
}
void nfc_generate_mf_classic_ext(
NfcDeviceData* data,
uint8_t uid_len,
MfClassicType type,
bool random_uid,
uint8_t* uid) {
nfc_generate_common_start(data);
if(random_uid) {
nfc_generate_mf_classic_uid(data->mf_classic_data.block[0].value, uid_len);
} else {
memcpy(data->mf_classic_data.block[0].value, uid, uid_len);
}
nfc_generate_mf_classic_common(data, uid_len, type);
// Set the UID
if(random_uid) {
data->nfc_data.uid[0] = NXP_MANUFACTURER_ID;
for(int i = 1; i < uid_len; i++) {
data->nfc_data.uid[i] = data->mf_classic_data.block[0].value[i];
}
} else {
for(int i = 0; i < uid_len; i++) {
data->nfc_data.uid[i] = data->mf_classic_data.block[0].value[i];
}
}
MfClassicData* mfc = &data->mf_classic_data;
mf_classic_set_block_read(mfc, 0, &mfc->block[0]);
if(type == MfClassicType4k) {
// Set every block to 0xFF
for(uint16_t i = 1; i < 256; i += 1) {
if(mf_classic_is_sector_trailer(i)) {
nfc_generate_mf_classic_sector_trailer(mfc, i);
} else {
memset(&mfc->block[i].value, 0xFF, 16);
}
mf_classic_set_block_read(mfc, i, &mfc->block[i]);
}
// Set SAK to 18
data->nfc_data.sak = 0x18;
} else if(type == MfClassicType1k) {
// Set every block to 0xFF
for(uint16_t i = 1; i < MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4; i += 1) {
if(mf_classic_is_sector_trailer(i)) {
nfc_generate_mf_classic_sector_trailer(mfc, i);
} else {
memset(&mfc->block[i].value, 0xFF, 16);
}
mf_classic_set_block_read(mfc, i, &mfc->block[i]);
}
// Set SAK to 08
data->nfc_data.sak = 0x08;
} else if(type == MfClassicTypeMini) {
// Set every block to 0xFF
for(uint16_t i = 1; i < MF_MINI_TOTAL_SECTORS_NUM * 4; i += 1) {
if(mf_classic_is_sector_trailer(i)) {
nfc_generate_mf_classic_sector_trailer(mfc, i);
} else {
memset(&mfc->block[i].value, 0xFF, 16);
}
mf_classic_set_block_read(mfc, i, &mfc->block[i]);
}
// Set SAK to 09
data->nfc_data.sak = 0x09;
}
nfc_generate_mf_classic_block_0(
data->mf_classic_data.block[0].value,
uid_len,
data->nfc_data.sak,
data->nfc_data.atqa[0],
data->nfc_data.atqa[1]);
mfc->type = type;
}
void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) {
uint8_t uid = 0;
nfc_generate_mf_classic_ext(data, uid_len, type, true, &uid);
}
static void nfc_generate_mf_mini(NfcDeviceData* data) {
nfc_generate_mf_classic(data, 4, MfClassicTypeMini);
}
static void nfc_generate_mf_classic_1k_4b_uid(NfcDeviceData* data) {
nfc_generate_mf_classic(data, 4, MfClassicType1k);
}
static void nfc_generate_mf_classic_1k_7b_uid(NfcDeviceData* data) {
nfc_generate_mf_classic(data, 7, MfClassicType1k);
}
static void nfc_generate_mf_classic_4k_4b_uid(NfcDeviceData* data) {
nfc_generate_mf_classic(data, 4, MfClassicType4k);
}
static void nfc_generate_mf_classic_4k_7b_uid(NfcDeviceData* data) {
nfc_generate_mf_classic(data, 7, MfClassicType4k);
}
static const NfcGenerator mf_ul_generator = {
.name = "Mifare Ultralight",
.generator_func = nfc_generate_mf_ul_orig,
};
static const NfcGenerator mf_ul_11_generator = {
.name = "Mifare Ultralight EV1 11",
.generator_func = nfc_generate_mf_ul_11,
};
static const NfcGenerator mf_ul_h11_generator = {
.name = "Mifare Ultralight EV1 H11",
.generator_func = nfc_generate_mf_ul_h11,
};
static const NfcGenerator mf_ul_21_generator = {
.name = "Mifare Ultralight EV1 21",
.generator_func = nfc_generate_mf_ul_21,
};
static const NfcGenerator mf_ul_h21_generator = {
.name = "Mifare Ultralight EV1 H21",
.generator_func = nfc_generate_mf_ul_h21,
};
static const NfcGenerator ntag203_generator = {
.name = "NTAG203",
.generator_func = nfc_generate_mf_ul_ntag203,
};
static const NfcGenerator ntag213_generator = {
.name = "NTAG213",
.generator_func = nfc_generate_ntag213,
};
static const NfcGenerator ntag215_generator = {
.name = "NTAG215",
.generator_func = nfc_generate_ntag215,
};
static const NfcGenerator ntag216_generator = {
.name = "NTAG216",
.generator_func = nfc_generate_ntag216,
};
static const NfcGenerator ntag_i2c_1k_generator = {
.name = "NTAG I2C 1k",
.generator_func = nfc_generate_ntag_i2c_1k,
};
static const NfcGenerator ntag_i2c_2k_generator = {
.name = "NTAG I2C 2k",
.generator_func = nfc_generate_ntag_i2c_2k,
};
static const NfcGenerator ntag_i2c_plus_1k_generator = {
.name = "NTAG I2C Plus 1k",
.generator_func = nfc_generate_ntag_i2c_plus_1k,
};
static const NfcGenerator ntag_i2c_plus_2k_generator = {
.name = "NTAG I2C Plus 2k",
.generator_func = nfc_generate_ntag_i2c_plus_2k,
};
static const NfcGenerator mifare_mini_generator = {
.name = "Mifare Mini",
.generator_func = nfc_generate_mf_mini,
};
static const NfcGenerator mifare_classic_1k_4b_uid_generator = {
.name = "Mifare Classic 1k 4byte UID",
.generator_func = nfc_generate_mf_classic_1k_4b_uid,
};
static const NfcGenerator mifare_classic_1k_7b_uid_generator = {
.name = "Mifare Classic 1k 7byte UID",
.generator_func = nfc_generate_mf_classic_1k_7b_uid,
};
static const NfcGenerator mifare_classic_4k_4b_uid_generator = {
.name = "Mifare Classic 4k 4byte UID",
.generator_func = nfc_generate_mf_classic_4k_4b_uid,
};
static const NfcGenerator mifare_classic_4k_7b_uid_generator = {
.name = "Mifare Classic 4k 7byte UID",
.generator_func = nfc_generate_mf_classic_4k_7b_uid,
};
const NfcGenerator* const nfc_generators[] = {
&mf_ul_generator,
&mf_ul_11_generator,
&mf_ul_h11_generator,
&mf_ul_21_generator,
&mf_ul_h21_generator,
&ntag203_generator,
&ntag213_generator,
&ntag215_generator,
&ntag216_generator,
&ntag_i2c_1k_generator,
&ntag_i2c_2k_generator,
&ntag_i2c_plus_1k_generator,
&ntag_i2c_plus_2k_generator,
&mifare_mini_generator,
&mifare_classic_1k_4b_uid_generator,
&mifare_classic_1k_7b_uid_generator,
&mifare_classic_4k_4b_uid_generator,
&mifare_classic_4k_7b_uid_generator,
NULL,
};
-29
View File
@@ -1,29 +0,0 @@
#pragma once
#include "../nfc_device.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*NfcGeneratorFunc)(NfcDeviceData* data);
typedef struct {
const char* name;
NfcGeneratorFunc generator_func;
} NfcGenerator;
extern const NfcGenerator* const nfc_generators[];
void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type);
void nfc_generate_mf_classic_ext(
NfcDeviceData* data,
uint8_t uid_len,
MfClassicType type,
bool random_uid,
uint8_t* uid);
#ifdef __cplusplus
}
#endif

Some files were not shown because too many files have changed in this diff Show More