diff --git a/docs/guide/wrapping-arduino-libraries/README.md b/docs/guide/wrapping-arduino-libraries/README.md index 9625b7da..f03b717b 100644 --- a/docs/guide/wrapping-arduino-libraries/README.md +++ b/docs/guide/wrapping-arduino-libraries/README.md @@ -1,38 +1,42 @@ --- -title: Wrapping Arduino Libraries +title: Wrapping Class-based Arduino Libraries version: 1.0.0 --- -# Wrapping Arduino Libraries +# Wrapping Class-based Arduino Libraries + Many libraries already have been written for Arduino and they can be included into XOD to use the full power of the existing ecosystem. To understand this guide, you have to know how to write -[C++ code in XOD](/docs/guide/nodes-for-xod-in-cpp/) and how to work with -[custom types](/docs/guide/custom-types/). Also, you need to have -some experience of working with C++ libraries for Arduino. +[C++ code in XOD](../../nodes-for-xod-in-cpp/) and how to work with +[custom types](../../custom-types/). Also, you need to have some experience of +working with C++ libraries for Arduino. Imagine that we want our Arduino board to turn the built-in led on or off when we bring an NFC tag, such as travel pass, to it. Consider that we have no XOD library to work with RFID/NFC scanner PN532 -([xod-dev/pn532-nfc](/libs/xod-dev/pn532-nfc)), and try to make it on your own. -In order not to go into the details of working with tags, we will take the -the [Adafruit-PN532](https://github.com/adafruit/Adafruit-PN532) Arduino library -and just wrap it in XOD nodes. +([xod-dev/pn532-nfc](/libs/xod-dev/pn532-nfc)), and try to make it on our own. +In order not to go into the details of working with tags, we will take the the +[Adafruit-PN532](https://github.com/adafruit/Adafruit-PN532) Arduino library and +just wrap it in XOD nodes. To do this, we need to: -1. Declare a new custom type `pn532-device`, which describes an RFIC/NFC module -and how is it connected to an Arduino board. There may be several instances of -this node, one for each hardware module. -2. Declare a dependency on a third-party C++ library so that XOD knows where to -download it, saving users from manual install. -3. Create action nodes for the new type that correspond to the functions -and methods provided by the third-party C++ library. -4. Create a quick-start node that reads an NFC tag to solve most common purposes. -5. Create few example patches. + +1. Declare a new custom type `pn532-device`, which describes an RFIC/NFC module + and how is it connected to an Arduino board. There may be several instances + of this node, one for each hardware module. +2. Declare a dependency on a third-party C++ library so that XOD knows where to + download it, saving users from manual install. +3. Create action nodes for the new type that correspond to the functions and + methods provided by the third-party C++ library. +4. Create a quick-start node that reads an NFC tag to serve most common + purposes. +5. Create few example patches. ## Create device and require library + Let's take a look on class constructors in the Adafruit library: ```cpp @@ -44,24 +48,25 @@ class Adafruit_PN532{ // … }; ``` + The class has three constructors for different connection types: HardwareSPI, SoftwareSPI and HardwareI2C. We'll choose the latest one and create the device node for the I2C connection: -1. Create a new patch "pn532-device". - The name of the patch becomes the name of the new custom type, which we will - later pass into action nodes. - Pay attention to "device" in the name. Conventionally, any nodes that - create a new type to work with hardware should be named as `xxx-device`. -2. Place the node `not-implemented-in-xod`, because we have to create an - instance of the class from C++ library. -3. Place the node `output-self` and set its label to `DEV`. - Such way we’re defining a new custom type. -4. Place one terminal `input-port` to specify interruption port with label `IRQ`. - This one of two ports are required in the constructor arguments. This port - is used to notify Arduino board that the module detected an NFC tag. The second - port (`reset`) we do not need, because it is necessary to restart the module only - if you are working with it at a low level and did something wrong. +1. Create a new patch "pn532-device". The name of the patch becomes the name of + the new custom type, which we will later pass into action nodes. Pay + attention to "device" in the name. Conventionally, any nodes that create a + new type to work with hardware should be named as `xxx-device`. +2. Place the node `not-implemented-in-xod`, because we have to create an + instance of the class from C++ library. +3. Place the node `output-self` and set its label to `DEV`. Such way we’re + defining a new custom type. +4. Place one terminal `input-port` to specify interruption port with label + `IRQ`. This one of two ports are required in the constructor arguments. This + port is used to notify Arduino board that the module detected an NFC tag. + The second port (`reset`) we do not need, because it is necessary to restart + the module only if you are working with it at a low level and did something + wrong. Double click on `not-implemented-in-xod` to open the C++ editor and type on the first line: @@ -77,8 +82,8 @@ master branches of GitHub repositories. If you want to require library from another branch or edited — make a fork and require it. -This is a special line tells XOD, that this node need a third-party library. -At the first compilation XOD will check its presence in your workspace and if it +This is a special line tells XOD, that this node needs a third-party library. At +the first compilation XOD will check its presence in your workspace and if it does not find a library, it will offer to download and install it just by clicking on the button in the IDE. @@ -87,8 +92,8 @@ clicking on the button in the IDE. After installation, you will need to run the compilation again. -So we installed library and now we are able to use it. -Let's include it and create an instance of the class: +So we installed library and now we are able to use it. Let's include it and +create an instance of the class: ```cpp // Tell XOD where it could download the library: @@ -113,9 +118,9 @@ using Type = Adafruit_PN532*; {{ GENERATED_CODE }} void evaluate(Context ctx) { - // It should be evaluated only once on the first (setting up) transaction - // to avoid memory leaks - if (!isSettingUp()) return; + // It should be evaluated only once on the first (setup) transaction + if (!isSettingUp()) + return; auto state = getState(ctx); auto irq = getValue(ctx); @@ -128,36 +133,39 @@ void evaluate(Context ctx) { } ``` -We included the library and created an instance of the class. It remains to -initialize the NFC scanner and start working with it. To do this, we need to -create action nodes. +We included the library and created the instance of the class. Let's create +action nodes to initialize the NFC scanner and start working with it. ## Action nodes To work with the instance of a class in XOD we need to wrap method calls in -nodes, and pass the class inside as a just created custom type. Thus, any action -node for this library will contain input of type `pn532-device`. +nodes. To access the instance itself we pass it the custom type value we defined +earlier. Thus, any action node for this library will contain an input of type +`pn532-device`. -Actually, we deal not with just a custom type, but we deal with the class, that -do some side-effects (communicating with hardware module) and this actions could -be an asynchronous (it means our program won't halt and wait until some -side-effect is done). Therefore, for each such action, we have to add some -`pulse` terminals: one to run action and two to notify about a completion -(successful or failed). +The methods can invoke some side-effects (communication with the hardware +module) and be asynchronous, that is our program won't halt and wait until some +side-effect are done. Therefore, for each such action node, we have to add some +`pulse` terminals: one to run the action and two to notify about completion, +either successful or failed. -For our task we have to create two action nodes: -1. `init` — to initialize hardware module -2. `pair-tag` — to detect an NFC tag and read its UID +For our task we create two action nodes: + +1. `init` — to initialize the hardware module +2. `pair-tag` — to detect an NFC tag and read its UID
Note -Pay attention, that names of action nodes begin with verbs. By convention, -names of any nodes which do instructions "what to do" in imperative style -must begin with a verb (`init`, `read-byte`, `pair-tag`, `write-line` and etc). + +Pay attention, that names of action nodes begin with verbs. By convention, names +of any nodes which do instructions "what to do" in imperative style must begin +with a verb (`init`, `read-byte`, `pair-tag`, `write-line` and etc). +
### Create node `init` -Let's start by creating a node that initializes the NFC scanner. + +Let's create a node that initializes the NFC scanner. ![Create init patch](./init.patch.png) @@ -174,7 +182,7 @@ void evaluate(Context ctx) { if (!isInputDirty(ctx)) return; - // Get our custom type, that is a pointer on the `Adafruit_PN532` class instance + // Get a pointer to the `Adafruit_PN532` class instance auto nfc = getValue(ctx); // Initialize RFID/NFC module @@ -188,8 +196,8 @@ void evaluate(Context ctx) { return; } - // Set the max number of retry attempts to read from a card - // This prevents us from waiting forever for a card, which is + // Set the max number of retry attempts to read from a tag + // This prevents us from waiting forever for a tag, which is // the default behavior of the PN532. nfc->setPassiveActivationRetries(1); @@ -201,29 +209,28 @@ void evaluate(Context ctx) { } ``` -Now we can initialize RFID/NFC module. -On the next step we'll prepare everything for reading an UID and compare it with -the UID of our NFC tag. And then create a node that will read an UID. +Now we can initialize the RFID/NFC module.
Note -Do not forget to give [descriptions](/docs/guide/documenting-nodes/) to -terminals and patches. + +Do not forget to give [descriptions](../../documenting-nodes/) to terminals and +patches. +
### Storing and comparing UIDs + The UID is a set of bytes, which may be sized from 4 to 10 bytes for different types of cards and different types of UID (Single size UID, Double size UID, -RUID, NUID, FNUID) by the specification ISO14443A. -For reliability, let's pack this value into another custom data type that we -have to create now. +RUID, NUID, FNUID) by the specification ISO14443A. For reliability, let's pack +this value into another custom data type. -Create a new patch `nfc-uid`: -![Create nfc-uid type](./nfc-uid.patch.png) +Create a new patch `nfc-uid`: ![Create nfc-uid type](./nfc-uid.patch.png) Note that here we have 7 inputs of type `byte` so that we can manually set the -UID of an NFC tag. This will be useful when we'll compare the UID of the -detected tag and the UID of our activation tag. +UID of an NFC tag. This will be useful when we'll compare a UID of the detected +tag and the UID of our activation tag. Let's write C++ code: @@ -231,7 +238,7 @@ Let's write C++ code: struct State { }; -// Declare out custom type as a struct, +// Declare custom type as a struct // in which we will store an array of bytes struct Type { uint8_t items[7]; @@ -255,23 +262,27 @@ void evaluate(Context ctx) { emitValue(ctx, uid); } ``` -In the likeness, we can make another node, which unfolds the UID into a set of -bytes with seven outputs from the bottom (`unpack-nfc-uid` is a good name for it). -This can be useful if we want to compare, for example, specific bytes after -reading the UID. For example, Double size UID contains the UID manufacturer at -the zero position. - -For our task is important to compare the UID of detected tag with the UID of our -tag (we don't want anyone to turn our led on and off, right?) -Let's create a new node `equal(nfc-uid)`. Note that we defined our data type -`nfc-uid` in the parentheses. It will be a -[specialization](/docs/guide/creating-generics/#specialization-patches) node for -comparing UIDs. In that way, any User can use familiar to him `xod/core/equal` -node even to compare UIDs. + +
+Note + +Likewise, we can make another node, which unfolds the UID into a set of bytes +with seven outputs from the bottom (`unpack-nfc-uid` is a good name for it). +This can be useful if we want to compare specific bytes after reading the UID. +For example, Double size UID contains a manufacturer ID at the zero position. + +
+ +For our task it is important to compare a UID of the detected tag with the UID +of our tag: we don't want anyone to turn our led on and off, right? Let's create +a new node `equal(nfc-uid)`. Note that we defined our data type `nfc-uid` in the +parentheses. It is a +[specialization](../../creating-generics/#specialization-patches) node, so any +xoder can use the familiar `xod/core/equal` node even to compare UIDs. ![Equal node for nfc-uid type](./equal-nfc-uid.patch.png) -To compare two byte array we'll use the built-in function `memcmp`: +To compare two byte arrays we use the standard function `memcmp`: ```cpp struct State { @@ -291,24 +302,17 @@ void evaluate(Context ctx) { } ``` -Let's check that everything is working and at the same time create a -demonstration patch: `example-uid-equals`. - -
-Note -Creating example patches within the library is a good practice. It allows you -to immediately check the workability of the library, check its usability and -in the future will be a great example of how to use the library. -
+Let's check that everything works. Create a demonstration patch +`example-uid-equals`. ![Example for equal node](./example-uid-eq.patch.png) -Now we can create, store and compare UIDs. It's time to read the UID from our +Now we can create, store, and compare UIDs. It's time to read the UID from our NFC tag. -### Create a node `pair-tag` +### Create node `pair-tag` -To interact with NFC tags we have to detect it first and read its UID. That is +To interact with an NFC tag we should detect it first and read its UID. That is why the node is not called `read-uid`, but `pair-tag`. ![Pair-tag node](./pair-tag.patch.png) @@ -332,8 +336,8 @@ void evaluate(Context ctx) { // Create a variable to store length of the UID uint8_t uidLength; - // Replace UID with zeros - memset(uid.items, 0, sizeof(uid)); + // Fill UID with zeroes + memset(uid.items, 0, sizeof(uid.items)); // Detect the tag and read the UID bool res = nfc->readPassiveTargetID(PN532_MIFARE_ISO14443A, uid.items, &uidLength); @@ -348,62 +352,63 @@ void evaluate(Context ctx) { Everything is ready to read the UID of the tag. But in fact, the library from Adafruit allows us to read not only the UID of the tag but also to read and -write data to the tag. And if you're wrapping on a library, we recommend -wrapping around at least the most common methods to avoid having multiple -wrappers over the same library that only have a limited set of features. +write data to the tag. And if you're wrapping a library, we recommend wrapping +at least the most common methods to avoid having multiple wrappers of the same +library that only have a limited set of features. -Try to make `read-page` and `write-page` nodes yourself using the +Try to make `read-page` and `write-page` nodes by yourself using the `mifareultralight_ReadPage` and `mifareultralight_WritePage` methods from the -Adafruit library. And make an example patch on which count the number of times -the tag is touched the NFC scanner, keeping this counter on the tag (you will -need the MIFARE Ultralight labels to work with these methods). +Adafruit library. And make an example patch to count the number of times the tag +has touched the NFC scanner, keeping this counter on the tag. You will need the +MIFARE Ultralight labels to work with these methods. ## Quick start node -After you have done the previous steps, it may seem that this step is optional -because you already know how the NFC scanner works, you know how to get the -desired data to make your idea work. +We could stop right here. But let's make yet another thing: a quick start node. +Imagine, this library was done by someone else and you just want to use it. Will +it be handy to use a chain of nodes `pn532-device`, `init`, `read-uid`, just to +know is there any NFC tag near the module? -But let's imagine that this library was done by someone else, and you just want -to use it. Will it be handy to use a chain of nodes `pn532-device`, `init`, -`read-uid`, just to know is there any NFC tag near the module? - -Let's simplify the life of both ourselves and the library's consumers, and write -a simple `nfc-scanner` that solves most simple tasks with just one node. -Such nodes are called quick start nodes. +Let's simplify our lives and write a `nfc-scanner` node that solves most common +tasks with just one node. Such nodes are called _quick start nodes_. ![Quick start node "nfc-scanner"](./nfc-scanner.patch.png) -*Footnotes:* -*[1] `flip-flop` is used to trigger `INIT` only once* -*[2] open the `gate` to trigger `READ` on every next trigger of the `SCAN`* +1. `flip-flop` is used to trigger `INIT` only once; +2. Open the `gate` to trigger `READ` on each subsequent pulse on the `SCAN`. -It's time to do our `example-nfc-scanner`: +It's time to make our `example-nfc-scanner`: ![nfc-scanner example](./example-nfc-scanner.patch.png) -Well done! -
Note -Now you can [add project description and share it](/docs/guide/creating-libraries/#setting-metadata) -with the community. + +Creating example patches within the library is a good practice. It allows you to +immediately check the workability and usability of the library. In the future +users will thank you for examples. +
+Well done! + ## Summary -1. To use a third-party library just specify a special pragma-instruction -in the code: -`#pragma XOD require "https://github.com/some/library"` -2. In addition to specifying where to get the library, do not forget to include -it in the code: + +1. To use a third-party library specify a special pragma-instruction in the + code: `#pragma XOD require "https://github.com/some/library"` +2. In addition to specifying where to get the library, do not forget to include + it in the code: ```cpp {{#global}} #include {{/global}} ``` -3. When you wrapping methods in nodes use verbs in their names -(`pair-tag`, `write-page`). -5. Create simple patch nodes (quick start nodes) to quickly solve common -problems (`nfc-scanner`, `nfc-writer`) -6. [Share](/docs/guide/creating-libraries/) your wrappers over C++ libraries. + +3. When you wrapping methods in nodes use verbs in their names (`pair-tag`, + `write-page`). +4. Create quick start nodes to solve common problems (`nfc-scanner`, + `nfc-writer`) + +Now you can [add project description and share it](../../creating-libraries/) +with the community. diff --git a/docs/guide/wrapping-arduino-libraries/RU.md b/docs/guide/wrapping-arduino-libraries/RU.md index 52028428..3d9ce89e 100644 --- a/docs/guide/wrapping-arduino-libraries/RU.md +++ b/docs/guide/wrapping-arduino-libraries/RU.md @@ -1,40 +1,45 @@ --- -title: Обертывание Arduino Библиотек +title: Создание оберток объектных Arduino-библиотек version: 1.0.0 --- -# Обертывание Arduino Библиотек +# Создание оберток объектных Arduino-библиотек + Для Arduino написано уже множество библиотек и их можно подключать в XOD и использовать всю мощь существующей экосистемы. -Чтобы понять это руководство, вы должны знать как работать с [кастомными типами](/docs/guide/custom-types/) -и как писать [C++ код в XOD](/docs/guide/nodes-for-xod-in-cpp/), и иметь хотя бы -небольшой опыт работы с C++ библиотеками. +Чтобы понять это руководство, вы должны знать как работать с +[кастомными типами](../../custom-types/) и как писать +[C++ код в XOD](../../nodes-for-xod-in-cpp/), и иметь хотя бы небольшой опыт +работы с C++ библиотеками. -Представим, что мы хотим чтобы наша плата Arduino включала или выключала built-in -светодиод, когда мы подносим к ней NFC-метку (наш проездной, например). +Представим, что мы хотим чтобы наша плата Arduino включала или выключала +built-in светодиод, когда мы подносим к ней NFC-метку (наш проездной, например). Давайте представим, что у нас нет XOD-библиотеки для работы с RFID/NFC сканером PN532 (`xod-dev/pn532-nfc`) и попробуем ее сделать. Чтобы не вдаваться в подробности работы с метками мы возьмем Arduino-библиотеку -[Adafruit-PN532](https://github.com/adafruit/Adafruit-PN532) и просто обернем -ее в XOD ноды. +[Adafruit-PN532](https://github.com/adafruit/Adafruit-PN532) и просто обернем ее +в XOD ноды. Для этого нам потребуется: -1. Объявить новый кастомный тип `pn532-device`, который описывает RFID/NFC модуль -и как он подключен к Arduino. Экземпляров такой ноды может быть много, по одному -экземпляру на каждый физический модуль. -2. Заявить зависимость от сторонней C++ библиотеки, чтобы XOD знал откуда её -можно скачать и пользователям библиотеки не пришлось бы делать это вручную -2. Создать ноды-действия для этого типа, которые соответствуют тем функциям и -методам, которые предоставляет сторонняя C++ библиотека. -3. Создать упрощенную ноду чтения метки, для быстрого решения наиболее частых -задач, стоящих перед RFID/NFC сканером. -4. Создать несколько патчей-примеров. + +1. Объявить новый кастомный тип `pn532-device`, который описывает RFID/NFC + модуль и как он подключен к Arduino. Экземпляров такой ноды может быть + много, по одному экземпляру на каждый физический модуль. +2. Заявить зависимость от сторонней C++ библиотеки, чтобы XOD знал откуда её + можно скачать и пользователям библиотеки не пришлось бы делать это вручную +3. Создать ноды-действия для этого типа, которые соответствуют тем функциям и + методам, которые предоставляет сторонняя C++ библиотека. +4. Создать упрощенную ноду чтения метки, для быстрого решения наиболее частых + задач, стоящих перед RFID/NFC сканером. +5. Создать несколько патчей-примеров. ## Создаем девайс и подключаем библиотеку + Давайте взглянем на библиотеку от Adafruit. И в первую очередь нас интересуют конструкторы класса: + ```cpp class Adafruit_PN532{ public: @@ -44,51 +49,56 @@ class Adafruit_PN532{ // … }; ``` + Она имеет три конструктора для разных способов подключения: HardwareSPI, -SoftwareSPI и HardwareI2C. -Давайте остановимся на последнем и создадим девайс для этого типа подключения: - -1. Создадим новый патч "pn532-device". -Название патча станет названием нового кастомного типа, который мы будем -передавать в ноды-действия. -Обратите внимание на **device** в названии. По конвенции, любые ноды, которые -создают новый тип данных для работы с устройствами, мы называем `xxx-device`. -2. Поставим ноду `not-implemented-in-xod`, т.к. нам потребуется создать -экземпляр класса из C++ библиотеки. -3. Поставим ноду `output-self`, задав ей label: `DEV` -Благодаря этому особому терминалу мы объявим [кастомный тип](/docs/guide/custom-types/). -4. Поставим один терминал `input-port` для указания порта прерывания: `IRQ`. -Это один из двух портов требуемых в конструкторе класса. По нему модуль будет -сообщать Arduino что обнаружена карта. Второй пин (reset) нам не потребуется, -т.к. Он нужен для перезагрузки модуля в случае если вы работаете с ним на низком -уровне и что-то сделали не так. За нас все это делает проверенная библиотека, -так что перезагружать модуль нам не придется. +SoftwareSPI и HardwareI2C. Давайте остановимся на последнем и создадим девайс +для этого типа подключения: + +1. Создадим новый патч "pn532-device". Название патча станет названием нового + кастомного типа, который мы будем передавать в ноды-действия. Обратите + внимание на **device** в названии. По конвенции, любые ноды, которые создают + новый тип данных для работы с устройствами, мы называем `xxx-device`. +2. Поставим ноду `not-implemented-in-xod`, т.к. нам потребуется создать + экземпляр класса из C++ библиотеки. +3. Поставим ноду `output-self`, задав ей label: `DEV` Благодаря этому особому + терминалу мы объявим [кастомный тип](../../custom-types/). +4. Поставим один терминал `input-port` для указания порта прерывания: `IRQ`. + Это один из двух портов требуемых в конструкторе класса. По нему модуль + будет сообщать Arduino что обнаружена карта. Второй пин (reset) нам не + потребуется, т.к. Он нужен для перезагрузки модуля в случае если вы + работаете с ним на низком уровне и что-то сделали не так. За нас все это + делает проверенная библиотека, так что перезагружать модуль нам не придется. Откроем редактор C++ кода и напишем на первой строчке: + ```cpp #pragma XOR require "https://github.com/adafruit/Adafruit-PN532" ```
Note -В данный момент подключение сторонних библиотек возможно только с GitHub -из master-ветки. Если вы хотите подключить библиотеку из другой ветки или с + +В данный момент подключение сторонних библиотек возможно только с GitHub из +master-ветки. Если вы хотите подключить библиотеку из другой ветки или с правками — сделайте fork и подключайте его. +
-Это особая строка, сообщающая XOD-у, что этой ноде потребуется сторонняя -C++ библиотека. -При первой же компиляции XOD проверит ее наличие в вашем workspace и если не -найдет ее, то предложит скачать и установить ее просто нажав на кнопку -в самой IDE. +Это особая строка, сообщающая XOD-у, что этой ноде потребуется сторонняя C++ +библиотека. При первой же компиляции XOD проверит ее наличие в вашем workspace и +если не найдет ее, то предложит скачать и установить ее просто нажав на кнопку в +самой IDE.
Note + После установки нужно будет запустить компиляцию еще раз. +
-Таким образом мы установим библиотеку и теперь сможем ей пользоваться. -Давайте подключим её и создадим экземпляр класса: +Таким образом мы установим библиотеку и теперь сможем ей пользоваться. Давайте +подключим её и создадим экземпляр класса: + ```cpp // Укажем откуда взять библиотеку: #pragma XOD require "https://github.com/adafruit/Adafruit-PN532" @@ -112,6 +122,10 @@ using Type = Adafruit_PN532*; {{ GENERATED_CODE }} void evaluate(Context ctx) { + // Функция должна исполниться один раз на первой (setup) транзакции + if (!isSettingUp()) + return; + auto state = getState(ctx); auto irq = getValue(ctx); @@ -130,20 +144,22 @@ NFC сканер и начать работать с ним. Для этого ноды-действия. Приступим. ## Ноды-действия + Чтобы работать с экземпляром класса в XOD мы должны обернуть вызовы его методов в ноды, а сам класс, с которым предстоит работать, передавать в виде созданного нами кастомного типа. Таким образом, любая нода-действие для этой библиотеки будет содержать вход типа `pn532-device`. -На деле же, мы имеем дело не просто с кастомным типом, а с классом который -совершает различные сайд-эффекты (общается с железкой) и эти действия могут быть -асинхронными. -Поэтому для каждого такого действия нам потребуются еще pulse terminals, для -запуска действия и для оповещении о завершении (успешном или провальном). +Методы класса могут совершать различные сайд-эффекты (общаение с железкой) и +быть асинхронными. Это значит, что наша программа не должна остановиться и ждать +пока этот сайд-эффект не будет выполнен. Поэтому для каждого такого действия нам +потребуются еще pulse терминалы, для запуска действия и для оповещении о +завершении, успешном или провальном. Для нашей задачи нам потребуется создать две ноды-действия: -1. `init` — инициализирует работу модуля -2. `pair-tag` — обнаружит метку и считает ее UID + +1. `init` — инициализирует работу модуля +2. `pair-tag` — обнаружит метку и считает ее UID
Note @@ -159,6 +175,7 @@ NFC сканер и начать работать с ним. Для этого ![Создаем ноду init](./init.patch.png) Перейдем к C++: + ```cpp struct State { }; @@ -199,29 +216,33 @@ void evaluate(Context ctx) { } ``` -Теперь мы можем инициализировать работу NFC сканера. -Далее мы подготовим все для чтения UID и его сравнения с нашей меткой, а затем -создадим ноду для чтения метки. +Теперь мы можем инициализировать работу NFC сканера. Далее мы подготовим все для +чтения UID и его сравнения с нашей меткой, а затем создадим ноду для чтения +метки.
Note -Не забывайте давать терминалам и патчам [описание](/docs/guide/documenting-nodes/). + +Не забывайте давать терминалам и патчам [описание](../../documenting-nodes/). +
### Хранение и сравнение UID + Т.к. UID метки это набор байтов, который по спецификации ISO14443A может быть размером от 4 до 10 байт для разных типов карт и разных видов UID (Single size UID, Double size UID, Triple size UID, RUID, NUID, FNUID), то для надежности -давайте упакуем это значение в специальный тип данных, который мы сейчас создадим. +давайте упакуем это значение в специальный тип данных, который мы сейчас +создадим. -Создадим патч `nfc-uid`: -![Новый тип nfc-uid](./nfc-uid.patch.png) +Создадим патч `nfc-uid`: ![Новый тип nfc-uid](./nfc-uid.patch.png) Обратите внимание, что здесь у нас есть 7 входов типа `byte`, чтобы мы могли вручную задать UID нашей метки. Это нам пригодится далее, когда мы будем сравнивать UID прочитанной карты с UID нашей карты активации. Перейдем к коду: + ```cpp struct State { }; @@ -254,19 +275,21 @@ void evaluate(Context ctx) { По подобию мы можем сделать ноду, которая "развернет" UID на набор байтов с семью выходами снизу (`unpack-nfc-uid` отличное название для нее). Это может быть полезно если мы захотим сравнивать, например, конкретные байты после -прочтения карты. Так, например, Double size UID содержит UID производителя -на 0 позиции. +прочтения карты. Так, например, Double size UID содержит ID производителя на 0 +позиции. Для нашей задачи важно сравнить UID поднесенной метки с UID нашей метки (мы ведь не хотим чтобы кто попало включал и выключал наш светодиод). Давайте создадим ноду `equal(nfc-uid)`. Обратите внимание, что в скбоках мы указали наш тип -данных, это будет [специализация](/docs/guide/creating-generics/#specialization-patches) -именно для сравнения UID. Таким образом пользователь сможет не задумываться и -использовать привычную ноду `xod/core/equal` для сравнения UID меток. +данных, это будет +[специализация](../../creating-generics/#specialization-patches) именно для +сравнения UID. Таким образом пользователь сможет не задумываться и использовать +привычную ноду `xod/core/equal` для сравнения UID меток. ![Нода equal для nfc-uid](./equal-nfc-uid.patch.png) Для сравнения двух массивов мы воспользуемся встроенной функцией `memcmp`: + ```cpp struct State { }; @@ -288,25 +311,20 @@ void evaluate(Context ctx) { Давайте проверим что все работает и заодно создадим демонстрационный патч: `example-uid-equals`. -
-Note -Создание патчей-примеров в рамках библиотеки это отличная практика. Она -позволяет сразу же проверить работоспособность библиотеки, проверить удобство ее -использования и в будущем станет отличным примером как пользоваться библиотекой. -
- ![Патч-пример example-uid-equals](./example-uid-eq.patch.png) Теперь мы можем создавать и хранить UID и сравнивать их между собой. Пришло время прочитать UID нашей NFC-метки. ### Создадим ноду `pair-tag` + Для того чтобы взаимодействовать с метками — нужно сначала обнаружить карту и прочитать её UID. Именно поэтому нода называется не `read-uid`, а `pair-tag`. ![Pair-tag нода](./pair-tag.patch.png) Перейдем к C++: + ```cpp struct State { }; @@ -343,8 +361,8 @@ void evaluate(Context ctx) { позволяет нам читать не только UID метки, но и считывать и записывать данные на метку. И если вы делаете обертку над библиотекой, то мы рекомендуем обернуть хотя бы самые распространенные методы, чтобы избежать появления множества -оберток над одной и той же библиотекой, которые имеют только ограниченный -набор возможностей. +оберток над одной и той же библиотекой, которые имеют только ограниченный набор +возможностей. Попробуйте самостоятельно сделать ноды `read-page` и `write-page`, используя методы `mifareultralight_ReadPage` и `mifareultralight_WritePage` из библиотеки @@ -353,19 +371,16 @@ Adafruit. И сделайте example patch, на котором будете с вам потребуются метки Mifare Ultralight). ## Быстрая нода -После того как вы проделали предыдущие шаги вам может показаться, что этот шаг -необязательный, ведь вы уже знаете как работает NFC сканер, знаете как получить -желаемые данные для того чтобы ваша задумка заработала. -Но давайте представим, что эту библиотеку делал кто-то другой, а вы хотите ей -лишь воспользоваться. Удобно ли вам было бы использовать целую цепочку -из нод `pn532-device`, `init`, `read-uid`, чтобы просто узнать поднесена ли -к модулю NFC-метка? +На этом мы могли бы закончить. Но давайте сделаем еще одну вещь: быструю ноду. +Представьте, что эту библиотеку делал кто-то другой, а вы хотите ей лишь +воспользоваться. Удобно ли вам было бы использовать целую цепочку из нод +`pn532-device`, `init`, `read-uid`, чтобы просто узнать поднесена ли к модулю +NFC-метка? -Давайте упростим жизнь и себе, и потребителям библиотеки, и напишем -простой `nfc-scanner`, который решит большинство простых задач с помощью -всего одной ноды. -Такие ноды называются быстрыми (quick start nodes). +Давайте упростим жизнь и себе, и потребителям библиотеки, и напишем простой +`nfc-scanner`, который решит большинство простых задач с помощью всего одной +ноды. Такие ноды называются быстрыми (quick start nodes). ![Быстрая нода nfc-scanner](./nfc-scanner.patch.png) @@ -373,23 +388,35 @@ Adafruit. И сделайте example patch, на котором будете с ![Пример использования nfc-scanner](./example-nfc-scanner.patch.png) -Всё готово и работает! -
Note -Теперь можно [добавить описание проекта и поделиться им](/docs/guide/creating-libraries/#setting-metadata) -с сообществом. + +Создание патчей-примеров в рамках библиотеки это отличная практика. Она +позволяет сразу же проверить работоспособность библиотеки, проверить удобство ее +использования и в будущем станет отличным примером как пользоваться библиотекой. +
+Всё готово и работает! + ## Подведем итог -1. Чтобы подключить стороннюю библиотеку, укажите в коде специальную pragma-инструкцию: -`#pragma XOR require "https://github.com/some/library"` -2. Кроме указания откуда взять библиотеку, нужно не забыть подключить ее в коде: + +1. Чтобы подключить стороннюю библиотеку, укажите в коде специальную + pragma-инструкцию: `#pragma XOR require "https://github.com/some/library"` +2. Кроме указания откуда взять библиотеку, нужно не забыть подключить ее в + коде: + ```cpp {{#global}} #include {{/global}} ``` -4. Оборачивая методы в ноды используйте в их названии глаголы (`pair-tag`, `write-page`). -5. Создавайте простые патч-ноды для быстрого решения стандартных задач (`nfc-scanner`, `nfc-writer`) -6. [Делитесь](/docs/guide/creating-libraries/) своими обертками над библиотеками. + +4. Оборачивая методы в ноды используйте в их названии глаголы (`pair-tag`, + `write-page`). +5. Создавайте простые патч-ноды для быстрого решения стандартных задач + (`nfc-scanner`, `nfc-writer`) + +Теперь осталось +[добавить описание проекта и поделиться им](../../creating-libraries/) с +сообществом. diff --git a/docs/guide/wrapping-arduino-libraries/example-uid-eq.patch.png b/docs/guide/wrapping-arduino-libraries/example-uid-eq.patch.png index 80033593..09d45902 100644 Binary files a/docs/guide/wrapping-arduino-libraries/example-uid-eq.patch.png and b/docs/guide/wrapping-arduino-libraries/example-uid-eq.patch.png differ diff --git a/docs/guide/wrapping-arduino-libraries/nfc-scanner.patch.png b/docs/guide/wrapping-arduino-libraries/nfc-scanner.patch.png index 632f252b..99db2093 100644 Binary files a/docs/guide/wrapping-arduino-libraries/nfc-scanner.patch.png and b/docs/guide/wrapping-arduino-libraries/nfc-scanner.patch.png differ diff --git a/docs/guide/wrapping-arduino-libraries/pn532-nfc.xodball b/docs/guide/wrapping-arduino-libraries/pn532-nfc.xodball index 1bb7b707..c8418a96 100644 --- a/docs/guide/wrapping-arduino-libraries/pn532-nfc.xodball +++ b/docs/guide/wrapping-arduino-libraries/pn532-nfc.xodball @@ -721,11 +721,11 @@ }, "@/nfc-scanner": { "comments": { - "H139Wm4dQ": { - "content": "<- [1]", - "id": "H139Wm4dQ", + "BJpf6LB_Q": { + "content": "<----[1]", + "id": "BJpf6LB_Q", "position": { - "x": 170, + "x": 68, "y": 102 }, "size": { @@ -733,29 +733,41 @@ "width": 68 } }, - "SJ9PmmEdX": { - "content": "<- [2]", - "id": "SJ9PmmEdX", + "H16jn8BOm": { + "content": "<----[3]", + "id": "H16jn8BOm", "position": { - "x": 170, + "x": 238, "y": 204 }, "size": { "height": 51, "width": 68 } + }, + "SJjnnUrum": { + "content": "[2]---->", + "id": "SJjnnUrum", + "position": { + "x": -102, + "y": 306 + }, + "size": { + "height": 51, + "width": 68 + } } }, "links": { - "B1evCGm4u7": { - "id": "B1evCGm4u7", + "B1zCBn8rdQ": { + "id": "B1zCBn8rdQ", "input": { - "nodeId": "rJPRG74d7", - "pinKey": "__in__" + "nodeId": "HyGBn8Bum", + "pinKey": "B1P1nFwaM" }, "output": { - "nodeId": "HJHYZXVdX", - "pinKey": "BJ25Rf4u7" + "nodeId": "SyZRSh8BOX", + "pinKey": "__out__" } }, "BJ9XVQ4dQ": { @@ -769,37 +781,15 @@ "pinKey": "H1oXb74O7" } }, - "BJD5ZQNd7": { - "id": "BJD5ZQNd7", + "BJdAsIS_7": { + "id": "BJdAsIS_7", "input": { "nodeId": "HysKZmV_7", "pinKey": "rJTxhzN_7" }, "output": { - "nodeId": "S1VqW7Ed7", - "pinKey": "HkyxURuSPyW" - } - }, - "BJhTf7EOX": { - "id": "BJhTf7EOX", - "input": { - "nodeId": "r1Wdf74u7", - "pinKey": "SJ-1mZPTz" - }, - "output": { - "nodeId": "ryaU-XVd7", - "pinKey": "__out__" - } - }, - "Bk66GXNOQ": { - "id": "Bk66GXNOQ", - "input": { - "nodeId": "r1Wdf74u7", - "pinKey": "B1P1nFwaM" - }, - "output": { - "nodeId": "S1VqW7Ed7", - "pinKey": "HkyxURuSPyW" + "nodeId": "BJP0sIH_m", + "pinKey": "ryVmUAOrvkb" } }, "ByIFZ7V_X": { @@ -813,37 +803,37 @@ "pinKey": "__out__" } }, - "H1x-wm74dm": { - "id": "H1x-wm74dm", + "H1AvhIBOX": { + "id": "H1AvhIBOX", "input": { "nodeId": "HysKZmV_7", "pinKey": "ryAsCfEuX" }, "output": { - "nodeId": "Hk-wmQV_m", - "pinKey": "__out__" + "nodeId": "HJHYZXVdX", + "pinKey": "BJ25Rf4u7" } }, - "HJzQrNmVdX": { - "id": "HJzQrNmVdX", + "HkLH3ISu7": { + "id": "HkLH3ISu7", "input": { - "nodeId": "Sk0gMX4dQ", - "pinKey": "ryv7IRdSP1b" + "nodeId": "HyGBn8Bum", + "pinKey": "SJ-1mZPTz" }, "output": { - "nodeId": "BJ-XrVXEd7", + "nodeId": "ryaU-XVd7", "pinKey": "__out__" } }, - "Hk0SmQ4OX": { - "id": "Hk0SmQ4OX", + "Hy2FjIru7": { + "id": "Hy2FjIru7", "input": { - "nodeId": "rJDHX7Vu7", - "pinKey": "ByU7LRuSPkW" + "nodeId": "Sk0gMX4dQ", + "pinKey": "ryv7IRdSP1b" }, "output": { - "nodeId": "r1Wdf74u7", - "pinKey": "OkPg7GDaW" + "nodeId": "r1Mpb7NOQ", + "pinKey": "BydV-mNdQ" } }, "SJOQEXEdm": { @@ -868,28 +858,6 @@ "pinKey": "BydV-mNdQ" } }, - "SJnBQQ4_m": { - "id": "SJnBQQ4_m", - "input": { - "nodeId": "rJDHX7Vu7", - "pinKey": "ryv7IRdSP1b" - }, - "output": { - "nodeId": "HysKZmV_7", - "pinKey": "rJYraMEdX" - } - }, - "SJxQPXQEOX": { - "id": "SJxQPXQEOX", - "input": { - "nodeId": "r1Mpb7NOQ", - "pinKey": "HJqG-m4dQ" - }, - "output": { - "nodeId": "BJXvmmNOX", - "pinKey": "__out__" - } - }, "Sy4QVmV_X": { "id": "Sy4QVmV_X", "input": { @@ -901,15 +869,15 @@ "pinKey": "BJE4WX4u7" } }, - "Syrc-Q4OX": { - "id": "Syrc-Q4OX", + "SylCS28S_m": { + "id": "SylCS28S_m", "input": { - "nodeId": "S1VqW7Ed7", - "pinKey": "Bkh8A_Sv1-" + "nodeId": "By0Hh8SOX", + "pinKey": "__in__" }, "output": { - "nodeId": "ryaU-XVd7", - "pinKey": "__out__" + "nodeId": "S1i4nLHdm", + "pinKey": "HkyxURuSPyW" } }, "SyvxGm4dQ": { @@ -923,26 +891,26 @@ "pinKey": "HkyxURuSPyW" } }, - "r1Q7EmN_Q": { - "id": "r1Q7EmN_Q", + "rJeJ9i8SOm": { + "id": "rJeJ9i8SOm", "input": { "nodeId": "Sk0gMX4dQ", "pinKey": "ByU7LRuSPkW" }, "output": { - "nodeId": "r1Mpb7NOQ", - "pinKey": "BydV-mNdQ" + "nodeId": "rkJcjISOm", + "pinKey": "__out__" } }, - "r1bI7XNdX": { - "id": "r1bI7XNdX", + "rJwr3Ur_m": { + "id": "rJwr3Ur_m", "input": { "nodeId": "r1Mpb7NOQ", "pinKey": "H1M7bmNdX" }, "output": { - "nodeId": "rJDHX7Vu7", - "pinKey": "ByHmL0uHPk-" + "nodeId": "HyGBn8Bum", + "pinKey": "OkPg7GDaW" } }, "rJxZMmVO7": { @@ -956,6 +924,17 @@ "pinKey": "ByHmL0uHPk-" } }, + "rkkS3UHOm": { + "id": "rkkS3UHOm", + "input": { + "nodeId": "S1i4nLHdm", + "pinKey": "Bkh8A_Sv1-" + }, + "output": { + "nodeId": "HysKZmV_7", + "pinKey": "rJYraMEdX" + } + }, "rkl7H4Q4dX": { "id": "rkl7H4Q4dX", "input": { @@ -966,33 +945,34 @@ "nodeId": "HysKZmV_7", "pinKey": "S118pGVOX" } + }, + "ryoO3ISum": { + "id": "ryoO3ISum", + "input": { + "nodeId": "r1Mpb7NOQ", + "pinKey": "HJqG-m4dQ" + }, + "output": { + "nodeId": "HJHYZXVdX", + "pinKey": "BJ25Rf4u7" + } } }, "nodes": { - "BJ-XrVXEd7": { - "id": "BJ-XrVXEd7", - "label": "ERR", + "BJP0sIH_m": { + "id": "BJP0sIH_m", "position": { - "x": 272, - "y": 510 - }, - "type": "xod/patch-nodes/from-bus" - }, - "BJXvmmNOX": { - "id": "BJXvmmNOX", - "label": "DEV", - "position": { - "x": 204, - "y": 306 + "x": 34, + "y": 102 }, - "type": "xod/patch-nodes/from-bus" + "type": "xod/core/boot" }, "BkAD-Q4OQ": { "id": "BkAD-Q4OQ", "label": "TAG", "position": { - "x": 102, - "y": 714 + "x": 68, + "y": 612 }, "type": "xod/patch-nodes/output-boolean" }, @@ -1000,11 +980,20 @@ "id": "BkjdW7EuX", "label": "ERR", "position": { - "x": 272, - "y": 714 + "x": 204, + "y": 612 }, "type": "xod/patch-nodes/output-pulse" }, + "By0Hh8SOX": { + "id": "By0Hh8SOX", + "label": "INTD", + "position": { + "x": -34, + "y": 408 + }, + "type": "xod/patch-nodes/to-bus" + }, "HJHYZXVdX": { "id": "HJHYZXVdX", "position": { @@ -1013,95 +1002,78 @@ }, "type": "@/pn532-device" }, - "Hk-wmQV_m": { - "id": "Hk-wmQV_m", - "label": "DEV", - "position": { - "x": 0, - "y": 306 - }, - "type": "xod/patch-nodes/from-bus" - }, "HkQHEm4dQ": { "id": "HkQHEm4dQ", "label": "ERR", "position": { - "x": 34, - "y": 510 + "x": 68, + "y": 306 }, "type": "xod/patch-nodes/to-bus" }, + "HyGBn8Bum": { + "id": "HyGBn8Bum", + "position": { + "x": 170, + "y": 204 + }, + "type": "xod/core/gate" + }, "HysKZmV_7": { "id": "HysKZmV_7", "position": { "x": 0, - "y": 408 + "y": 204 }, "type": "@/init" }, - "S1VqW7Ed7": { - "id": "S1VqW7Ed7", + "S1i4nLHdm": { + "id": "S1i4nLHdm", "position": { - "x": 68, - "y": 102 + "x": -34, + "y": 306 }, "type": "xod/core/flip-flop" }, "Sk0gMX4dQ": { "id": "Sk0gMX4dQ", "position": { - "x": 272, - "y": 612 + "x": 204, + "y": 510 }, "type": "xod/core/any" }, - "r1Mpb7NOQ": { - "id": "r1Mpb7NOQ", + "SyZRSh8BOX": { + "id": "SyZRSh8BOX", + "label": "INTD", "position": { "x": 204, - "y": 408 + "y": 102 }, - "type": "@/pair-tag" + "type": "xod/patch-nodes/from-bus" }, - "r1Wdf74u7": { - "id": "r1Wdf74u7", + "r1Mpb7NOQ": { + "id": "r1Mpb7NOQ", "position": { - "x": 102, - "y": 204 + "x": 136, + "y": 306 }, - "type": "xod/core/gate" + "type": "@/pair-tag" }, "rJ4PZQ4OQ": { "id": "rJ4PZQ4OQ", "label": "UID", "position": { - "x": 0, - "y": 714 + "x": -34, + "y": 612 }, "type": "@/output-nfc-uid" }, - "rJDHX7Vu7": { - "id": "rJDHX7Vu7", - "position": { - "x": 102, - "y": 408 - }, - "type": "xod/core/any" - }, - "rJPRG74d7": { - "id": "rJPRG74d7", - "label": "DEV", - "position": { - "x": 0, - "y": 204 - }, - "type": "xod/patch-nodes/to-bus" - }, "rJgeG7Nd7": { "id": "rJgeG7Nd7", "position": { - "x": 102, - "y": 612 + "x": 68, + "y": 510 }, "type": "xod/core/flip-flop" }, @@ -1114,12 +1086,21 @@ }, "type": "xod/patch-nodes/input-port" }, + "rkJcjISOm": { + "id": "rkJcjISOm", + "label": "ERR", + "position": { + "x": 238, + "y": 408 + }, + "type": "xod/patch-nodes/from-bus" + }, "rkdd-QNdX": { "id": "rkdd-QNdX", "label": "OK", "position": { - "x": 204, - "y": 714 + "x": 170, + "y": 612 }, "type": "xod/patch-nodes/output-pulse" }, @@ -1130,7 +1111,7 @@ "id": "ryaU-XVd7", "label": "SCAN", "position": { - "x": 68, + "x": 170, "y": 0 }, "type": "xod/patch-nodes/input-pulse"