Nordicのsdkではapp_を使用scheduler Bluetoothコールバックの非同期タスクの実行
接触したばかりの頃、Bluetoothインタフェースでユーザーが構成を書き込むことができ、flashに書き込んで保存するという問題がありました.簡単な操作結果が間違っています.fds操作にはコールバックがありません.問題はどこですか.
fdsの操作に問題があると思って、テストコードを書いて、結果テストコードはよく走って、コールバックがあります!問題は明らかで、実行するコンテキスト環境に問題があるに違いない.
fdsのソースコードについて前述したように、fdsを使用して初期化操作を行う場合は、コールバックを登録する:(void)fds_register(fds_evt_handler);この登録コールバックの関数(fds_init)は、main関数において実行され、main関数と同じスレッドに走っている.つまり、fdsの任意の操作は、その操作結果が最終的にmain関数が存在するスレッドに送信される.詳細は、mainスレッド登録のコールバック、mainスレッドが開始したfds操作、fdsが非同期スレッドを開始して実際のflash操作を実行し、操作結果がmainに送信されるスレッド.
fdsの操作がbleイベントのコールバックに置かれると,状況が異なる.詳細なドキュメントではnordicがble割り込みイベントに言及していることは見つかりません.そのコールバックは非同期スレッドで実行されますが、確かにそうです.Bluetooth profileの書き込みコールバックでfds操作を実行すると、mainスレッドに登録されたコールバック、非同期スレッドA(Bluetooth profile書き込み操作コールバック)はfds操作を開始し、fdsは非同期スレッドBを開始して実際の操作を実行します.では、B操作が完了したら、結果は誰に送るべきですか.この具体的な詳細は、fdsのソースコードで後で解読します.ここでは、結果はmainスレッドに送られず、登録されたコールバックはこのメッセージを受信できません.
この問題を解決するためにAPPを導入すべきだ.SCHEDULERモジュール.これは、現在の環境(割り込みなど)に適さないいくつかの操作をプライマリスレッドに送信して実行するスケジューリングモジュールです.
使用方法、通常の初期化操作を見てみましょう.
ここでは、最大のイベント長を提供し、スペースの割り当てを容易にする必要があります.注意が必要なのはapp_timerもapp_を参照scheduler、ここで最大のイベント長を計算するには、含める必要があります.我々のアプリケーションでは、BluetoothホストモードとBluetoothスレーブモードの両方を使用しているので、ここでは両方を見てみましょう.
次にmain loopで、スケジューリングタスクがあるかどうかを確認する必要があります.
やはり簡単ですが、ここまで来ればapp_を使うことができますschedulerです.温度単位の変更を例にとると、app端子から設定する温度単位、摂氏度または華氏度、app_schedulerは単位と実際の処理関数(単位をflashに書いて保存した関数)を保存し、mainスレッドに送信し、main loopで実行します.
アプリを見てみましょうschedulerがイベントをキューに入れる関数はどのように定義されますか?
ここでevent dataはイベントのインタフェースであり,実際に実行されるイベントは何であるかである.では、まずイベントインタフェースを定義します.ここでは、fdsがflashを書く関数ポインタと対応するパラメータです.
ここで、fdsが単位を更新するための関数は、bool update_unit(TEMP_UNITS unit).evt_update_unit_handler_tは、関数を指すポインタであり、パラメータはtemp_である.unit.
そして3番目のパラメータapp_sched_event_handler_t,前に定義したイベントをどのように実行するかを理解し,通常はtemp_で直接実行する.unitパラメータ実行m_handler.
ここでは、タイプ変換にエラーが発生しないようにチェックしました.
スケジューリングを開始できます.
Bluetooth読み書き割り込みで直接関数evt_を実行schedule_update_unitでいいです.
APP_SCHED_INITの場合、最大のイベント長を入力する必要があります.ここでは、このようなevtを何個定義し、何個計算する必要がありますか.私はこのように定義しています.新しいイベントを追加するたびに、計算する必要があります.
fdsの操作に問題があると思って、テストコードを書いて、結果テストコードはよく走って、コールバックがあります!問題は明らかで、実行するコンテキスト環境に問題があるに違いない.
fdsのソースコードについて前述したように、fdsを使用して初期化操作を行う場合は、コールバックを登録する:(void)fds_register(fds_evt_handler);この登録コールバックの関数(fds_init)は、main関数において実行され、main関数と同じスレッドに走っている.つまり、fdsの任意の操作は、その操作結果が最終的にmain関数が存在するスレッドに送信される.詳細は、mainスレッド登録のコールバック、mainスレッドが開始したfds操作、fdsが非同期スレッドを開始して実際のflash操作を実行し、操作結果がmainに送信されるスレッド.
fdsの操作がbleイベントのコールバックに置かれると,状況が異なる.詳細なドキュメントではnordicがble割り込みイベントに言及していることは見つかりません.そのコールバックは非同期スレッドで実行されますが、確かにそうです.Bluetooth profileの書き込みコールバックでfds操作を実行すると、mainスレッドに登録されたコールバック、非同期スレッドA(Bluetooth profile書き込み操作コールバック)はfds操作を開始し、fdsは非同期スレッドBを開始して実際の操作を実行します.では、B操作が完了したら、結果は誰に送るべきですか.この具体的な詳細は、fdsのソースコードで後で解読します.ここでは、結果はmainスレッドに送られず、登録されたコールバックはこのメッセージを受信できません.
この問題を解決するためにAPPを導入すべきだ.SCHEDULERモジュール.これは、現在の環境(割り込みなど)に適さないいくつかの操作をプライマリスレッドに送信して実行するスケジューリングモジュールです.
使用方法、通常の初期化操作を見てみましょう.
/**@brief Function for the Event Scheduler initialization.
*/
static void scheduler_init(void)
{
APP_SCHED_INIT(MAX_EVT_SIZE(APP_TIMER_SCHED_EVENT_DATA_SIZE,MAX_EVT_SIZE(PERIPHERAL_MAX_EVT_SIZE,CENTRAL_MAX_EVT_SIZE)), SCHED_QUEUE_SIZE);
}
ここでは、最大のイベント長を提供し、スペースの割り当てを容易にする必要があります.注意が必要なのはapp_timerもapp_を参照scheduler、ここで最大のイベント長を計算するには、含める必要があります.我々のアプリケーションでは、BluetoothホストモードとBluetoothスレーブモードの両方を使用しているので、ここでは両方を見てみましょう.
次にmain loopで、スケジューリングタスクがあるかどうかを確認する必要があります.
// Enter main loop.
for (;;)
{
#if (MI_BLE_ENABLE)
mible_tasks_exec();
#endif
app_sched_execute();
idle_state_handle();
}
やはり簡単ですが、ここまで来ればapp_を使うことができますschedulerです.温度単位の変更を例にとると、app端子から設定する温度単位、摂氏度または華氏度、app_schedulerは単位と実際の処理関数(単位をflashに書いて保存した関数)を保存し、mainスレッドに送信し、main loopで実行します.
アプリを見てみましょうschedulerがイベントをキューに入れる関数はどのように定義されますか?
/**@brief Function for scheduling an event.
*
* @details Puts an event into the event queue.
*
* @param[in] p_event_data Pointer to event data to be scheduled.
* @param[in] event_size Size of event data to be scheduled.
* @param[in] handler Event handler to receive the event.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
uint32_t app_sched_event_put(void const * p_event_data,
uint16_t event_size,
app_sched_event_handler_t handler);
ここでevent dataはイベントのインタフェースであり,実際に実行されるイベントは何であるかである.では、まずイベントインタフェースを定義します.ここでは、fdsがflashを書く関数ポインタと対応するパラメータです.
typedef bool(*evt_update_unit_handler_t)(TEMP_UNITS unit);
typedef struct{
evt_update_unit_handler_t m_handler;
TEMP_UNITS temp_unit;
}update_unit_evt_data;
ここで、fdsが単位を更新するための関数は、bool update_unit(TEMP_UNITS unit).evt_update_unit_handler_tは、関数を指すポインタであり、パラメータはtemp_である.unit.
そして3番目のパラメータapp_sched_event_handler_t,前に定義したイベントをどのように実行するかを理解し,通常はtemp_で直接実行する.unitパラメータ実行m_handler.
static void update_unit_evt_get(void * p_event_data, uint16_t event_size)
{
update_unit_evt_data * p_update_unit_event = (update_unit_evt_data *)p_event_data;
APP_ERROR_CHECK_BOOL(event_size == sizeof(update_unit_evt_data));
p_update_unit_event->m_handler(p_update_unit_event->temp_unit);
}
ここでは、タイプ変換にエラーが発生しないようにチェックしました.
スケジューリングを開始できます.
uint32_t evt_schedule_update_unit(evt_update_unit_handler_t update_handler,TEMP_UNITS unit){
update_unit_evt_data evt_handler;
evt_handler.m_handler=update_handler;
evt_handler.temp_unit=unit;
return app_sched_event_put(&evt_handler, sizeof(evt_handler), update_unit_evt_get);
}
Bluetooth読み書き割り込みで直接関数evt_を実行schedule_update_unitでいいです.
APP_SCHED_INITの場合、最大のイベント長を入力する必要があります.ここでは、このようなevtを何個定義し、何個計算する必要がありますか.私はこのように定義しています.新しいイベントを追加するたびに、計算する必要があります.
#define MAX_EVT_SIZE(a,b) (a>b?a:b)
#define PERIPHERAL_MAX_EVT_SIZE MAX_EVT_SIZE(sizeof(update_unit_evt_data),\
MAX_EVT_SIZE(sizeof(update_profile_series_data),\
MAX_EVT_SIZE(sizeof(update_profile_series_by_leftcnt_data),\
MAX_EVT_SIZE(sizeof(update_algorithm_flag_data),\
MAX_EVT_SIZE(sizeof(update_account_data),\
MAX_EVT_SIZE(sizeof(update_profile_id_data),\
sizeof(remove_detail_items_data)\
))))))