Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/hal/nfc #1606

Merged
merged 22 commits into from May 31, 2019

Conversation

@YutingYou
Copy link
Contributor

YutingYou commented Nov 26, 2018

Problem

Implement NFC Type 2 HAL driver

NOTE: This PR changed the timer used by USART, because NFC uses timer 4. Now we use timer 1 in USART driver.

Steps to Test

  1. Flash example application to Xenon
  2. Connect NFC antenna to Xenon
  3. Use mobile phone NFC app to scan NFC antenna
  4. When connected, D7 LED will turn on and you'll see the Particle website on your phone NFC app

Example App

#include "application.h"
#include "nfc_hal.h"
#include "nfc_ndef_msg.h"
#include "nfc_text_rec.h"
#include "nfc_uri_msg.h"
#include "nfc_t2t_lib.h"

SYSTEM_MODE(MANUAL);

static void nfc_event_callback(nfc_event_type_t type, nfc_event_t *event, void *ctx) {
    switch (type) {
        case NFC_EVENT_FIELD_ON: {
            digitalWrite(D7, 1);
            break;
        }
        case NFC_EVENT_FIELD_OFF: {
            digitalWrite(D7, 0);
            break;
        }
        case NFC_EVENT_READ: {
            break;
        }
        default:
            break;
    }
}

void setup(void) {
    static const uint8_t m_url[] = {'p', 'a', 'r', 't', 'i', 'c', 'l', 'e', '.', 'i', 'o'}; //URL "particle.com"
    static uint8_t m_ndef_msg_buf[256];

    // Just for NFC HAL API test, encode work will be done in wiring API
    uint32_t len = sizeof(m_ndef_msg_buf);
    uint32_t err_code = nfc_uri_msg_encode( NFC_URI_HTTP_WWW, m_url, sizeof(m_url), m_ndef_msg_buf, &len);
    APP_ERROR_CHECK(err_code);

    pinMode(D7, OUTPUT);
    digitalWrite(D7, 0);
    hal_nfc_type2_init();
    hal_nfc_type2_set_callback(nfc_event_callback);
    hal_nfc_type2_set_payload(m_ndef_msg_buf, len);
    hal_nfc_type2_start_emulation();
}

void loop() {

}

Update

NFC Wiring API Test

  1. Flash Example App
  2. Use NFC Reader application on iOS to scan NFC Tag, you'll see three record
  3. Click mode button, NFC records are updated

Example App

void nfc_event_handler(nfc_event_type_t type, nfc_event_t *event, void* ctx) {
    switch (type) {
        case NFC_EVENT_FIELD_ON:  digitalWrite(D7, 1); break;
        case NFC_EVENT_FIELD_OFF: digitalWrite(D7, 0); break;
        case NFC_EVENT_READ:      digitalWrite(D7, 0); break;
        default: break;
    }
}

void setup() {
    pinMode(D7, OUTPUT);
    digitalWrite(D7, 0);

    System.on(button_click, [](system_event_t ev, int clicks)->void {
        NFC.getNdefMessage()[0] = std::make_shared<TextRecord>("Update record - 1!", "en");
        NFC.getNdefMessage()[1] = std::make_shared<TextRecord>("Update record - 2!", "en");
        NFC.getNdefMessage()[2] = std::make_shared<TextRecord>("Update record - 3!", "en");
        NFC.getNdefMessage().addTextRecord("New record!", "en");

        NFC.stop();
        NFC.start(nfc_event_handler);
    });

    NFC.getNdefMessage().addTextRecord("Hello Particle!", "en");
    NFC.getNdefMessage().addUriRecord("particle.io", UriRecord::NFC_URI_HTTPS_WWW);
    NFC.getNdefMessage().addLauchAppRecord("io.particle.android.app");

    NFC.start(nfc_event_handler);
}

void loop() {

}

Note

  1. UID setting is not supported by Nordic Library, will be supported in the future
  2. Lauch app only supports Android platform
  3. TODO: Only support one message on NFC tag for now

References


Completeness

  • User is totes amazing for contributing!
  • Contributor has signed CLA (Info here)
  • Problem and Solution clearly stated
  • Run unit/integration/application tests on device
  • Added documentation
  • Added to CHANGELOG.md after merging (add links to docs and issues)

  • [gen 3] NFC support #1606
@@ -618,7 +618,7 @@ const auto UARTE1_INTERRUPT_PRIORITY = APP_IRQ_PRIORITY_HIGHEST;
Usart* getInstance(HAL_USART_Serial serial) {
static Usart usartMap[] = {
{NRF_UARTE0, uarte0InterruptHandler, UARTE0_INTERRUPT_PRIORITY, NRF_TIMER3, NRF_PPI_CHANNEL4, TX, RX, CTS, RTS},
{NRF_UARTE1, uarte1InterruptHandler, UARTE1_INTERRUPT_PRIORITY, NRF_TIMER4, NRF_PPI_CHANNEL5, TX1, RX1, CTS1, RTS1}
{NRF_UARTE1, uarte1InterruptHandler, UARTE1_INTERRUPT_PRIORITY, NRF_TIMER1, NRF_PPI_CHANNEL5, TX1, RX1, CTS1, RTS1}

This comment has been minimized.

Copy link
@avtolstoy

This comment has been minimized.

Copy link
@YutingYou

YutingYou Nov 27, 2018

Author Contributor

We've run out of timer resource, I'd like to release the timer in button hal, we have below choice for button debounce timer, or you can add other suggestion:

  • Use FreeRTOS timer in Device OS and use Timer 2 in bootloader
  • Use a high-precision timer to make a general software timer just like app timer, then we can use it in Bootloader and Device OS
  • Add a software timer handler in HAL_SysTick_Handler(), if we start the button timer, we set a timer flag, then we check the flag in HAL_SysTick_Handler()

I'd prefer the third one, since the handler won't take a long time.

Timer resource:

RTC0: Softdevice
RTC1: FreeRTOS
RTC2: OpenThread

Timer0: Softdevice
Timer1: Radio
Timer2: Button_hal
Timer3: Usart
Timer4: Usart

This comment has been minimized.

Copy link
@avtolstoy

avtolstoy Nov 27, 2018

Member

Agreed, I don't think we have any other choice at the moment. Moreover on Gen 3 devices this shouldn't cause any issues for FreeRTOS, since FreeRTOS is run off of RTC timer instead of SysTick.


typedef void (*NfcEventCallback)(NfcEventType type, NfcEvent *event);

int HAL_NFC_Type2_Init(void);

This comment has been minimized.

Copy link
@avtolstoy

avtolstoy Nov 26, 2018

Member

While we do not have a formal style guide at present, I think lowercase snake_case should be preferred for new HALs. This should apply both to function names and type names.

This comment has been minimized.

Copy link
@YutingYou

YutingYou Nov 28, 2018

Author Contributor

Changed

typedef void (*NfcEventCallback)(NfcEventType type, NfcEvent *event);

int HAL_NFC_Type2_Init(void);
int HAL_NFC_Type2_Set_Payload(const uint8_t *msg_buf, uint16_t msg_len);

This comment has been minimized.

Copy link
@avtolstoy

avtolstoy Nov 26, 2018

Member

Can the payload in theory be more than 2^16 bytes (not taking into account our specific microcontroller)? If yes, I suggest we change this to size_t. A reserved void* argument here also sounds like a good idea.

This comment has been minimized.

Copy link
@YutingYou

YutingYou Nov 28, 2018

Author Contributor

Changed

int HAL_NFC_Type2_Set_Payload(const uint8_t *msg_buf, uint16_t msg_len);
int HAL_NFC_Type2_Start_Emulation(void);
int HAL_NFC_Type2_Stop_Emulation(void);
int HAL_NFC_Type2_Set_Callback(NfcEventCallback callback);

This comment has been minimized.

Copy link
@avtolstoy

avtolstoy Nov 26, 2018

Member

An additional void* ctx argument and a change in NfcEventCallback signature ((NfcEventType type, NfcEvent *event, void* ctx)) sounds like a good idea.

This comment has been minimized.

Copy link
@YutingYou

YutingYou Nov 28, 2018

Author Contributor

Added it

@YutingYou YutingYou force-pushed the feature/hal/nfc branch 2 times, most recently from d62d399 to 02cd1fe Nov 28, 2018
@avtolstoy

This comment has been minimized.

Copy link
Member

avtolstoy commented Nov 28, 2018

@YutingYou Will the wiring API be a separate PR?

Please also add a new dynalib exporting these new NFC functions, otherwise they will not be accessible in modular firmware from the user part.

@YutingYou YutingYou force-pushed the feature/hal/nfc branch from 02cd1fe to e3bbafa Nov 29, 2018
@YutingYou

This comment has been minimized.

Copy link
Contributor Author

YutingYou commented Nov 29, 2018

@avtolstoy wiring API will be a separate PR. Added dynalib support.

@llacom

This comment has been minimized.

Copy link

llacom commented Jan 24, 2019

I'm trying to build the sample application. I copied the code in user/applications/nfc/application.cpp and build it using make all PLATFORM=argon APP=nfc from the firmware/modules folder.

The error I get:

../../../build/target/user/platform-12-m/applications/nfc//libuser.a(application.o): In function `setup':
/home/dromar/projects/particle-firmware/firmware/user/applications/nfc/application.cpp:35: undefined reference to `app_error_handler'
/home/dromar/projects/particle-firmware/firmware/user/applications/nfc/application.cpp:39: undefined reference to `hal_nfc_type2_init()'
/home/dromar/projects/particle-firmware/firmware/user/applications/nfc/application.cpp:40: undefined reference to `hal_nfc_type2_set_callback(void (*)(nfc_event_type_t, nfc_event_t*, void*))'
/home/dromar/projects/particle-firmware/firmware/user/applications/nfc/application.cpp:41: undefined reference to `hal_nfc_type2_set_payload(void const*, unsigned int)'
/home/dromar/projects/particle-firmware/firmware/user/applications/nfc/application.cpp:42: undefined reference to `hal_nfc_type2_start_emulation()'
collect2: error: ld returned 1 exit status

Those symbols were defined on libhal.a but not in libhal-dynalib.a. Trying to solve it, I added a file hal-dynalib/src/hal_nfc.c with the following:

#include "hal_dynalib_nfc.h"

Now the symbols are in libhal-dynalib.a but the same error persist. I'm probably misunderstanding how dynalib works or the corrent build process.

@avtolstoy avtolstoy force-pushed the feature/hal/nfc branch 2 times, most recently from 930fdb0 to 56fba06 Jan 29, 2019
@YutingYou YutingYou force-pushed the feature/hal/nfc branch 2 times, most recently from 0a15c7f to 8dfffdf Feb 21, 2019

typedef void (*nfc_event_callback_t)(nfc_event_type_t type, nfc_event_t *event, void* ctx);

int hal_nfc_type2_init(void);

This comment has been minimized.

Copy link
@avtolstoy

avtolstoy Mar 4, 2019

Member

void* reserved


int hal_nfc_type2_init(void);
int hal_nfc_type2_set_payload(const void *msg_buf, size_t msg_len);
int hal_nfc_type2_start_emulation(void);

This comment has been minimized.

Copy link
@avtolstoy

avtolstoy Mar 4, 2019

Member

void* reserved

int hal_nfc_type2_init(void);
int hal_nfc_type2_set_payload(const void *msg_buf, size_t msg_len);
int hal_nfc_type2_start_emulation(void);
int hal_nfc_type2_stop_emulation(void);

This comment has been minimized.

Copy link
@avtolstoy

avtolstoy Mar 4, 2019

Member

void* reserved

int hal_nfc_type2_set_payload(const void *msg_buf, size_t msg_len);
int hal_nfc_type2_start_emulation(void);
int hal_nfc_type2_stop_emulation(void);
int hal_nfc_type2_set_callback(nfc_event_callback_t callback);

This comment has been minimized.

Copy link
@avtolstoy

avtolstoy Mar 4, 2019

Member

Any functions taking a callback should have a void* context argument which should be stored along with the callback itself. The stored context should be passed as an argument to the callback function.


static nfc_event_callback_t g_nfc_event_user_callback = NULL;

static void nfc_type_2_callback(void * p_context, nfc_t2t_event_t event, const uint8_t * p_data, size_t data_length) {

This comment has been minimized.

Copy link
@avtolstoy

avtolstoy Mar 4, 2019

Member

Nitpicking: prefer type* to type *

return records_.size() - 1;
}

int NdefMessage::addUriRecord(const char *uri, UriRecord::NfcUriType type) {

This comment has been minimized.

Copy link
@avtolstoy

avtolstoy Mar 4, 2019

Member

Nitpicking: prefer const char* to const char *.

return records_.size() - 1;
}

int NdefMessage::addLauchAppRecord(const char *androidPackageName) {

This comment has been minimized.

Copy link
@avtolstoy

avtolstoy Mar 4, 2019

Member

Nitpicking: prefer const char* to const char *

wiring/inc/spark_wiring_nfc.h Show resolved Hide resolved
return 0;
}

NfcTagType2 NFC;

This comment has been minimized.

Copy link
@avtolstoy

avtolstoy Mar 4, 2019

Member

Consider using:

class NfcTagType2 {
public:
    NfcTagType2& instance() {
        static NfcTagType2 inst;
        return inst;
    }
protected:
    NfcTagType2() {
        ...
    }
}

#define NFC NfcTagType2::instance()

to save on flash space/RAM when the application is not using NFC.

@aroller

This comment has been minimized.

Copy link
Contributor

aroller commented Mar 5, 2019

I posted on the community forum the attempt to build this branch on a Xenon before @avtolstoy requested the latest changes. @YutingYou I'm not much help at coding the device-os, but I'm ready to help with building, testing and documenting when changes are applied. Let me know if I can be of assistance. Thanks for your efforts with the NFC API.

@YutingYou

This comment has been minimized.

Copy link
Contributor Author

YutingYou commented Mar 6, 2019

@llacom Sorry for the late reply, the HAL layer example is only for monolithic firmware, your issue is caused by I didn't export NFC functions as C function. It was fixed in the latest commit. The HAL example also uses some unexported function, so I'd suggest using wiring API to continue your test.

@aroller You should meet the same issue as @llacom met, please try again, if you got any issue or suggestions, feel free to let me know.

@YutingYou YutingYou force-pushed the feature/hal/nfc branch 3 times, most recently from c12c0ed to 0eea298 Mar 26, 2019
@YutingYou YutingYou force-pushed the feature/hal/nfc branch from 0eea298 to 71a61d9 Apr 3, 2019
@avtolstoy avtolstoy changed the base branch from mesh-develop to develop Apr 3, 2019
@YutingYou YutingYou force-pushed the feature/hal/nfc branch from a3d0d99 to 3be1c6d Apr 25, 2019
Copy link
Member

avtolstoy left a comment

🎉

@YutingYou

This comment has been minimized.

Copy link
Contributor Author

YutingYou commented May 27, 2019

Sure thing, it seems there is no example for the new API, I'll look into it.

@technobly technobly force-pushed the feature/hal/nfc branch from 5e14bf5 to 6fc8256 May 31, 2019
@technobly technobly merged commit d2da75e into develop May 31, 2019
2 checks passed
2 checks passed
continuous-integration/travis-ci/pr The Travis CI build passed
Details
continuous-integration/travis-ci/push The Travis CI build passed
Details
@technobly technobly deleted the feature/hal/nfc branch May 31, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants
You can’t perform that action at this time.